├── .discourse-compatibility
├── .github
└── workflows
│ └── discourse-plugin.yml
├── .gitignore
├── .npmrc
├── .prettierrc.cjs
├── .rubocop.yml
├── .streerc
├── .template-lintrc.cjs
├── Gemfile
├── Gemfile.lock
├── LICENSE
├── README.md
├── app
├── jobs
│ ├── regular
│ │ ├── create_github_linkback.rb
│ │ └── replace_github_non_permalinks.rb
│ └── scheduled
│ │ └── grant_github_badges.rb
├── lib
│ ├── commits_populator.rb
│ ├── github_badges.rb
│ ├── github_badges_repo_setting_validator.rb
│ ├── github_linkback.rb
│ ├── github_linkback_access_token_setting_validator.rb
│ └── github_permalinks.rb
└── models
│ ├── github_commit.rb
│ └── github_repo.rb
├── 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
│ ├── 20190617035051_rename_site_setting_github_badges_repo.rb
│ ├── 20190618174229_create_github_repos.rb
│ ├── 20190618183340_create_github_commits.rb
│ ├── 20201210032852_discourse_github_rebuild_git_history.rb
│ └── 20230227050148_update_github_badge_icons.rb
├── eslint.config.mjs
├── package.json
├── plugin.rb
├── pnpm-lock.yaml
├── spec
├── jobs
│ ├── create_github_linkback_spec.rb
│ └── replace_github_non_permalinks_spec.rb
├── lib
│ ├── commits_populator_spec.rb
│ ├── github_badges_repo_setting_validator_spec.rb
│ ├── github_badges_spec.rb
│ ├── github_linkback_access_token_setting_validator_spec.rb
│ ├── github_linkback_spec.rb
│ └── github_permalinks_spec.rb
├── models
│ └── github_repo_spec.rb
└── system
│ └── core_features_spec.rb
├── stylelint.config.mjs
└── translator.yml
/.discourse-compatibility:
--------------------------------------------------------------------------------
1 | < 3.5.0.beta1-dev: 59e5fc5692959c6c564ab0e09de364ccfedd6702
2 | < 3.4.0.beta1-dev: e24de3f5cd6ec5cef17dc3e07dfb3bfac8867e08
3 | < 3.3.0.beta1-dev: 53e22ccbd32dd868435f66efa2d48e0389673dea
4 | 3.1.999: 8aa068d56ef010cecaabd50657e7753f4bbecc1f
5 |
--------------------------------------------------------------------------------
/.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 | /gems
2 | node_modules
3 |
--------------------------------------------------------------------------------
/.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 | AllCops:
4 | Exclude:
5 | - "gems/**/*"
6 | - "vendor/bundle/**/*"
7 |
--------------------------------------------------------------------------------
/.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.2.0)
19 | benchmark (0.4.0)
20 | bigdecimal (3.1.9)
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 Github
2 |
3 | https://meta.discourse.org/t/discourse-github/99895/
4 |
5 | This plugin combines functionality of deprecated github_badges and discourse-github-linkback plugins.
6 |
7 | ### Installation
8 |
9 | Follow the [plugin installation guide](https://meta.discourse.org/t/install-a-plugin/19157).
10 |
11 | ### Github Badges
12 |
13 | Assign badges to your users based on GitHub contributions.
14 |
15 | #### How to use:
16 |
17 | 1. Enable `github badges enabled` in Settings -> Plugins.
18 |
19 | 2. Generate an access token on Github. Be sure to give it only the `public_repo` scope. Paste that token into the `github linkback access token` setting.
20 |
21 | 3. Add URL of the GitHub repo to scan for contributions to the `github badges repo` site setting.
22 |
23 | ### Github Linkback
24 |
25 | Create a link from a Github pull request or commit back to a Discourse post where it is mentioned.
26 |
27 | #### How to use:
28 |
29 | 1. Enable `github linkback enabled` in Settings -> Plugins.
30 |
31 | 2. Generate an [access token](https://github.com/settings/tokens) on Github.
32 | Be sure to give it only the `public_repo` scope. Paste that token into the
33 | `github linkback access token` setting.
34 |
35 | 3. Finally, add the projects you wish to post to in the `github linkback projects` site setting in the formats:
36 | - `username/repository` for specific repositories
37 | - `username/*` for all repositories of a certain user
38 |
39 | ### Github Permalink
40 |
41 | Replace Github non-permalinks with [permalinks](https://help.github.com/articles/getting-permanent-links-to-files/).
42 |
43 | #### How to use:
44 |
45 | 1. Enable `github permalinks enabled` in Settings -> Plugins.
46 | 2. If you want to exclude certain files or directories from permalink overwrites, you can modify that in the `github permalinks exclude` site setting in the following formats:
47 | - `filename` links to all files with matching filename
48 | - `username/*` links to all repositories belonging to the user/organization
49 | - `username/repository/*` links to any file in the repository
50 | - `username/repository/directory/*` links to any file in the directory within repository
51 | - `username/repository/file.rb` a specific file
52 |
--------------------------------------------------------------------------------
/app/jobs/regular/create_github_linkback.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Jobs
4 | class CreateGithubLinkback < ::Jobs::Base
5 | def execute(args)
6 | return unless SiteSetting.enable_discourse_github_plugin?
7 | return unless SiteSetting.github_linkback_enabled?
8 | return if (post = Post.find_by_id(args[:post_id])).blank?
9 | GithubLinkback.new(post).create
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/app/jobs/regular/replace_github_non_permalinks.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "net/http"
4 | require "json"
5 | require "uri"
6 |
7 | module Jobs
8 | class ReplaceGithubNonPermalinks < ::Jobs::Base
9 | sidekiq_options queue: "low"
10 |
11 | def execute(args)
12 | return unless SiteSetting.enable_discourse_github_plugin?
13 | return unless SiteSetting.github_permalinks_enabled?
14 |
15 | post_id = args[:post_id]
16 | raise Discourse::InvalidParameters.new(:post_id) if post_id.blank?
17 |
18 | post = Post.find_by(id: post_id)
19 | return if post.blank?
20 |
21 | raw = post.raw.dup
22 | start_raw = raw.dup
23 |
24 | regex =
25 | %r{github\.com/(?[^/]+)/(?[^/\s]+)/blob/(?[^/\s]+)/(?[^#\s]+)(?#(L([^-\s]*)(-L(\d*))?))?}i
26 |
27 | matches = post.raw.scan(regex)
28 | matches.each do |user, repo, sha1, file, from_to|
29 | next if excluded?(user, repo, file)
30 |
31 | begin
32 | api_url = "https://api.github.com/repos/#{user}/#{repo}/commits/#{sha1}"
33 | json = api_request(api_url)
34 | if json && (json["sha"] != sha1)
35 | new_sha = json["sha"]
36 | old_url = "github.com/#{user}/#{repo}/blob/#{sha1}/#{file}#{from_to}"
37 | new_url = "github.com/#{user}/#{repo}/blob/#{new_sha}/#{file}#{from_to}"
38 | raw.sub!(old_url, new_url)
39 | end
40 | rescue => e
41 | log(
42 | :error,
43 | "Failed to replace Github link with permalink in post #{post_id}\n" + e.message + "\n" +
44 | e.backtrace.join("\n"),
45 | )
46 | end
47 | end
48 |
49 | post.reload
50 |
51 | if start_raw == post.raw && raw != post.raw
52 | changes = { raw: raw, edit_reason: I18n.t("replace_github_link.edit_reason") }
53 | post.revise(Discourse.system_user, changes, bypass_bump: true)
54 | end
55 | end
56 |
57 | def excluded?(user, repo, file)
58 | excluded = SiteSetting.github_permalinks_exclude.split("|")
59 |
60 | excluded.each do |e|
61 | path_parts = e.split("/")
62 | # when only filename is provided
63 | if path_parts.length == 1
64 | return true if file == e
65 | next
66 | end
67 |
68 | path_parts.each { |p| p.sub!("*", "\\S+") }
69 |
70 | regex = Regexp.new(path_parts.join("\/"))
71 | return true if "#{user}/#{repo}/#{file}".match(regex)
72 | end
73 |
74 | false
75 | end
76 |
77 | private
78 |
79 | def api_request(url)
80 | uri = URI(url)
81 | response = Net::HTTP.get_response(uri)
82 |
83 | JSON.parse(response.body) if response.kind_of? Net::HTTPSuccess
84 | end
85 |
86 | def log(log_level, message)
87 | Rails.logger.public_send(
88 | log_level,
89 | "#{RailsMultisite::ConnectionManagement.current_db}: #{message}",
90 | )
91 | end
92 | end
93 | end
94 |
--------------------------------------------------------------------------------
/app/jobs/scheduled/grant_github_badges.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscourseGithubPlugin
4 | class UpdateJob < ::Jobs::Scheduled
5 | every 4.hours
6 |
7 | def execute(args)
8 | return unless SiteSetting.enable_discourse_github_plugin?
9 | return unless SiteSetting.github_badges_enabled?
10 | return if SiteSetting.github_linkback_access_token.blank?
11 |
12 | GithubRepo.repos.each { |repo| CommitsPopulator.new(repo).populate! }
13 | GithubBadges.grant!
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/app/lib/commits_populator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscourseGithubPlugin
4 | class CommitsPopulator
5 | MERGE_COMMIT_REGEX = /^Merge pull request/
6 | HISTORY_COMPLETE = "history-complete"
7 | class GraphQLError < StandardError
8 | end
9 |
10 | ROLES = { committer: 0, contributor: 1 }
11 |
12 | class PaginatedCommits
13 | def initialize(octokit, repo, cursor: nil, page_size: 100)
14 | @client = octokit
15 | @repo = repo
16 | @cursor = cursor
17 | @page_size = page_size
18 | raise ArgumentError, "page_size arg must be <= 100" if page_size > 100
19 | if cursor && !cursor.match?(/^\h{40}\s(\d+)$/)
20 | raise ArgumentError,
21 | "cursor must be a 40-characters hex string followed by a space and a number"
22 | end
23 | fetch_commits
24 | end
25 |
26 | def next
27 | cursor = next_cursor
28 | return unless cursor
29 | PaginatedCommits.new(@client, @repo, cursor: cursor, page_size: @page_size)
30 | end
31 |
32 | def commits
33 | @data.repository.defaultBranchRef.target.history.nodes
34 | end
35 |
36 | def next_cursor
37 | info = @data.repository.defaultBranchRef.target.history.pageInfo
38 | return unless info.hasNextPage
39 | info.endCursor
40 | end
41 |
42 | private
43 |
44 | def fetch_commits
45 | owner, name = @repo.name.split("/", 2)
46 | history_args = "first: #{@page_size}"
47 | history_args += ", after: #{@cursor.inspect}" if @cursor
48 |
49 | query = <<~QUERY
50 | query {
51 | repository(name: #{name.inspect}, owner: #{owner.inspect}) {
52 | defaultBranchRef {
53 | target {
54 | ... on Commit {
55 | history(#{history_args}) {
56 | pageInfo {
57 | endCursor
58 | hasNextPage
59 | }
60 | nodes {
61 | oid
62 | message
63 | committedDate
64 | associatedPullRequests(first: 1) {
65 | nodes {
66 | author {
67 | login
68 | }
69 | mergedBy {
70 | login
71 | }
72 | }
73 | }
74 | author {
75 | email
76 | }
77 | }
78 | }
79 | }
80 | }
81 | }
82 | }
83 | }
84 | QUERY
85 | response = @client.post("/graphql", { query: query }.to_json)
86 | raise GraphQLError, response.errors.inspect if response.errors
87 | raise GraphQLError, response.message if !response.data
88 | @data = response.data
89 | end
90 | end
91 |
92 | def initialize(repo)
93 | @repo = repo
94 | @client =
95 | Octokit::Client.new(access_token: SiteSetting.github_linkback_access_token, per_page: 100)
96 | end
97 |
98 | def populate!
99 | return unless SiteSetting.github_badges_enabled?
100 | return if @client.branches(@repo.name).empty?
101 |
102 | if @repo.commits.size == 0
103 | build_history!
104 | else
105 | front_sha = Discourse.redis.get(front_commit_redis_key)
106 | if front_sha.present? && removed?(front_sha)
107 | # there has been a force push, next run will rebuild history
108 | @repo.commits.delete_all
109 | Discourse.redis.del(back_cursor_redis_key)
110 | Discourse.redis.del(front_commit_redis_key)
111 | return
112 | end
113 | fetch_new_commits!(front_sha)
114 | front_sha = Discourse.redis.get(front_commit_redis_key)
115 | @repo.reload
116 |
117 | back_cursor = Discourse.redis.get(back_cursor_redis_key)
118 | return if back_cursor == HISTORY_COMPLETE
119 | if back_cursor.present?
120 | build_history!(cursor: back_cursor)
121 | elsif front_sha.present?
122 | count = @repo.commits.count
123 | build_history!(cursor: "#{front_sha} #{count - 1}")
124 | else
125 | # this is a bad state that we should never be in
126 | # But in case it happens, easiest way to recover
127 | # is to start from scratch.
128 | @repo.commits.delete_all
129 | Discourse.redis.del(back_cursor_redis_key)
130 | Discourse.redis.del(front_commit_redis_key)
131 | end
132 | end
133 | rescue Octokit::Error => err
134 | case err
135 | when Octokit::NotFound
136 | disable_github_badges_and_inform_admin(
137 | title: I18n.t("github_commits_populator.errors.repository_not_found_pm_title"),
138 | raw:
139 | I18n.t(
140 | "github_commits_populator.errors.repository_not_found_pm",
141 | repo_name: @repo.name,
142 | base_path: Discourse.base_path,
143 | ),
144 | )
145 | Rails.logger.warn(
146 | "Disabled github_badges_enabled site setting due to repository Not Found error ",
147 | )
148 | when Octokit::Unauthorized
149 | disable_github_badges_and_inform_admin(
150 | title: I18n.t("github_commits_populator.errors.invalid_octokit_credentials_pm_title"),
151 | raw:
152 | I18n.t(
153 | "github_commits_populator.errors.invalid_octokit_credentials_pm",
154 | base_path: Discourse.base_path,
155 | ),
156 | )
157 | Rails.logger.warn(
158 | "Disabled github_badges_enabled site setting due to invalid GitHub authentication credentials via github_linkback_access_token.",
159 | )
160 | else
161 | Rails.logger.warn("#{err.class}: #{err.message}")
162 | end
163 | rescue Octokit::InvalidRepository => err
164 | disable_github_badges_and_inform_admin(
165 | title: I18n.t("github_commits_populator.errors.repository_identifier_invalid_pm_title"),
166 | raw:
167 | I18n.t(
168 | "github_commits_populator.errors.repository_identifier_invalid_pm",
169 | repo_name: @repo.name,
170 | base_path: Discourse.base_path,
171 | ),
172 | )
173 | Rails.logger.warn(
174 | "Disabled github_badges_enabled site setting due to invalid repository identifier",
175 | )
176 | end
177 |
178 | private
179 |
180 | def is_contribution?(commit)
181 | pr = commit.associatedPullRequests.nodes.first
182 | pr && pr.author && pr.mergedBy && pr.author.login != pr.mergedBy.login
183 | end
184 |
185 | def fetch_new_commits!(stop_at)
186 | paginator = PaginatedCommits.new(@client, @repo, page_size: 10)
187 | batch = paginator.commits
188 | done = false
189 | commits = []
190 | recent_commits =
191 | stop_at.present? ? [] : @repo.commits.order("committed_at DESC").first(100).pluck(:sha)
192 | while !done
193 | batch.each do |c|
194 | if c.oid == stop_at || recent_commits.include?(c.oid)
195 | done = true
196 | break
197 | end
198 | commits << c
199 | end
200 | break if done
201 | paginator = paginator.next
202 | batch = paginator&.commits || []
203 | break if batch.empty?
204 | end
205 | return if commits.size == 0
206 | existing_shas = @repo.commits.pluck(:sha)
207 | commits.reject! { |c| existing_shas.include?(c.oid) }
208 | batch_to_db(commits)
209 | set_front_commit(commits.first.oid)
210 | end
211 |
212 | # detect if a force push happened and commit is lost
213 | def removed?(sha)
214 | commit = @client.commit(@repo.name, sha)
215 | return true if commit.commit.nil?
216 | found =
217 | @client.commits(@repo.name, until: commit.commit.committer.date, page: 1, per_page: 1).first
218 | commit.sha != found.sha
219 | end
220 |
221 | def build_history!(cursor: nil)
222 | paginator = PaginatedCommits.new(@client, @repo, cursor: cursor, page_size: 100)
223 | batch = paginator.commits
224 | return if batch.empty?
225 | set_front_commit(batch.first.oid) if cursor.blank?
226 |
227 | while batch.size > 0
228 | batch_to_db(batch)
229 | next_cursor = paginator.next_cursor
230 | set_back_cursor(next_cursor) if next_cursor
231 |
232 | paginator = paginator.next
233 | batch = paginator&.commits || []
234 | end
235 | set_back_cursor(HISTORY_COMPLETE)
236 | end
237 |
238 | def batch_to_db(batch)
239 | fragments = []
240 | batch.each do |c|
241 | hash = commit_to_hash(c)
242 | fragments << DB.sql_fragment(<<~SQL, hash)
243 | (:repo_id, :sha, :email, :committed_at, :role_id, :merge_commit, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
244 | SQL
245 | end
246 | DB.exec(<<~SQL)
247 | INSERT INTO github_commits
248 | (repo_id, sha, email, committed_at, role_id, merge_commit, created_at, updated_at) VALUES #{fragments.join(",")}
249 | SQL
250 | end
251 |
252 | def commit_to_hash(commit)
253 | {
254 | sha: commit.oid,
255 | email: commit.author.email,
256 | repo_id: @repo.id,
257 | committed_at: commit.committedDate,
258 | merge_commit: commit.message.match?(MERGE_COMMIT_REGEX),
259 | role_id: is_contribution?(commit) ? ROLES[:contributor] : ROLES[:committer],
260 | }
261 | end
262 |
263 | def set_front_commit(sha)
264 | Discourse.redis.set(front_commit_redis_key, sha)
265 | end
266 |
267 | def set_back_cursor(cursor)
268 | Discourse.redis.set(back_cursor_redis_key, cursor)
269 | end
270 |
271 | def front_commit_redis_key
272 | # this key should refer to the MOST RECENT commit we have in the db
273 | "discourse-github-front-commit-#{@repo.name}"
274 | end
275 |
276 | def back_cursor_redis_key
277 | # this key should refer to the cursor that lets us continue
278 | # building history from the point we reached in the previous run
279 | # that couldn't continue for whatever reasons
280 | # e.g., if we got rate-limited by github
281 | "discourse-github-back-cursor-#{@repo.name}"
282 | end
283 |
284 | def disable_github_badges_and_inform_admin(title:, raw:)
285 | SiteSetting.github_badges_enabled = false
286 | site_admin_usernames =
287 | User.where(admin: true).human_users.order("last_seen_at DESC").limit(10).pluck(:username)
288 | PostCreator.create!(
289 | Discourse.system_user,
290 | title: title,
291 | raw: raw,
292 | archetype: Archetype.private_message,
293 | target_usernames: site_admin_usernames,
294 | skip_validations: true,
295 | )
296 | end
297 | end
298 | end
299 |
--------------------------------------------------------------------------------
/app/lib/github_badges.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscourseGithubPlugin
4 | module GithubBadges
5 | BADGE_NAME_BRONZE = "Contributor"
6 | BADGE_NAME_SILVER = "Great Contributor"
7 | BADGE_NAME_GOLD = "Amazing Contributor"
8 |
9 | COMMITTER_BADGE_NAME_BRONZE = "Committer"
10 | COMMITTER_BADGE_NAME_SILVER = "Frequent Committer"
11 | COMMITTER_BADGE_NAME_GOLD = "Amazing Committer"
12 |
13 | class Granter
14 | def initialize(emails)
15 | @emails = emails
16 | @badges = []
17 | end
18 |
19 | def add_badge(badge, as_title:, threshold:)
20 | @badges << [badge, as_title, threshold]
21 | end
22 |
23 | def grant!
24 | email_commits = @emails.group_by { |e| e }.map { |k, l| [k, l.count] }.to_h
25 |
26 | regular_emails = []
27 | github_name_email = {}
28 | @emails.each do |email|
29 | match = email.match(/\A(\d+\+)?(?.+)@users.noreply.github.com\Z/)
30 |
31 | if match
32 | name = match[:name]
33 | github_name_email[name] = email
34 | else
35 | regular_emails << email
36 | end
37 | end
38 |
39 | user_emails = {}
40 | User
41 | .real
42 | .where(staged: false)
43 | .with_email(regular_emails)
44 | .each { |user| user_emails[user] = user.emails }
45 |
46 | if github_name_email.any?
47 | screen_names =
48 | UserAssociatedAccount
49 | .where(provider_name: "github")
50 | .where("info ->> 'nickname' IN (?)", github_name_email.keys)
51 | .includes(:user)
52 | .map { |row| [row.user, row.info["nickname"]] }
53 | .to_h
54 |
55 | screen_names.each do |user, screen_name|
56 | user_emails[user] ||= []
57 | user_emails[user] << github_name_email[screen_name]
58 | end
59 | end
60 |
61 | user_emails.each do |user, emails|
62 | commits_count = emails.sum { |email| email_commits[email] || 0 }
63 | @badges.each do |badge, as_title, threshold|
64 | if commits_count >= threshold && badge.enabled? && SiteSetting.enable_badges
65 | BadgeGranter.grant(badge, user)
66 | user.update!(title: badge.name) if badge.allow_title? && user.title.blank? && as_title
67 | end
68 | end
69 | end
70 | end
71 | end
72 |
73 | def self.grant!
74 | grant_committer_badges!
75 | grant_contributor_badges!
76 | end
77 |
78 | def self.grant_committer_badges!
79 | emails =
80 | GithubCommit.where(merge_commit: false, role_id: CommitsPopulator::ROLES[:committer]).pluck(
81 | :email,
82 | )
83 |
84 | bronze, silver, gold = committer_badges
85 |
86 | granter = GithubBadges::Granter.new(emails)
87 | granter.add_badge(bronze, as_title: false, threshold: 1)
88 | granter.add_badge(silver, as_title: true, threshold: 25)
89 | granter.add_badge(gold, as_title: true, threshold: 1000)
90 | granter.grant!
91 | end
92 |
93 | def self.grant_contributor_badges!
94 | emails =
95 | GithubCommit.where(
96 | merge_commit: false,
97 | role_id: CommitsPopulator::ROLES[:contributor],
98 | ).pluck(:email)
99 |
100 | bronze, silver, gold = contributor_badges
101 |
102 | granter = GithubBadges::Granter.new(emails)
103 | granter.add_badge(bronze, as_title: false, threshold: 1)
104 | granter.add_badge(
105 | silver,
106 | as_title: true,
107 | threshold: SiteSetting.github_silver_badge_min_commits,
108 | )
109 | granter.add_badge(gold, as_title: true, threshold: SiteSetting.github_gold_badge_min_commits)
110 | granter.grant!
111 | end
112 |
113 | def self.ensure_badge(name, attrs)
114 | badge = Badge.find_by("name ILIKE ?", name)
115 |
116 | # Check for letter-case differences
117 | badge.update!(name: name) if badge && badge.name != name
118 |
119 | badge || Badge.create!(name: name, **attrs)
120 | end
121 |
122 | def self.contributor_badges
123 | bronze =
124 | ensure_badge(
125 | BADGE_NAME_BRONZE,
126 | description: "Contributed an accepted pull request",
127 | badge_type_id: 3,
128 | default_icon: "fab-git-alt",
129 | )
130 |
131 | silver =
132 | ensure_badge(
133 | BADGE_NAME_SILVER,
134 | description: "Contributed 25 accepted pull requests",
135 | badge_type_id: 2,
136 | default_icon: "fab-git-alt",
137 | )
138 |
139 | gold =
140 | ensure_badge(
141 | BADGE_NAME_GOLD,
142 | description: "Contributed 250 accepted pull requests",
143 | badge_type_id: 1,
144 | default_icon: "fab-git-alt",
145 | )
146 |
147 | [bronze, silver, gold]
148 | end
149 |
150 | def self.committer_badges
151 | bronze =
152 | ensure_badge(
153 | COMMITTER_BADGE_NAME_BRONZE,
154 | description: "Created a commit",
155 | enabled: false,
156 | badge_type_id: 3,
157 | )
158 |
159 | silver =
160 | ensure_badge(
161 | COMMITTER_BADGE_NAME_SILVER,
162 | description: "Created 25 commits",
163 | enabled: false,
164 | badge_type_id: 2,
165 | )
166 |
167 | gold =
168 | ensure_badge(
169 | COMMITTER_BADGE_NAME_GOLD,
170 | description: "Created 1000 commits",
171 | enabled: false,
172 | badge_type_id: 1,
173 | )
174 |
175 | [bronze, silver, gold]
176 | end
177 | end
178 | end
179 |
--------------------------------------------------------------------------------
/app/lib/github_badges_repo_setting_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class GithubBadgesRepoSettingValidator
4 | def initialize(opts = {})
5 | @opts = opts
6 | end
7 |
8 | def valid_value?(val)
9 | return true if val.blank?
10 | val
11 | .split("|")
12 | .all? do |repo|
13 | repo.match?(DiscourseGithubPlugin::GithubRepo::VALID_URL_BASED_REPO_REGEX) ||
14 | repo.match?(DiscourseGithubPlugin::GithubRepo::VALID_USER_BASED_REPO_REGEX)
15 | end
16 | end
17 |
18 | def error_message
19 | I18n.t("site_settings.errors.invalid_badge_repo")
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/app/lib/github_linkback.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require_dependency "pretty_text"
4 | require "digest/sha1"
5 |
6 | class GithubLinkback
7 | class Link
8 | attr_reader :url, :project, :type
9 | attr_accessor :sha, :pr_number, :issue_number
10 |
11 | def initialize(url, project, type)
12 | @url = url
13 | @project = project
14 | @type = type
15 | end
16 | end
17 |
18 | def initialize(post)
19 | @post = post
20 | end
21 |
22 | def should_enqueue?
23 | !!(
24 | SiteSetting.github_linkback_enabled? && SiteSetting.enable_discourse_github_plugin? &&
25 | @post.present? && @post.post_type == Post.types[:regular] && @post.raw =~ /github\.com/ &&
26 | Guardian.new.can_see?(@post) && @post.topic.visible?
27 | )
28 | end
29 |
30 | def enqueue
31 | Jobs.enqueue(:create_github_linkback, post_id: @post.id) if should_enqueue?
32 | end
33 |
34 | def github_links
35 | projects = SiteSetting.github_linkback_projects.split("|")
36 |
37 | return [] if projects.blank?
38 |
39 | result = {}
40 | PrettyText
41 | .extract_links(@post.cooked)
42 | .map(&:url)
43 | .each do |l|
44 | if l =~ %r{https?://github\.com/([^/]+)/([^/]+)/commit/([0-9a-f]+)}
45 | url, org, repo, sha = Regexp.last_match.to_a
46 | project = "#{org}/#{repo}"
47 |
48 | next if result[url]
49 | next if @post.custom_fields[GithubLinkback.field_for(url)].present?
50 | next unless is_allowed_project_link?(projects, project)
51 |
52 | link = Link.new(url, project, :commit)
53 | link.sha = sha
54 | result[url] = link
55 | elsif l =~ %r{https?://github.com/([^/]+)/([^/]+)/pull/(\d+)}
56 | url, org, repo, pr_number = Regexp.last_match.to_a
57 | project = "#{org}/#{repo}"
58 |
59 | next if result[url]
60 | next if @post.custom_fields[GithubLinkback.field_for(url)].present?
61 | next unless is_allowed_project_link?(projects, project)
62 |
63 | link = Link.new(url, project, :pr)
64 | link.pr_number = pr_number.to_i
65 | result[url] = link
66 | elsif l =~ %r{https?://github.com/([^/]+)/([^/]+)/issues/(\d+)}
67 | url, org, repo, issue_number = Regexp.last_match.to_a
68 | project = "#{org}/#{repo}"
69 |
70 | next if result[url]
71 | next if @post.custom_fields[GithubLinkback.field_for(url)].present?
72 | next unless is_allowed_project_link?(projects, project)
73 |
74 | link = Link.new(url, project, :issue)
75 | link.issue_number = issue_number.to_i
76 | result[url] = link
77 | end
78 | end
79 | result.values
80 | end
81 |
82 | def is_allowed_project_link?(projects, project)
83 | return true if projects.include?(project)
84 |
85 | check_user = project.split("/")[0]
86 | projects.any? do |allowed_project|
87 | allowed_user, allowed_all_projects = allowed_project.split("/")
88 | (allowed_user == check_user) && (allowed_all_projects == "*")
89 | end
90 | end
91 |
92 | def create
93 | return [] if SiteSetting.github_linkback_access_token.blank?
94 |
95 | links = []
96 |
97 | DistributedMutex.synchronize("github_linkback_#{@post.id}") do
98 | links = github_links
99 | return [] if links.length() > SiteSetting.github_linkback_maximum_links
100 |
101 | links.each do |link|
102 | case link.type
103 | when :commit
104 | post_commit(link)
105 | when :pr
106 | post_pr_or_issue(link, :pr)
107 | when :issue
108 | post_pr_or_issue(link, :issue)
109 | else
110 | next
111 | end
112 |
113 | # Don't post the same link twice
114 | @post.custom_fields[GithubLinkback.field_for(link.url)] = "true"
115 | end
116 | @post.save_custom_fields
117 | end
118 |
119 | links
120 | end
121 |
122 | def self.field_for(url)
123 | "github-linkback:#{Digest::SHA1.hexdigest(url)[0..15]}"
124 | end
125 |
126 | private
127 |
128 | def post_pr_or_issue(link, type)
129 | pr_or_issue_number = link.pr_number || link.issue_number
130 | github_url =
131 | "https://api.github.com/repos/#{link.project}/issues/#{pr_or_issue_number}/comments"
132 | comment =
133 | I18n.t(
134 | type == :pr ? "github_linkback.pr_template" : "github_linkback.issue_template",
135 | title: SiteSetting.title,
136 | post_url: "#{Discourse.base_url}#{@post.url}",
137 | )
138 |
139 | Excon.post(github_url, body: { body: comment }.to_json, headers: headers)
140 | end
141 |
142 | def post_commit(link)
143 | github_url = "https://api.github.com/repos/#{link.project}/commits/#{link.sha}/comments"
144 |
145 | comment =
146 | I18n.t(
147 | "github_linkback.commit_template",
148 | title: SiteSetting.title,
149 | post_url: "#{Discourse.base_url}#{@post.url}",
150 | )
151 |
152 | Excon.post(github_url, body: { body: comment }.to_json, headers: headers)
153 | end
154 |
155 | def headers
156 | {
157 | "Content-Type" => "application/json",
158 | "Authorization" => "token #{SiteSetting.github_linkback_access_token}",
159 | "User-Agent" => "Discourse-Github-Linkback",
160 | }
161 | end
162 | end
163 |
--------------------------------------------------------------------------------
/app/lib/github_linkback_access_token_setting_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class GithubLinkbackAccessTokenSettingValidator
4 | def initialize(opts = {})
5 | @opts = opts
6 | end
7 |
8 | def valid_value?(val)
9 | return true if val.blank?
10 | client = Octokit::Client.new(access_token: val, per_page: 1)
11 | DiscourseGithubPlugin::GithubRepo.repos.each { |repo| client.branches(repo.name) }
12 | true
13 | rescue Octokit::Unauthorized
14 | false
15 | end
16 |
17 | def error_message
18 | I18n.t("site_settings.errors.invalid_github_linkback_access_token")
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/app/lib/github_permalinks.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module ::GithubPermalinks
4 | def self.replace_github_non_permalinks(post)
5 | # replaces github non-permalinks with permalinks containing a specific commit id
6 | regex = %r{https?://github\.com/[^/]+/[^/\s]+/blob/[^\s]+}i
7 |
8 | # don't replace urls in posts that are more than 1h old
9 | return if ((Time.zone.now - post.created_at) / 60).round > 60
10 |
11 | # only run the job when post is changed by a user and it contains a github url
12 | return if (post.last_editor_id && post.last_editor_id <= 0) || !post.raw.match(regex)
13 |
14 | # make sure no other job is scheduled
15 | Jobs.cancel_scheduled_job(:replace_github_non_permalinks, post_id: post.id)
16 |
17 | # schedule the job
18 | Jobs.enqueue_in(
19 | (SiteSetting.editing_grace_period + 1).seconds.to_i,
20 | :replace_github_non_permalinks,
21 | post_id: post.id,
22 | bypass_bump: false,
23 | )
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/app/models/github_commit.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscourseGithubPlugin
4 | class GithubCommit < ActiveRecord::Base
5 | belongs_to :repo, class_name: :GithubRepo
6 | end
7 | end
8 |
9 | # == Schema Information
10 | #
11 | # Table name: github_commits
12 | #
13 | # id :bigint not null, primary key
14 | # repo_id :bigint not null
15 | # sha :string(40) not null
16 | # email :string(513) not null
17 | # committed_at :datetime not null
18 | # role_id :integer not null
19 | # merge_commit :boolean default(FALSE), not null
20 | # created_at :datetime not null
21 | # updated_at :datetime not null
22 | #
23 | # Indexes
24 | #
25 | # index_github_commits_on_repo_id (repo_id)
26 | #
27 |
--------------------------------------------------------------------------------
/app/models/github_repo.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscourseGithubPlugin
4 | class GithubRepo < ActiveRecord::Base
5 | VALID_URL_BASED_REPO_REGEX = %r{https?://github.com/(.+)}
6 | VALID_USER_BASED_REPO_REGEX = Octokit::Repository::NAME_WITH_OWNER_PATTERN
7 |
8 | has_many :commits, foreign_key: :repo_id, class_name: :GithubCommit, dependent: :destroy
9 |
10 | def self.repos
11 | repos = []
12 | SiteSetting
13 | .github_badges_repos
14 | .split("|")
15 | .each do |link|
16 | name = match_name_from_setting(link)
17 | next if name.blank?
18 | name.gsub!(/\.git$/, "")
19 | name.gsub!(%r{/$}, "") # Remove trailing '/'
20 | repos << find_or_create_by!(name: name)
21 | end
22 | repos
23 | end
24 |
25 | def self.match_name_from_setting(repo)
26 | if repo =~ VALID_URL_BASED_REPO_REGEX
27 | Regexp.last_match[1]
28 | elsif repo =~ VALID_USER_BASED_REPO_REGEX
29 | repo_name = Regexp.last_match[0]
30 | repo.match(/https?:/).blank? ? repo_name : nil
31 | end
32 | end
33 | end
34 | end
35 |
36 | # == Schema Information
37 | #
38 | # Table name: github_repos
39 | #
40 | # id :bigint not null, primary key
41 | # name :string(255) not null
42 | # created_at :datetime not null
43 | # updated_at :datetime not null
44 | #
45 | # Indexes
46 | #
47 | # index_github_repos_on_name (name) UNIQUE
48 | #
49 |
--------------------------------------------------------------------------------
/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_github: "Discourse GitHub"
13 | replace_github_link:
14 | edit_reason: "تم استبدال رابط Github برابط دائم"
15 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | admin_js:
9 | admin:
10 | site_settings:
11 | categories:
12 | discourse_github: "Discourse GitHub"
13 | replace_github_link:
14 | edit_reason: "Odkaz na Github byl nahrazen trvalým odkazem"
15 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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_github: "Discourse – GitHub"
13 | replace_github_link:
14 | edit_reason: "Github-Link wurde durch einen permanenten Link ersetzt"
15 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/config/locales/client.en.yml:
--------------------------------------------------------------------------------
1 | en:
2 | admin_js:
3 | admin:
4 | site_settings:
5 | categories:
6 | discourse_github: "Discourse GitHub"
7 | replace_github_link:
8 | edit_reason: "Github link was replaced with a permanent link"
9 |
--------------------------------------------------------------------------------
/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_github: "GitHub de Discourse"
13 | replace_github_link:
14 | edit_reason: "El enlace de Github ha sido sustituido por un enlace permanente"
15 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | replace_github_link:
9 | edit_reason: "پیوند گیتهاب با یک پیوند دائمی جایگزین شد"
10 |
--------------------------------------------------------------------------------
/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_github: "Discourse GitHub"
13 | replace_github_link:
14 | edit_reason: "Github-linkki korvattiin pysyvällä linkillä"
15 |
--------------------------------------------------------------------------------
/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_github: "Discourse GitHub"
13 | replace_github_link:
14 | edit_reason: "Le lien Github a été remplacé par un lien permanent"
15 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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_github: "Discourse GitHub"
13 | replace_github_link:
14 | edit_reason: "הקישור ל־GitHub הוחלף בקישור קבוע"
15 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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_github: "Discourse GitHub"
13 | replace_github_link:
14 | edit_reason: "Il collegamento Github è stato sostituito con un collegamento permanente"
15 |
--------------------------------------------------------------------------------
/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_github: "Discourse GitHub"
13 | replace_github_link:
14 | edit_reason: "GitHub リンクはパーマリンクに置き換えられました"
15 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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_github: "Discourse GitHub"
13 | replace_github_link:
14 | edit_reason: "Github-link is vervangen door een permanente link"
15 |
--------------------------------------------------------------------------------
/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 | replace_github_link:
9 | edit_reason: "Link do Githuba został zastąpiony stałym linkiem"
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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_github: "Discourse GitHub"
13 | replace_github_link:
14 | edit_reason: "O link do Github foi subtituído por um link permanente"
15 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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_github: "Плагин GitHub для Discourse"
13 | replace_github_link:
14 | edit_reason: "Ссылка на Github была заменена на постоянную ссылку"
15 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | replace_github_link:
9 | edit_reason: "Github-länken ersattes med en permanent länk"
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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_github: "Discourse GitHub"
13 | replace_github_link:
14 | edit_reason: "Github bağlantısı kalıcı bir bağlantıyla değiştirildi"
15 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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_github: "Discourse GitHub"
13 | replace_github_link:
14 | edit_reason: "Github 链接被替换为永久链接"
15 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | enable_discourse_github_plugin: "تفعيل المكوِّن الإضافي discourse-github"
10 | github_linkback_enabled: "ربط مشكلات GitHub بمناقشات المنتدى"
11 | github_linkback_projects: "قائمة المشروعات التي يمكن الربط بها"
12 | github_linkback_access_token: 'رمز وصول صالح للمستخدم الذي سينشر الرابط ولإحصاء الإرسالات/المساهمات لمنح الشارات. راجع هنا للحصول على الإرشادات بشأن كيفية الحصول على رمز مميَّز.'
13 | github_linkback_maximum_links: "الحد الأقصى لعدد الروابط التي يمكن إنشاؤها من منشور واحد. عندما تحتوي إحدى المشاركات على روابط أكثر من الحد، لا يتم إنشاء أيٍّ منها."
14 | github_permalinks_enabled: "تفعيل استبدال الرابط الثابت من GitHub"
15 | github_permalinks_exclude: "اسم الملف أو الدليل الذي يجب استبعاده من استبدال الرابط الثابت. أدخل اسم الملف أو المسار الكامل فقط: user/repository/optional-directory/filename"
16 | github_badges_enabled: "تفعيل شارات GitHub"
17 | github_badges_repos: "عناوين URL الخاصة بمستودعات GitHub للبحث عن المساهمات والإرسالات"
18 | github_silver_badge_min_commits: "أقل عدد من الإرسالات للحصول على الشارة الفضية"
19 | github_gold_badge_min_commits: "أقل عدد من الإرسالات للحصول على الشارة الذهبية"
20 | errors:
21 | invalid_badge_repo: "يجب عليك إدخال عنوان URL على GitHub أو اسم المستودع بالتنسيق github_user/repository_name"
22 | invalid_github_linkback_access_token: "يجب عليك إدخال رمز وصول صالح إلى رابط GitHub والذي يمكنه الوصول إلى مستودعات الشارة التي أدخلتها."
23 | github_linkback:
24 | commit_template: |
25 | تم ذكر هذا الإرسال في **%{title}**. قد تكون هناك تفاصيل ذات صلة هناك:
26 |
27 | %{post_url}
28 | pr_template: |
29 | تم ذكر طلب السحب هذا في **%{title}**. قد تكون هناك تفاصيل ذات صلة هناك:
30 |
31 | %{post_url}
32 | issue_template: |
33 | تم ذكر هذه المشكلة في **%{title}**. قد تكون هناك تفاصيل ذات صلة هناك:
34 |
35 | %{post_url}
36 | github_commits_populator:
37 | errors:
38 | repository_identifier_invalid_pm_title: "الإجراء المطلوب للمكوِّن الإضافي discourse-github"
39 | repository_identifier_invalid_pm: |
40 | المستودع المحدَّد في المكوِّن الإضافي discourse-github غير صالح:
41 | %{repo_name}
42 |
43 | يجب تحديده في صورة `user/repo`.
44 |
45 | لن يتم منح الشارات حتى يتم تصحيح الاسم في
46 | إعدادات الموقع لـ discourse-github
47 | وإعادة تشغيل "github_badges_enabled".
48 | repository_not_found_pm_title: "الإجراء المطلوب للمكوِّن الإضافي discourse-github"
49 | repository_not_found_pm: |
50 | أرجع المستودع المحدَّد في المكوِّن الإضافي discourse-github رسالة الخطأ "غير موجود":
51 | %{repo_name}
52 |
53 | يجب تحديده في صورة `user/repo`.
54 |
55 | لن يتم منح الشارات حتى يتم تصحيح الاسم في
56 | إعدادات الموقع لـ discourse-github
57 | وإعادة تشغيل "github_badges_enabled".
58 | invalid_octokit_credentials_pm_title: "الإجراء المطلوب للمكوِّن الإضافي discourse-github"
59 | invalid_octokit_credentials_pm: |
60 | بيانات اعتماد GitHub التي أدخلتها للمكوِّن الإضافي discourse-github غير صالحة. تم تعطيل إعداد الموقع "github badges enabled"، ولن يتم ملء الإرسالات بعد الآن حتى يتم حل المشكلة.
61 |
62 | تحقَّق من إعداد الموقع "رمز الوصول إلى رابط github" للتأكُّد من صحة الرمز المميَّز وأن لديه إذن لجميع المستودعات عبر
63 | إعدادات الموقع لـ discourse-github.
64 |
--------------------------------------------------------------------------------
/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 | site_settings:
9 | enable_discourse_github_plugin: "Povolit discourse-github plugin"
10 | github_linkback_enabled: "Propojit GitHub issues a diskuse na fóru"
11 | github_linkback_projects: "Seznam projektů, které chcete propojit"
12 | github_linkback_access_token: 'Platný přístupový token pro uživatele, který bude zveřejňovat zpětný odkaz a počítat commity/příspěvky pro udělování odznaků. Pokyny k získání tokenu naleznete zde.'
13 | github_linkback_maximum_links: "Maximální počet zpětných odkazů, které lze vytvořit z jednoho příspěvku. Když příspěvek obsahuje více odkazů, žádný se nevytvoří."
14 | github_permalinks_enabled: "Povolení přepisování trvalých odkazů GitHubu"
15 | github_permalinks_exclude: "Název souboru nebo adresáře, který má být vyloučen z přepisování trvalých odkazů. Zadejte pouze název souboru nebo celou cestu: user/repository/optional-directory/filename."
16 | github_badges_enabled: "Povolit odznaky GitHub"
17 | github_badges_repos: "Adresy URL repozitářů GitHub pro vyhledávání příspěvků a commitů."
18 | github_silver_badge_min_commits: "Minimální počet commitů pro stříbrný odznak"
19 | github_gold_badge_min_commits: "Minimální počet commitů pro zlatý odznak"
20 | errors:
21 | invalid_badge_repo: "Musíte zadat adresu URL GitHubu nebo název úložiště ve formátu github_user/repository_name"
22 | invalid_github_linkback_access_token: "Musíte poskytnout platný přístupový token pro zpětné odkazy GitHub, který má přístup k repozitářům odznaků, které jste poskytli."
23 | github_linkback:
24 | commit_template: |
25 | Tento commit byl zmíněn na **%{title}**. Mohou tam být relevantní podrobnosti:
26 |
27 | %{post_url}
28 | pr_template: |
29 | Tento pull request byl zmíněn na **%{title}**. Možná tam existují relevantní podrobnosti:
30 |
31 | %{post_url}
32 | issue_template: |
33 | Tento problém byl zmíněn na **%{title}**. Tam mohou být relevantní podrobnosti:
34 |
35 | %{post_url}
36 | github_commits_populator:
37 | errors:
38 | repository_identifier_invalid_pm_title: "Pro plugin discourse-github je vyžadována akce"
39 | repository_identifier_invalid_pm: |
40 | Repozitář zadaný v pluginu discourse-github je neplatný:
41 | %{repo_name}
42 |
43 | Měl by být zadán jako `user/repo`.
44 |
45 | Odznaky nebudou uděleny, dokud nebude název opraven v
46 | nastavení webu discourse-github
47 | a nebude znovu zapnuto „github_badges_enabled“.
48 | repository_not_found_pm_title: "Pro plugin discourse-github je vyžadována akce"
49 | repository_not_found_pm: |
50 | Repozitář uvedený v pluginu discourse-github vrátil chybu "Not Found"
51 | : %{repo_name}
52 |
53 | odznaky nebudou uděleny, dokud nebude název opraven v
54 | nastavení webu discourse-github
55 | a nebude znovu zapnuto "github_badges_enabled".
56 | invalid_octokit_credentials_pm_title: "Pro plugin discourse-github je vyžadována akce"
57 | invalid_octokit_credentials_pm: "Pověření GitHub poskytnutá pluginu discourse-github jsou neplatná. Nastavení \"github badges enabled\" \nbylo deaktivováno a commity již nebudou vyplňovány, dokud nebude problém vyřešen.\n\nZkontrolujte nastavení webu „github linkback access token“, abyste se ujistili, že token je správný a má oprávnění ke všem úložištím\nprostřednictvím\nnastavení webu discourse-github.\n"
58 |
--------------------------------------------------------------------------------
/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 | enable_discourse_github_plugin: "Aktiviere das discourse-github-Plug-in"
10 | github_linkback_enabled: "GitHub-Themen mit Forumsdiskussionen verlinken"
11 | github_linkback_projects: "Liste der Projekte, von denen zurückverlinkt werden soll"
12 | github_linkback_access_token: 'Ein gültiges Zugriffstoken für den Benutzer, der den Linkback veröffentlicht, und für das Zählen von Commits/Beiträgen, um Abzeichen zu vergeben. Siehe hier für Anweisungen, wie du ein Token bekommst.'
13 | github_linkback_maximum_links: "Maximale Anzahl von Linkbacks, die aus einem einzigen Beitrag erstellt werden können. Wenn ein Beitrag mehr Links enthält, werden keine erstellt."
14 | github_permalinks_enabled: "Überschreiben von GitHub-Permalinks aktivieren"
15 | github_permalinks_exclude: "Dateiname oder Verzeichnis, der/das vom Überschreiben von Permalinks ausgeschlossen werden soll. Gib nur den Dateinamen oder den vollständigen Pfad an: user/repository/optional-directory/filename"
16 | github_badges_enabled: "GitHub-Abzeichen aktivieren"
17 | github_badges_repos: "URLs der GitHub-Repos, die nach Beiträgen und Commits durchsucht werden sollen"
18 | github_silver_badge_min_commits: "Mindestanzahl an Commits für das Silberabzeichen"
19 | github_gold_badge_min_commits: "Mindestanzahl an Commits für das Goldabzeichen"
20 | errors:
21 | invalid_badge_repo: "Du musst eine GitHub-URL oder den Repository-Namen im Format github_user/repository_name angeben"
22 | invalid_github_linkback_access_token: "Du musst ein gültiges GitHub-Linkback-Access-Token angeben, das Zugriff auf die von dir angegebenen Abzeichen-Repositories hat."
23 | github_linkback:
24 | commit_template: |
25 | Dieser Commit wurde auf **%{title}** erwähnt. Vielleicht gibt es dort relevante Details:
26 |
27 | %{post_url}
28 | pr_template: |
29 | Dieser PR wurde auf **%{title}** erwähnt. Vielleicht gibt es dort relevante Details:
30 |
31 | %{post_url}
32 | issue_template: |
33 | Dieses Thema wurde auf **%{title}** erwähnt. Vielleicht gibt es dort relevante Details:
34 |
35 | %{post_url}
36 | github_commits_populator:
37 | errors:
38 | repository_identifier_invalid_pm_title: "Aktion erforderlich für discourse-github-Plug-in"
39 | repository_identifier_invalid_pm: |
40 | Ein im discourse-github-Plug-in angegebenes Repository ist ungültig:
41 | %{repo_name}
42 |
43 | Es muss als `user/repo` angegeben werden.
44 |
45 | Abzeichen werden erst vergeben, nachdem der Name in den
46 | Website-Einstellungen für discourse-github
47 | korrigiert und „github_badges_enabled“ wieder aktiviert wurde.
48 | repository_not_found_pm_title: "Aktion erforderlich für discourse-github-Plug-in"
49 | repository_not_found_pm: |
50 | Ein im discourse-github-Plug-in angegebenes Repository wurde nicht gefunden:
51 | %{repo_name}
52 |
53 | Abzeichen werden erst vergeben, nachdem der Name in den
54 | Website-Einstellungen für discourse-github
55 | korrigiert und „github_badges_enabled“ wieder aktiviert wurde.
56 | invalid_octokit_credentials_pm_title: "Aktion erforderlich für discourse-github-Plug-in"
57 | invalid_octokit_credentials_pm: |
58 | Die GitHub-Anmeldedaten, die für das discourse-github-Plug-in angegeben wurden, sind ungültig. Die Website-Einstellung „github badges enabled“
59 | wurde deaktiviert und Commits werden nicht mehr übertragen, bis das Problem behoben ist.
60 |
61 | Überprüfe deine Website-Einstellung „github linkback access token“, um sicherzustellen, dass das Token korrekt ist und über Zugriffsrechte auf alle Repos verfügt. Besuche hierzu die
62 | Website-Einstellungen für discourse-github.
63 |
--------------------------------------------------------------------------------
/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 | enable_discourse_github_plugin: "Enable the discourse-github plugin"
4 | github_linkback_enabled: "Link GitHub issues back to forum discussions"
5 | github_linkback_projects: "List of projects to link back from"
6 | github_linkback_access_token: 'A valid access token for the user who will post the linkback and for counting commits/contributions to grant badges. See here for instructions on how to get a token.'
7 | github_linkback_maximum_links: "Maximum number of linkbacks to create from one single post. When a post contains more links, none is created."
8 | github_permalinks_enabled: "Enable GitHub permalink overwrites"
9 | github_permalinks_exclude: "Filename or directory that should be excluded from permalink overwrites. Provide only filename or full path: user/repository/optional-directory/filename"
10 | github_badges_enabled: "Enable GitHub badges"
11 | github_badges_repos: "URLs of the GitHub repos to scan for contributions and commits"
12 | github_silver_badge_min_commits: "Minumum number of commits for silver badge"
13 | github_gold_badge_min_commits: "Minumum number of commits for gold badge"
14 |
15 | errors:
16 | invalid_badge_repo: "You must provide a GitHub URL or the repository name in the format github_user/repository_name"
17 | invalid_github_linkback_access_token: "You must provide a valid GitHub linkback access token which has access to the badge repositories you have provided."
18 |
19 | github_linkback:
20 | commit_template: |
21 | This commit has been mentioned on **%{title}**. There might be relevant details there:
22 |
23 | %{post_url}
24 | pr_template: |
25 | This pull request has been mentioned on **%{title}**. There might be relevant details there:
26 |
27 | %{post_url}
28 | issue_template: |
29 | This issue has been mentioned on **%{title}**. There might be relevant details there:
30 |
31 | %{post_url}
32 | github_commits_populator:
33 | errors:
34 | repository_identifier_invalid_pm_title: "Action required for discourse-github plugin"
35 | repository_identifier_invalid_pm: |
36 | A repository specified in the discourse-github plugin is invalid:
37 | %{repo_name}
38 |
39 | They should be specified as `user/repo`.
40 |
41 | Badges will not be awarded until the name is corrected in
42 | discourse-github Site Settings
43 | and "github_badges_enabled" is turned back on.
44 | repository_not_found_pm_title: "Action required for discourse-github plugin"
45 | repository_not_found_pm: |
46 | A repository specified in the discourse-github plugin returned a "Not Found"
47 | error: %{repo_name}
48 |
49 | Badges will not be awarded until the name is corrected in
50 | discourse-github Site Settings
51 | and "github_badges_enabled" is turned back on.
52 | invalid_octokit_credentials_pm_title: "Action required for discourse-github plugin"
53 | invalid_octokit_credentials_pm: |
54 | The GitHub credentials provided to the discourse-github plugin are invalid. The "github badges enabled\ site
55 | setting has been disabled, and commits will no longer be populated until the issue is resolved.
56 |
57 | Check your "github linkback access token" site setting to ensure the token is correct and has permission to all
58 | repos via
59 | discourse-github Site Settings.
60 |
--------------------------------------------------------------------------------
/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 | enable_discourse_github_plugin: "Habilitar el plugin discourse-github"
10 | github_linkback_enabled: "Vincular problemas de GitHub a discusiones del foro"
11 | github_linkback_projects: "Lista de proyectos desde los que enlazar"
12 | github_linkback_access_token: 'Un token de acceso válido para el usuario que publicará el enlace de regreso y para contar commits/contribuciones para conceder insignias. Puedes obtener instrucciones sobre cómo obtener un token aquí.'
13 | github_linkback_maximum_links: "Número máximo de enlaces a crear a partir de una sola entrada. Cuando una entrada contiene más enlaces, no se crea ninguno."
14 | github_permalinks_enabled: "Habilitar sobrescrituras de enlaces permanentes de GitHub"
15 | github_permalinks_exclude: "Nombre de archivo o directorio que debe excluirse de las sobrescrituras de enlaces permanentes. Proporciona solo el nombre de archivo o la ruta completa: usuario/repositorio/directorio-opcional/nombre_del_archivo"
16 | github_badges_enabled: "Habilitar insignias de GitHub"
17 | github_badges_repos: "URL de los repositorios de GitHub para buscar contribuciones y commits"
18 | github_silver_badge_min_commits: "Número mínimo de commits para la insignia de plata"
19 | github_gold_badge_min_commits: "Número mínimo de commits para la insignia de oro"
20 | errors:
21 | invalid_badge_repo: "Debes proporcionar una URL de GitHub o el nombre del repositorio en el formato github_user/nombre_del_repositorio"
22 | invalid_github_linkback_access_token: "Debes proporcionar un token de acceso de enlace de retorno de GitHub válido que tenga acceso a los repositorios de insignias que has proporcionado."
23 | github_linkback:
24 | commit_template: |
25 | Este commit ha sido mencionado en **%{title}**. Puede que haya detalles relevantes allí:
26 |
27 | %{post_url}
28 | pr_template: |
29 | Esta solicitud de extracción ha sido mencionada en **%{title}**. Puede que haya detalles relevantes allí:
30 |
31 | %{post_url}
32 | issue_template: |
33 | Este problema ha sido mencionado en **%{title}**. Puede que haya detalles relevantes allí:
34 |
35 | %{post_url}
36 | github_commits_populator:
37 | errors:
38 | repository_identifier_invalid_pm_title: "Acción requerida para el plugin discourse-github"
39 | repository_identifier_invalid_pm: |
40 | Un repositorio especificado en el plugin discourse-github no es válido:
41 | %{repo_name}
42 |
43 | Deben especificarse como `user/repo`.
44 |
45 | No se concederán insignias hasta que se corrija el nombre en
46 | los Ajustes del sitio de discourse-github
47 | y «github_badges_enabled» esté habilitado de nuevo.
48 | repository_not_found_pm_title: "Acción requerida para el plugin discourse-github"
49 | repository_not_found_pm: |
50 | Un repositorio especificado en el plugin discourse-github ha devuelto un error
51 | «No encontrado»: %{repo_name}
52 |
53 | No se concederán insignias hasta que se corrija el nombre en
54 | los Ajustes del sitio de discourse-github
55 | y «github_badges_enabled» esté habilitado de nuevo.
56 | invalid_octokit_credentials_pm_title: "Acción requerida para el plugin discourse-github"
57 | invalid_octokit_credentials_pm: |
58 | Las credenciales de GitHub proporcionadas al plugin discourse-github no son válidas. El ajuste «github badges enabled\ site»
59 | ha sido deshabilitada, y los commits ya no se poblarán hasta que el problema sea resuelto.
60 |
61 | Comprueba la configuración de tu «token de acceso al enlace de retorno de github» para asegurarte de que el token es correcto y tienes permiso para todos los
62 | repositorios a través de
63 | los Ajustes del sitio de discourse-github.
64 |
--------------------------------------------------------------------------------
/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 | enable_discourse_github_plugin: "افزونه discourse-github را فعال کنید"
10 | github_permalinks_enabled: "فعال کردن بازنویسی پیوند دائمی گیتهاب"
11 | github_badges_enabled: "فعال کردن نشانهای گیتهاب"
12 |
--------------------------------------------------------------------------------
/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 | enable_discourse_github_plugin: "Ota discourse-github-lisäosa käyttöön"
10 | github_linkback_enabled: "Liitä GitHub-ongelmat foorumin keskusteluihin"
11 | github_linkback_projects: "Luettelo projekteista, joista voit linkittää takaisin"
12 | github_linkback_access_token: 'Kelvollinen käyttöoikeustietue käyttäjälle, joka julkaisee paluulinkin, ja solmujen/kontribuutioiden laskemiseen kunniamerkkien myöntämiseksi. Katso ohjeita tietueen saamiseen täältä.'
13 | github_linkback_maximum_links: "Yhdestä viestistä julkaistavien paluulinkkien enimmäismäärä. Kun viesti sisältää enemmän linkkejä, yhtään ei luoda."
14 | github_permalinks_enabled: "Ota GitHubin pysyvien linkkien korvaaminen käyttöön"
15 | github_permalinks_exclude: "Tiedostonimi tai hakemisto, joka tulee sulkea pois pysyvien linkkien korvaamisesta. Anna vain tiedostonimi tai täydellinen polku: käyttäjä/tietovarasto/valinnainen-hakemisto/tiedostonimi"
16 | github_badges_enabled: "Ota GitHub-kunniamerkit käyttöön"
17 | github_badges_repos: "GitHub-tietovarastojen URL-osoitteet, joista etsitään kontribuutioita ja solmuja"
18 | github_silver_badge_min_commits: "Solmujen vähimmäismäärä hopeakunniamerkin saamiseksi"
19 | github_gold_badge_min_commits: "Solmujen vähimmäismäärä kultakunniamerkin saamiseksi"
20 | errors:
21 | invalid_badge_repo: "Sinun täytyy antaa GitHubin URL-osoite tai tietovaraston nimi muodossa github_käyttäjä/tietovaraston_nimi"
22 | invalid_github_linkback_access_token: "Sinun täytyy antaa kelvollinen GitHub-paluulinkin käyttöoikeustietue, jolla on antamiesi kunniamerkkitietovarastojen käyttöoikeus."
23 | github_linkback:
24 | commit_template: |
25 | Tämä solmu on mainittu ketjussa **%{title}**. Sieltä voi löytyä olennaisia tietoja:
26 |
27 | %{post_url}
28 | pr_template: |
29 | Tämä vetopyyntö on mainittu ketjussa **%{title}**. Sieltä voi löytyä olennaisia tietoja:
30 |
31 | %{post_url}
32 | issue_template: |
33 | Tämä seikka on mainittu ketjussa **%{title}**. Sieltä voi löytyä olennaisia tietoja:
34 |
35 | %{post_url}
36 | github_commits_populator:
37 | errors:
38 | repository_identifier_invalid_pm_title: "Discourse-github-lisäosa edellyttää toimenpiteitä"
39 | repository_identifier_invalid_pm: |
40 | Discourse-github-lisäosassa määritetty tietovarasto on virheellinen:
41 | %{repo_name}
42 |
43 | Ne tulisi määrittää muodossa "käyttäjä/tietovarasto".
44 |
45 | Kunniamerkkejä ei myönnetä ennen kuin nimi on korjattu
46 | discourse-githubin sivustoasetuksissa
47 | ja "github_badges_enabled" on otettu käyttöön uudelleen.
48 | repository_not_found_pm_title: "Discourse-github-lisäosa edellyttää toimenpiteitä"
49 | repository_not_found_pm: |
50 | Discourse-github-lisäosassa määritetty tietovarasto palautti "ei löydy" -virheen:
51 | %{repo_name}
52 |
53 | Kunniamerkkejä ei myönnetä ennen kuin nimi on korjattu
54 | discourse-githubin sivustoasetuksissa
55 | ja "github_badges_enabled" on otettu käyttöön uudelleen.
56 | invalid_octokit_credentials_pm_title: "Discourse-github-lisäosa edellyttää toimenpiteitä"
57 | invalid_octokit_credentials_pm: |
58 | Discourse-github-lisäosalle annetut GitHubin tunnistetiedot ovat virheellisiä. "Github badges enabled" -sivustoasetus on poistettu käytöstä, eikä solmuja enää täytetä ennen kuin ongelma on ratkaistu.
59 |
60 | Tarkista "github linkback access token" -sivustoasetuksesi varmistaaksesi, että tietue on oikea ja että sillä on kaikkien tietovarastojen käyttöoikeus discourse-githubin sivustoasetuksissa.
61 |
--------------------------------------------------------------------------------
/config/locales/server.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 | site_settings:
9 | enable_discourse_github_plugin: "Activer l'extension discourse-github"
10 | github_linkback_enabled: "Relier les problèmes de GitHub aux discussions du forum"
11 | github_linkback_projects: "Liste des projets à partir desquels effectuer le lien"
12 | github_linkback_access_token: 'Un jeton d''accès valide pour l''utilisateur qui publiera le lien et pour compter les commits/contributions pour accorder des badges. Consultez cette page pour savoir comment obtenir un jeton.'
13 | github_linkback_maximum_links: "Nombre maximal de liens à créer à partir d'un seul message. Lorsqu'un message contient plus de liens, aucun d'entre eux n'est créé."
14 | github_permalinks_enabled: "Activer les écrasements de permaliens GitHub"
15 | github_permalinks_exclude: "Nom de fichier ou répertoire à exclure des remplacements de permaliens. Indiquez uniquement le nom de fichier ou le chemin d'accès complet : user/repository/optional-directory/filename"
16 | github_badges_enabled: "Activer les badges GitHub"
17 | github_badges_repos: "Adresses URL des dépôts GitHub pour rechercher les contributions et les commits"
18 | github_silver_badge_min_commits: "Nombre minimal de commits pour le badge d'argent"
19 | github_gold_badge_min_commits: "Nombre minimal de commits pour le badge d'or"
20 | errors:
21 | invalid_badge_repo: "Vous devez fournir une adresse URL GitHub ou le nom du dépôt au format github_user/repository_name"
22 | invalid_github_linkback_access_token: "Vous devez fournir un jeton d'accès de lien GitHub valide qui donne accès aux dépôts de badges que vous avez fournis."
23 | github_linkback:
24 | commit_template: |
25 | Ce commit a été mentionné sur **%{title}**. Il pourrait y avoir des détails pertinents ici :
26 |
27 | %{post_url}
28 | pr_template: |
29 | Cette requête pull a été mentionnée sur **%{title}**. Il pourrait y avoir des détails pertinents ici :
30 |
31 | %{post_url}
32 | issue_template: |
33 | Ce problème a été mentionné sur **%{title}**. Il pourrait y avoir des détails pertinents ici :
34 |
35 | %{post_url}
36 | github_commits_populator:
37 | errors:
38 | repository_identifier_invalid_pm_title: "Action requise pour l'extension discourse-github"
39 | repository_identifier_invalid_pm: |
40 | Un dépôt spécifié dans l'extension discourse-github n'est pas valide :
41 | %{repo_name}
42 |
43 | Ils doivent être spécifiés en tant que « user/repo ».
44 |
45 | Les badges ne seront pas attribués tant que le nom n'aura pas été corrigé dans les paramètres du site
46 |
47 | et que « github_badges_enabled » ne sera pas réactivé.
48 | repository_not_found_pm_title: "Action requise pour l'extension discourse-github"
49 | repository_not_found_pm: |
50 | Un dépôt spécifié dans l'extension discourse-github a renvoyé une erreur
51 | %{repo_name}
52 |
53 | Les badges ne seront pas attribués tant que le nom n'aura pas été corrigé dans les
54 | paramètres du site discourse-github
55 | et que « github_badges_enabled » n'aura pas été réactivé.
56 | invalid_octokit_credentials_pm_title: "Action requise pour l'extension discourse-github"
57 | invalid_octokit_credentials_pm: "Les informations d'identification GitHub fournies à l'extension discourse-github ne sont pas valides. Le paramètre de site « badges github activés » \na été désactivé et les validations ne seront plus renseignées tant que le problème ne sera pas résolu.\n\nVérifiez le paramètre de site « jeton d'accès au lien github » pour vous assurer que le jeton est correct et autorisé à accéder à tous les\ndépôts via les\nparamètres de site discours-github.\n"
58 |
--------------------------------------------------------------------------------
/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 | enable_discourse_github_plugin: "הפעלת התוסף discourse-github"
10 | github_linkback_enabled: "קישור תקלות ב־GitHub בחזרה לדיונים בפורום"
11 | github_linkback_projects: "רשימות של מיזמים לקשר מהם בחזרה"
12 | github_linkback_access_token: 'אסימון גישה תקף למשתמש שיפרסם את הקישור החוזה ולספירת הגשות/תרומות כדי להעניק עיטורים. ניתן לעיין כאן להנחיות איך לקבל את האסימון.'
13 | github_linkback_maximum_links: "מספר הקישורים החוזרים המרבי ליצירה מפוסט יחיד. כאשר פוסט מכיל יותר קישורים, לא נוצרים כלל."
14 | github_permalinks_enabled: "הפעלת שכתוב כתובות קבועות של GitHub"
15 | github_permalinks_exclude: "שם קובץ או תיקייה שיוחרגו משכתובי הקישורים הקבועים. יש לספק שם קובץ או נתיב מלא בלבד: user/repository/optional-directory/filename"
16 | github_badges_enabled: "הפעלת עיטורים של GitHub"
17 | github_badges_repos: "כתובות של מאגרי GitHub לסריקה אחר תרומות והגשות"
18 | github_silver_badge_min_commits: "מספר ההגשות המזערי לעיטור כסף"
19 | github_gold_badge_min_commits: "מספר ההגשות המזערי לעיטור זהב"
20 | errors:
21 | invalid_badge_repo: "עליך לספק כתובת GitHub או את שם המאגר בצורה github_user/repository_name"
22 | invalid_github_linkback_access_token: "עליך לספק אסימון גישה תקף לקישור חוזר אל GitHub שיש לו גישה למאגרי העיטורים שסיפקת."
23 | github_linkback:
24 | commit_template: |
25 | הגשה (Commit) זו הוזכרה ב־**%{title}**. יכול להיות שיש פרטים קשורים כאן:
26 |
27 | %{post_url}
28 | pr_template: |
29 | בקשת דחיפה (Pull Request) זו הוזכרה ב־**%{title}**. יכול להיות שיש פרטים קשורים כאן:
30 |
31 | %{post_url}
32 | issue_template: |
33 | נושא (Issue) זה הוזכר ב־**%{title}**. יכול להיות שיש פרטים קשורים כאן:
34 |
35 | %{post_url}
36 | github_commits_populator:
37 | errors:
38 | repository_identifier_invalid_pm_title: "נדרשת פעולה עבור תוסף discourse-github"
39 | repository_identifier_invalid_pm: |
40 | מאגר שצוין ב־discourse-github שגוי:
41 | %{repo_name}
42 |
43 | יש לציין אותם בתור `user/repo` (משתמש/מאגר).
44 |
45 | לא יוענקו עיטורים עד שהשם יתוקן
46 | בהגדרות האתר של discourse-github
47 | ו־„github_badges_enabled” (עיטורים של GitHub פעילים) מופעל בחזרה.
48 | repository_not_found_pm_title: "נדרשת פעולה עבור תוסף discourse-github"
49 | repository_not_found_pm: |
50 | מאגר שצוין ב־discourse-github החזירה שגיאת „לא נמצא”: %{repo_name}
51 |
52 | לא יוענקו עיטורים עד שהשם יתוקן
53 | בהגדרות האתר של discourse-github
54 | ו־„github_badges_enabled” (עיטורים של GitHub פעילים) מופעל בחזרה.
55 | invalid_octokit_credentials_pm_title: "נדרשת פעולה עבור תוסף discourse-github"
56 | invalid_octokit_credentials_pm: |
57 | פרטי הגישה ל־GitHub שסופקו לתוסף discourse-github שגויים. הגדרת האתר „github badges enabled” הושבתה וההגשות לא ימולאו עד לפתרון התקלה.
58 |
59 | כדאי לבדוק את הגדרת האתר „github linkback access token” (אסימון גישה לקישור חוזר ל־GitHub) כדי לוודא שהאסימון נכון ושיש ללו הרשאות לכל המאגרים דרך הגדרות האתר של discourse-github.
60 |
--------------------------------------------------------------------------------
/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 | enable_discourse_github_plugin: "Abilita il plugin discourse-github"
10 | github_linkback_enabled: "Collega i problemi di Github alle relative discussioni sul forum"
11 | github_linkback_projects: "Elenco dei progetti da collegare al forum"
12 | github_linkback_access_token: 'Un token di accesso valido per l''utente che pubblicherà il linkback e per il conteggio dei commit/contributi per la concessione di distintivi. Consulta qui le istruzioni per ottenere un token.'
13 | github_linkback_maximum_links: "Numero massimo di linkback da creare da un singolo messaggio. Quando un messaggio contiene più link, non ne viene creato nessuno."
14 | github_permalinks_enabled: "Abilita le sovrascritture dei collegamenti GitHub permanenti"
15 | github_permalinks_exclude: "Nome del file o directory che dovrebbe essere esclusa dalle sovrascritture dei collegamenti permanenti. Fornisci solo il nome del file o il percorso completo: user/repository/optional-directory/filename"
16 | github_badges_enabled: "Abilita distintivi GitHub"
17 | github_badges_repos: "URL degli archivi GitHub per cercare contributi e commit"
18 | github_silver_badge_min_commits: "Numero minimo di commit per il distintivo d'argento"
19 | github_gold_badge_min_commits: "Numero minimo di commit per il distintivo d'oro"
20 | errors:
21 | invalid_badge_repo: "Devi fornire un URL GitHub o il nome dell'archivio nel formato github_user/repository_name"
22 | invalid_github_linkback_access_token: "Devi fornire un token valido di accesso al linkback GitHub che permette di accedere agli archivi dei distintivi che hai fornito."
23 | github_linkback:
24 | commit_template: |
25 | Questo problema è stato menzionato in **%{title}**. Lì potresti trovare informazioni rilevanti:
26 |
27 | %{post_url}
28 | pr_template: |
29 | Questa richiesta pull è stata menzionata in **%{title}**. Lì potresti trovare informazioni rilevanti:
30 |
31 | %{post_url}
32 | issue_template: |
33 | Questo problema è stato menzionato in **%{title}**. Lì potresti trovare informazioni rilevanti:
34 |
35 | %{post_url}
36 | github_commits_populator:
37 | errors:
38 | repository_identifier_invalid_pm_title: "Azione richiesta per il plug-in discourse-github"
39 | repository_identifier_invalid_pm: |
40 | Un archivio indicato nel plugin discourse-github non è valido:
41 | %{repo_name}
42 |
43 | Dovrebbe essere indicato in formato `user/repo`.
44 |
45 | I distintivi non saranno assegnati fino a quando il nome non sarà corretto nelle
46 | Impostazioni del sito discourse-github
47 | e l'opzione "github_badges_enabled" non sarà riattivata.
48 | repository_not_found_pm_title: "Azione richiesta per il plug-in discourse-github"
49 | repository_not_found_pm: |
50 | Un archivio indicato nel plugin discourse-github ha restituito un errore "Non trovato": %{repo_name}
51 |
52 | I distintivi non saranno assegnati fino a quando il nome non sarà corretto nelle
53 | Impostazioni del sito discourse-github
54 | e l'opzione "github_badges_enabled" non sarà riattivata.
55 | invalid_octokit_credentials_pm_title: "Azione richiesta per il plug-in discourse-github"
56 | invalid_octokit_credentials_pm: |
57 | Le credenziali GitHub fornite al plug-in discourse-github non sono valide. L'impostazione del sito "github badge enabled"
58 | è stata disabilitata e i commit non verranno più compilati fino a quando il problema non sarà risolto.
59 |
60 | Controlla l'impostazione del sito "github linkback access token" per assicurarti che il token sia corretto e abbia l'autorizzazione per tutti gli
61 | accessi tramite le
62 | Impostazioni del sito discourse-github.
63 |
--------------------------------------------------------------------------------
/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 | enable_discourse_github_plugin: "discourse-github プラグインを有効にする"
10 | github_linkback_enabled: "GitHub の課題をフォーラムディスカッションにバックリンクする"
11 | github_linkback_projects: "バックリンクするプロジェクトのリスト"
12 | github_linkback_access_token: 'バックリンクを投稿するユーザー用とバッジを付与するためのコミット数/貢献数をカウントするための有効なアクセストークン。トークンの取得方法については、こちらをご覧ください。'
13 | github_linkback_maximum_links: "1 つの投稿から作成できるリンクバックの最大数。投稿に複数のリンクが含まれる場合は、何も作成されません。"
14 | github_permalinks_enabled: "GitHub パーマリンクの上書きを有効にする"
15 | github_permalinks_exclude: "パーマリンクの上書きから除外する必要のあるファイル名またはディレクトリ。ファイル名のみ、またはフルパス(user/repository/optional-directory/filename)を指定します"
16 | github_badges_enabled: "GitHub バッジを有効にする"
17 | github_badges_repos: "貢献とコミットをスキャンする GitHub リポジトリの URL"
18 | github_silver_badge_min_commits: "シルバーバッジの最低コミット数"
19 | github_gold_badge_min_commits: "ゴールドバッジの最低コミット数"
20 | errors:
21 | invalid_badge_repo: "GitHub URL または github_user/repository_name の形式のリポジトリ名を指定する必要があります"
22 | invalid_github_linkback_access_token: "指定したバッジリポジトリにアクセスできる有効な GitHub バックリンクアクセストークンを指定する必要があります。"
23 | github_linkback:
24 | commit_template: |
25 | このコミットは **%{title}** でメンションされています。関連する詳細があるかもしれません。
26 |
27 | %{post_url}
28 | pr_template: |
29 | このプルリクエストは **%{title}** でメンションされています。関連する詳細があるかもしれません。
30 |
31 | %{post_url}
32 | issue_template: |
33 | この課題は **%{title}** でメンションされています。関連する詳細があるかもしれません。
34 |
35 | %{post_url}
36 | github_commits_populator:
37 | errors:
38 | repository_identifier_invalid_pm_title: "discourse-github プラグインにアクションが必要です"
39 | repository_identifier_invalid_pm: |
40 | discourse-github プラグインに指定されたリポジトリは無効です:
41 | %{repo_name}
42 |
43 | `user/repo` の形式で指定されている必要があります。
44 |
45 | この名前が
46 | discourse-github のサイト設定で修正され、"github_badges_enabled" がもう一度オンになるまで、バッジは授与されません。
47 | repository_not_found_pm_title: "discourse-github プラグインにアクションが必要です"
48 | repository_not_found_pm: |
49 | discourse-github プラグインに指定されたリポジトリから "見つかりません"
50 | エラーが返されました: %{repo_name}
51 |
52 | この名前が
53 | discourse-github のサイト設定で修正され、"github_badges_enabled" がもう一度オンになるまで、バッジは授与されません。
54 | invalid_octokit_credentials_pm_title: "discourse-github プラグインにアクションが必要です"
55 | invalid_octokit_credentials_pm: |
56 | discourse-github プラグインに指定された GitHub 資格情報は無効です。"github badges enabled\ サイト設定が無効になっているため、この問題が解決するまでコミットは表示されません。
57 |
58 | discourse-github サイト設定から "GitHub バックリンクアクセストークン" サイト設定を確認し、トークンが正しく、すべてのリポジトリへの権限が付与されていることを確認してください。
59 |
--------------------------------------------------------------------------------
/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 | enable_discourse_github_plugin: "Discourse-Github-plug-in inschakelen"
10 | github_linkback_enabled: "GitHub-problemen teruglinken naar forumdiscussies"
11 | github_linkback_projects: "Lijst van projecten om van terug te linken"
12 | github_linkback_access_token: 'Een geldig toegangstoken voor de gebruiker die de teruglink plaatst en voor het tellen van commits/bijdragen om badges toe te kennen. Zie hier voor instructies voor het verkrijgen van een token.'
13 | github_linkback_maximum_links: "Maximaal aantal teruglinks om te maken vanuit één enkele post. Als een bericht meer links bevat, wordt er geen gemaakt."
14 | github_permalinks_enabled: "Overschrijven van GitHub-permalink inschakelen"
15 | github_permalinks_exclude: "Bestandsnaam of map die moet worden uitgesloten van permalinkoverschrijvingen. Geef alleen de bestandsnaam of het volledige pad op: gebruiker/repository/optionele-directory/bestandsnaam"
16 | github_badges_enabled: "GitHub-badges inschakelen"
17 | github_badges_repos: "URL's van de GitHub-repository's om te scannen op bijdragen en commits"
18 | github_silver_badge_min_commits: "Minimaal aantal commits voor zilveren badge"
19 | github_gold_badge_min_commits: "Minimaal aantal commits voor gouden badge"
20 | errors:
21 | invalid_badge_repo: "Je moet een GitHub-URL of de repositorynaam opgeven in de vorm githubgebruiker/repositorynaam"
22 | invalid_github_linkback_access_token: "Je moet een geldig GitHub-linkbackaccesstoken opgeven dat toegang heeft tot de door jou opgegeven badgerepository's."
23 | github_linkback:
24 | commit_template: |
25 | Deze commit is vermeld op **%{title}**. Er kunnen relevante details zijn:
26 |
27 | %{post_url}
28 | pr_template: |
29 | Dit pullverzoek is vermeld op **%{title}**. Er kunnen relevante details zijn:
30 |
31 | %{post_url}
32 | issue_template: |
33 | Dit probleem is vermeld op **%{title}**. Er kunnen relevante details zijn:
34 |
35 | %{post_url}
36 | github_commits_populator:
37 | errors:
38 | repository_identifier_invalid_pm_title: "Actie vereist voor Discourse-Github-plug-in"
39 | repository_identifier_invalid_pm: |
40 | Een repository opgegeven in de Discourse-Github-plug-in is ongeldig:
41 | %{repo_name}
42 |
43 | Deze moet worden opgegeven als 'gebruiker/respository'.
44 |
45 | Badges worden pas toegekend als de naam is gecorrigeerd in
46 | Discourse-Github-site-instellingen
47 | en 'github_badges_enabled' weer is ingeschakeld.
48 | repository_not_found_pm_title: "Actie vereist voor Discourse-Github-plug-in"
49 | repository_not_found_pm: |
50 | Een repository opgegeven in de Discourse-Github-plug-in heeft een 'Niet gevonden'-fout
51 | geretourneerd: %{repo_name}
52 |
53 | Badges worden pas toegekend als de naam is gecorrigeerd in
54 | Discourse-Github-site-instellingen
55 | en 'github_badges_enabled' weer is ingeschakeld.
56 | invalid_octokit_credentials_pm_title: "Actie vereist voor Discourse-Github-plug-in"
57 | invalid_octokit_credentials_pm: |
58 | De GitHub-aanmeldgegevens die aan de Discourse-Github-plug-in zijn verstrekt, zijn ongeldig. De site-instelling 'github badges enabled' is uitgeschakeld en commits worden niet meer ingevuld totdat het probleem is opgelost.
59 |
60 | Controleer de site-instelling 'github linkback access token' om zeker te zijn dat het token juist is en toestemming heeft voor alle repository's via
61 | Discourse-Github-site-instellingen.
62 |
--------------------------------------------------------------------------------
/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 | enable_discourse_github_plugin: "Włącz wtyczkę discourse-github"
10 | github_linkback_enabled: "Połącz problemy z GitHub z dyskusjami na forum"
11 | github_linkback_projects: "Lista projektów do odsyłania"
12 | github_linkback_access_token: 'Ważny token dostępu dla użytkownika, który opublikuje link zwrotny oraz do liczenia commitów/wkładów w celu przyznania odznak. Zerknij tutaj, aby uzyskać instrukcje, jak zdobyć token.'
13 | github_badges_enabled: "Włącz odznaki GitHub"
14 |
--------------------------------------------------------------------------------
/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 | enable_discourse_github_plugin: "Ativar o plugin discourse-github"
10 | github_linkback_enabled: "O link do Github envia de volta para discussões do fórum"
11 | github_linkback_projects: "Lista de projetos para fazer linkback"
12 | github_linkback_access_token: 'Um token de acesso válido para o(a) usuário(a) que postar o linkback e contar confirmações/contribuições para conceder emblemas. Acesse aqui para obter instruções de como receber um token.'
13 | github_linkback_maximum_links: "Número máximo de linkbacks para criar a partir de uma única postagem. Quando uma postagem contiver mais links, nenhum será criado."
14 | github_permalinks_enabled: "Ativar substituições de permalink do GitHub"
15 | github_permalinks_exclude: "Diretório ou nome do arquivo que deve ser excluído das substituições de permalink. Informe apenas o nome do arquivo ou caminho completo: user/repository/optional-directory/filename"
16 | github_badges_enabled: "Ativar emblemas do GitHub"
17 | github_badges_repos: "URLs do repositório do GitHub para verificar contribuições e confirmações"
18 | github_silver_badge_min_commits: "Número mínimo de confirmações para emblema de prata"
19 | github_gold_badge_min_commits: "Número mínimo de confirmações para emblema de ouro"
20 | errors:
21 | invalid_badge_repo: "Você deve informar uma URL do GitHub ou o nome do repositório no formato github_user/repository_name"
22 | invalid_github_linkback_access_token: "Você deve informar um token válido de acesso ao linkback do GitHub, com acesso aos repositórios do emblema informados."
23 | github_linkback:
24 | commit_template: |
25 | A confirmação foi mencionada em **%{title}**. Pode haver detalhes importantes:
26 |
27 | %{post_url}
28 | pr_template: |
29 | O pedido de recebimento foi mencionado em **%{title}**. Pode haver detalhes importantes:
30 |
31 | %{post_url}
32 | issue_template: |
33 | Este problema foi mencionado em **%{title}**. Pode haver detalhes importantes:
34 |
35 | %{post_url}
36 | github_commits_populator:
37 | errors:
38 | repository_identifier_invalid_pm_title: "Ação necessária para o plugin discourse-github"
39 | repository_identifier_invalid_pm: |
40 | Um repositório especificado no plugin discourse-github não é válido:
41 | %{repo_name}
42 |
43 | Deve ser especificado como "user/repo".
44 |
45 | Emblemas não serão concedidos até que o nome seja corrigido
46 | Configurações do site do discourse-github
47 | e "github_badges_enabled" seja reativado.
48 | repository_not_found_pm_title: "Ação necessária para o plugin discourse-github"
49 | repository_not_found_pm: |
50 | Um repositório especificado no plugin discourse-github retornou um "Não encontrado"
51 | %{repo_name}
52 |
53 | Emblemas não serão concedidos até que o nome seja corrigido
54 | Configurações do site do discourse-github
55 | e "github_badges_enabled" seja reativado.
56 | invalid_octokit_credentials_pm_title: "Ação necessária para o plugin discourse-github"
57 | invalid_octokit_credentials_pm: |
58 | As credenciais do GitHub informadas ao plugin discourse-github não são válidas. A configuração "github badges enabled\site"
59 | foi desativada, e as confirmações não serão mais preenchidas até que o problema seja solucionado.
60 |
61 | Confira a configuração do site "github linkback access token" para garantir que o token está correto e tem permissão para todos os respositórios via
62 | discourse-github Site Settings.
63 |
--------------------------------------------------------------------------------
/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 | enable_discourse_github_plugin: "Включить плагин discourse-github"
10 | github_linkback_enabled: "Связать тикеты GitHub с обсуждениями на форуме"
11 | github_linkback_projects: "Список проектов, на которые можно ссылаться"
12 | github_linkback_access_token: 'Действующий токен доступа для пользователя, который будет размещать обратную ссылку и для подсчёта коммитов/вкладов при присвоении наград. Получение токена описано в этой теме.'
13 | github_linkback_maximum_links: "Максимальное количество обратных ссылок, создаваемых из одного сообщения. Если сообщение содержит больше ссылок - ни одна не создается."
14 | github_permalinks_enabled: "Включить перезапись постоянных ссылок GitHub"
15 | github_permalinks_exclude: "Имя файла или каталога, которые следует исключить из перезаписи постоянных ссылок. Укажите только имя файла или полный путь: пользователь/репозиторий/необязательный каталог/имя файла"
16 | github_badges_enabled: "Включить награды GitHub"
17 | github_badges_repos: "URL-адреса репозиториев GitHub для проверки вкладов и коммитов"
18 | github_silver_badge_min_commits: "Минимальное количество коммитов для получения серебряного значка"
19 | github_gold_badge_min_commits: "Минимальное количество коммитов для получения золотого значка"
20 | errors:
21 | invalid_badge_repo: "Вы должны предоставить URL GitHub или имя репозитория в формате 'github_пользователь/название_репозитория'"
22 | invalid_github_linkback_access_token: "Необходимо указать действующий токен доступа к GitHub Linkback, который имеет доступ к указанным вами репозиториям с наградами."
23 | github_linkback:
24 | commit_template: |
25 | Этот коммит был упомянут в **%{title}**. Там могут быть соответствующие подробности:
26 |
27 | %{post_url}
28 | pr_template: |
29 | Этот запрос на слияние был упомянут в **%{title}**. Там могут быть соответствующие подробности:
30 |
31 | %{post_url}
32 | issue_template: |
33 | Эта проблема была упомянута в **%{title}**. Там могут быть соответствующие подробности:
34 |
35 | %{post_url}
36 | github_commits_populator:
37 | errors:
38 | repository_identifier_invalid_pm_title: "Плагин «discourse-github» требует принятия мер"
39 | repository_identifier_invalid_pm: |
40 | Репозиторий, указанный в плагине «discourse-github», недействителен:
41 | %{repo_name}
42 |
43 | Он должен быть указан как `пользователь/репозиторий`.
44 |
45 | Награды не будут выдаваться до тех пор, пока название не будет исправлено в
46 | настройках «discourse-github»
47 | и параметр «github_badges_enabled» не будет снова включён.
48 | repository_not_found_pm_title: "Плагин «discourse-github» требует принятия мер"
49 | repository_not_found_pm: |
50 | Репозиторий, указанный в плагине discourse-github, выдаёт ошибку «Не найдено»: %{repo_name}
51 |
52 | Награды не будут выдаваться до тех пор, пока название не будет исправлено в
53 | настройках «discourse-github»
54 | и параметр «github_badges_enabled» не будет снова включён.
55 | invalid_octokit_credentials_pm_title: "Плагин «discourse-github» требует принятия мер"
56 | invalid_octokit_credentials_pm: |
57 | Учётные данные GitHub, предоставленные плагину «discourse-github», недействительны. Награды Github отключены, коммиты не будут заполняться, пока проблема не будет решена.
58 |
59 | Проверьте настройку токена доступа Github Linkback: токен должен быть действителен и должен иметь право доступа ко всем
60 | репозиториям — см.
61 | настройки «discourse-github».
62 |
--------------------------------------------------------------------------------
/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 | enable_discourse_github_plugin: "Aktivera insticksprogrammet Discourse-github"
10 | github_linkback_enabled: "Länka GitHub-ärenden tillbaka till forumdiskussioner"
11 | github_linkback_projects: "Lista över projekt att länka tillbaka från"
12 | github_linkback_access_token: 'En giltig åtkomsttoken för användaren som lägger upp återlänken samt för att räkna åtaganden/bidrag för att ge märken. Se här för instruktioner om hur du skaffar en token.'
13 | github_linkback_maximum_links: "Maximalt antal återlänkar att skapa från ett enda inlägg. När ett inlägg innehåller fler länkar skapas inga."
14 | github_permalinks_enabled: "Aktivera överskrivning av GitHub-permalänk"
15 | github_permalinks_exclude: "Filnamn eller katalog som bör uteslutas från permalänksöverskrivningar. Ange endast filnamn eller fullständig sökväg: user/repository/optional-directory/filname"
16 | github_badges_enabled: "Aktivera GitHub-märken"
17 | github_badges_repos: "Webbadresser till GitHub-depåer för att söka efter bidrag och åtaganden"
18 | github_silver_badge_min_commits: "Minsta antal åtaganden för silvermärke"
19 | github_gold_badge_min_commits: "Minsta antal åtaganden för guldmärke"
20 | errors:
21 | invalid_badge_repo: "Du måste ange en GitHub-URL eller databasnamnet i formatet github_user/repository_name"
22 | invalid_github_linkback_access_token: "Du måste ange en giltig GitHub återkopplingsbehörighetstoken som har åtkomst till de märkesdatabaser som du har angett."
23 | github_linkback:
24 | commit_template: |
25 | Detta åtagande har nämnts i **%{title}**. Det kan finnas relevanta detaljer där:
26 |
27 | %{post_url}
28 | pr_template: |
29 | Denna dragbegäran har nämnts i **%{title}**. Det kan finnas relevanta detaljer där:
30 |
31 | %{post_url}
32 | issue_template: |
33 | Detta ärende har nämnts i **%{title}**. Det kan finnas relevanta detaljer där:
34 |
35 | %{post_url}
36 | github_commits_populator:
37 | errors:
38 | repository_identifier_invalid_pm_title: "Åtgärd krävs för insticksprogrammet discourse-github"
39 | repository_identifier_invalid_pm: |
40 | En databas som anges i insticksprogrammet Discourse-github är ogiltig:
41 | %{repo_name}
42 |
43 | De bör anges som `user/repo`.
44 |
45 | Märken tilldelas inte förrän namnet har korrigerats i
46 | discourse-github webbplatsinställningar
47 | och ”github_badges_enabled” är aktiverat igen.
48 | repository_not_found_pm_title: "Åtgärd krävs för insticksprogrammet discourse-github"
49 | repository_not_found_pm: |
50 | En databas som anges i insticksprogrammet Discourse-github returnerade felet ”Hittas inte”
51 | : %{repo_name}
52 |
53 | Märken kommer inte att tilldelas förrän namnet har korrigerats i
54 | discourse-github webbplatsinställningar
55 | och ”github_badges_enabled” är aktiverat igen.
56 | invalid_octokit_credentials_pm_title: "Åtgärd krävs för insticksprogrammet discourse-github"
57 | invalid_octokit_credentials_pm: |
58 | GitHubs autentiseringsuppgifter som angivits till insticksprogrammet discourse-github är ogiltiga. Inställningen ”github märken aktiverad"
59 | har inaktiverats, och åtaganden kommer inte längre att fyllas i förrän problemet är löst.
60 |
61 | Kontrollera inställningen ”github linkback access token” för att säkerställa att token är korrekt och har behörighet till alla
62 | depåer via
63 | discourse-github webbplatsinställningar.
64 |
--------------------------------------------------------------------------------
/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 | enable_discourse_github_plugin: "discourse-github eklentisini etkinleştirin"
10 | github_linkback_enabled: "GitHub sorunlarını forum tartışmalarına geri bağlayın"
11 | github_linkback_projects: "Geri bağlantı kurulacak projelerin listesi"
12 | github_linkback_access_token: 'Geri bağlantıyı gönderecek kullanıcı için ve rozet vermek üzere taahhütleri/katkıları saymak için geçerli bir erişim token''ı. Nasıl token alınacağına ilişkin talimatlar için burayı inceleyin.'
13 | github_linkback_maximum_links: "Tek bir gönderiden oluşturulacak maksimum geri bağlantı sayısı. Bir gönderi daha fazla bağlantı içeriyorsa hiçbiri oluşturulmaz."
14 | github_permalinks_enabled: "GitHub kalıcı bağlantılarının üzerine yazmayı etkinleştirin"
15 | github_permalinks_exclude: "Kalıcı bağlantı üzerine yazma işlemlerinin dışında bırakılması gereken dosya adı veya dizin. Yalnızca dosya adı veya tam yol sağlayın: kullanıcı/havuz/isteğe bağlı dizin/dosya adı"
16 | github_badges_enabled: "GitHub rozetlerini etkinleştirin"
17 | github_badges_repos: "Katkılar ve taahhütler için taranacak GitHub depolarının URL'leri"
18 | github_silver_badge_min_commits: "Gümüş rozet için minimum taahhüt sayısı"
19 | github_gold_badge_min_commits: "Altın rozet için minimum taahhüt sayısı"
20 | errors:
21 | invalid_badge_repo: "Bir GitHub URL'si veya depo adını github_user/repository_name biçiminde sağlamalısınız"
22 | invalid_github_linkback_access_token: "Sağladığınız rozet depolarına erişimi olan geçerli bir GitHub linkback erişim token'ı sağlamalısınız."
23 | github_linkback:
24 | commit_template: |
25 | Bu taahhütten **%{title}** başlığında bahsedildi. Orada ilgili ayrıntılar olabilir:
26 |
27 | %{post_url}
28 | pr_template: |
29 | Bu çekme talebinden **%{title}** başlığında bahsedildi. Orada ilgili ayrıntılar olabilir:
30 |
31 | %{post_url}
32 | issue_template: |
33 | Bu sorundan **%{title}** başlığında bahsedildi. Orada ilgili ayrıntılar olabilir:
34 |
35 | %{post_url}
36 | github_commits_populator:
37 | errors:
38 | repository_identifier_invalid_pm_title: "discourse-github eklentisi için eylem gerekli"
39 | repository_identifier_invalid_pm: |
40 | discourse-github eklentisinde belirtilen bir depo geçersiz:
41 | %{repo_name}
42 |
43 | "user/repo" olarak belirtilmeliler.
44 |
45 | İsim
46 | discourse-github Site Ayarları
47 | adresinde düzeltilene ve "github_badges_enabled" tekrar açılana kadar rozet verilmeyecek.
48 | repository_not_found_pm_title: "discourse-github eklentisi için eylem gerekli"
49 | repository_not_found_pm: |
50 | discourse-github eklentisinde belirtilen bir depo "Bulunamadı"
51 | hatası döndürdü: %{repo_name}
52 |
53 | İsim
54 | discourse-github Site Ayarları
55 | içinde düzeltilene ve "github_badges_enabled" tekrar açılana kadar rozet verilmeyecek.
56 | invalid_octokit_credentials_pm_title: "discourse-github eklentisi için eylem gerekli"
57 | invalid_octokit_credentials_pm: |
58 | discourse-github eklentisine eklenen GitHub kimlik bilgileri geçersiz. "github rozetleri etkin\ site
59 | ayarı devre dışı ve sorun çözülene kadar taahhütler doldurulmayacak.
60 |
61 | Belirtecin doğru olduğundan ve
62 | discourse-github Site Ayarları aracılığıyla tüm
63 | depolara izne sahip olduğundan emin olmak için "github geri bağlantı erişim token'ı" site ayarınızı kontrol edin.
64 |
--------------------------------------------------------------------------------
/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 | enable_discourse_github_plugin: "启用 discourse-github 插件"
10 | github_linkback_enabled: "将 GitHub 议题链接回论坛讨论"
11 | github_linkback_projects: "待链接回的项目列表"
12 | github_linkback_access_token: '一个有效访问令牌,用于将发布反向链接的用户以及计算提交/贡献以授予徽章。有关如何获取令牌的说明,请参阅此处。'
13 | github_linkback_maximum_links: "从单个帖子创建的最大反向链接数。当帖子包含更多链接时,将不会创建任何链接。"
14 | github_permalinks_enabled: "启用 GitHub 永久链接覆盖"
15 | github_permalinks_exclude: "应从永久链接覆盖中排除的文件名或目录。仅提供文件名或完整路径:user/repository/optional-directory/filename"
16 | github_badges_enabled: "启用 GitHub 徽章"
17 | github_badges_repos: "用于扫描贡献和提交的 GitHub 仓库的 URL"
18 | github_silver_badge_min_commits: "白银徽章的最低提交次数"
19 | github_gold_badge_min_commits: "黄金徽章的最低提交次数"
20 | errors:
21 | invalid_badge_repo: "您必须提供 GitHub URL 或格式为 github_user/repository_name 的仓库名称"
22 | invalid_github_linkback_access_token: "您必须提供有效的 GitHub 反向链接访问令牌,该令牌应该可以访问您提供的徽章仓库。"
23 | github_linkback:
24 | commit_template: |
25 | 此提交已在 **%{title}** 上被提及。那里可能有相关详细信息:
26 |
27 | %{post_url}
28 | pr_template: |
29 | 此拉取请求已在 **%{title}** 上被提及。那里可能有相关详细信息:
30 |
31 | %{post_url}
32 | issue_template: |
33 | 此问题已在 **%{title}** 上被提及。那里可能有相关详细信息:
34 |
35 | %{post_url}
36 | github_commits_populator:
37 | errors:
38 | repository_identifier_invalid_pm_title: "discourse-github 插件所需操作"
39 | repository_identifier_invalid_pm: |
40 | discourse-github 插件中指定的仓库无效:
41 | %{repo_name}
42 |
43 | 它们应该被指定为 `user/repo`。
44 |
45 | 除非在 discourse-github 站点设置中更正名称并重新打开“github_badges_enabled”,否则不会授予徽章。
46 | repository_not_found_pm_title: "discourse-github 插件所需操作"
47 | repository_not_found_pm: |
48 | discourse-github 插件中指定的仓库返回了“找不到”错误:%{repo_name}
49 |
50 | 除非在 discourse-github 站点设置中更正名称并重新打开“github_badges_enabled”,否则不会授予徽章。
51 | invalid_octokit_credentials_pm_title: "discourse-github 插件所需操作"
52 | invalid_octokit_credentials_pm: |
53 | 提供给 discourse-github 插件的 GitHub 凭据无效。“github badges enabled”站点设置已被禁用,并且在议题解决之前将不会填充提交。
54 |
55 | 检查您的“github 反向链接访问令牌”站点设置,确保令牌正确并通过 discourse-github 站点设置获得对所有仓库的权限。
56 |
--------------------------------------------------------------------------------
/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_github:
2 | enable_discourse_github_plugin: true
3 | github_linkback_enabled:
4 | default: false
5 | github_linkback_projects:
6 | default: ""
7 | type: list
8 | github_linkback_access_token:
9 | default: ""
10 | secret: true
11 | validator: "GithubLinkbackAccessTokenSettingValidator"
12 | github_linkback_maximum_links:
13 | default: 25
14 | min: 1
15 | github_badges_enabled:
16 | default: false
17 | github_badges_repos:
18 | default: ""
19 | type: list
20 | validator: "GithubBadgesRepoSettingValidator"
21 | github_permalinks_enabled:
22 | default: false
23 | github_permalinks_exclude:
24 | default: "README.md"
25 | type: list
26 | github_silver_badge_min_commits:
27 | default: 25
28 | min: 1
29 | github_gold_badge_min_commits:
30 | default: 250
31 | min: 1
32 |
--------------------------------------------------------------------------------
/db/migrate/20190617035051_rename_site_setting_github_badges_repo.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class RenameSiteSettingGithubBadgesRepo < ActiveRecord::Migration[5.2]
4 | def up
5 | execute(<<~SQL)
6 | UPDATE site_settings SET name = 'github_badges_repos', data_type = 8 WHERE name = 'github_badges_repo' AND data_type = 1
7 | SQL
8 | end
9 |
10 | def down
11 | execute(<<~SQL)
12 | UPDATE site_settings SET name = 'github_badges_repo', data_type = 1 WHERE name = 'github_badges_repos' AND data_type = 8
13 | SQL
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/db/migrate/20190618174229_create_github_repos.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CreateGithubRepos < ActiveRecord::Migration[5.2]
4 | def change
5 | create_table :github_repos do |t|
6 | t.string :name, null: false, limit: 255
7 | t.timestamps null: false
8 | end
9 | add_index :github_repos, :name, unique: true
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20190618183340_create_github_commits.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CreateGithubCommits < ActiveRecord::Migration[5.2]
4 | def change
5 | create_table :github_commits do |t|
6 | t.references :repo, null: false # rubocop:disable Discourse/NoAddReferenceOrAliasesActiveRecordMigration
7 | t.string :sha, limit: 40, null: false
8 | t.string :email, limit: 513, null: false
9 | t.timestamp :committed_at, null: false
10 | t.integer :role_id, null: false
11 | t.boolean :merge_commit, null: false, default: false
12 | t.timestamps null: false
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/db/migrate/20201210032852_discourse_github_rebuild_git_history.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class DiscourseGithubRebuildGitHistory < ActiveRecord::Migration[6.0]
4 | def up
5 | # the table will be repopulated the next time the `UpdateJob` runs.
6 | # This will not have any noticeable effects on the site because
7 | # this table is merely used to grant the committer and contributor
8 | # badges. Deleting commits will not cause users to lose badges.
9 | execute "DELETE FROM github_commits"
10 | end
11 |
12 | def down
13 | raise ActiveRecord::IrreversibleMigration
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/db/migrate/20230227050148_update_github_badge_icons.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class UpdateGithubBadgeIcons < ActiveRecord::Migration[7.0]
4 | def change
5 | badges = [
6 | DiscourseGithubPlugin::GithubBadges::BADGE_NAME_BRONZE,
7 | DiscourseGithubPlugin::GithubBadges::BADGE_NAME_SILVER,
8 | DiscourseGithubPlugin::GithubBadges::BADGE_NAME_GOLD,
9 | DiscourseGithubPlugin::GithubBadges::COMMITTER_BADGE_NAME_BRONZE,
10 | DiscourseGithubPlugin::GithubBadges::COMMITTER_BADGE_NAME_SILVER,
11 | DiscourseGithubPlugin::GithubBadges::COMMITTER_BADGE_NAME_GOLD,
12 | ]
13 | execute <<~SQL
14 | UPDATE badges
15 | SET icon = 'fab-git-alt'
16 | WHERE
17 | name IN (#{badges.map { |b| "'#{b}'" }.join(",")})
18 | AND icon = 'fa-certificate'
19 | SQL
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import DiscourseRecommended from "@discourse/lint-configs/eslint";
2 |
3 | export default [...DiscourseRecommended];
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "devDependencies": {
4 | "@discourse/lint-configs": "2.21.0",
5 | "ember-template-lint": "7.7.0",
6 | "eslint": "9.27.0",
7 | "prettier": "3.5.3",
8 | "stylelint": "16.19.1"
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 |
--------------------------------------------------------------------------------
/plugin.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # name: discourse-github
4 | # about: Allows staff to assign badges to users based on GitHub contributions, and allows users to create Github Linkbacks and Permalinks
5 | # meta_topic_id: 99895
6 | # version: 0.3
7 | # authors: Robin Ward, Sam Saffron
8 | # url: https://github.com/discourse/discourse-github
9 |
10 | gem "sawyer", "0.9.2"
11 | gem "octokit", "5.6.1"
12 |
13 | # Site setting validators must be loaded before initialize
14 | require_relative "app/lib/github_badges_repo_setting_validator.rb"
15 | require_relative "app/lib/github_linkback_access_token_setting_validator.rb"
16 |
17 | enabled_site_setting :enable_discourse_github_plugin
18 |
19 | after_initialize do
20 | %w[
21 | ../app/models/github_commit.rb
22 | ../app/models/github_repo.rb
23 | ../app/lib/github_linkback.rb
24 | ../app/lib/github_badges.rb
25 | ../app/lib/github_permalinks.rb
26 | ../app/lib/commits_populator.rb
27 | ../app/jobs/regular/create_github_linkback.rb
28 | ../app/jobs/scheduled/grant_github_badges.rb
29 | ../app/jobs/regular/replace_github_non_permalinks.rb
30 | ].each { |path| require File.expand_path(path, __FILE__) }
31 |
32 | on(:post_created) do |post|
33 | if SiteSetting.github_linkback_enabled? && SiteSetting.enable_discourse_github_plugin?
34 | GithubLinkback.new(post).enqueue
35 | end
36 | end
37 |
38 | on(:post_edited) do |post|
39 | if SiteSetting.github_linkback_enabled? && SiteSetting.enable_discourse_github_plugin?
40 | GithubLinkback.new(post).enqueue
41 | end
42 | end
43 |
44 | on(:before_post_process_cooked) do |doc, post|
45 | if SiteSetting.github_permalinks_enabled? && SiteSetting.enable_discourse_github_plugin?
46 | GithubPermalinks.replace_github_non_permalinks(post)
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/spec/jobs/create_github_linkback_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "rails_helper"
4 |
5 | describe Jobs::CreateGithubLinkback do
6 | before { SiteSetting.github_linkback_enabled = true }
7 |
8 | it "shouldn't raise error if post not found" do
9 | post = Fabricate(:post)
10 | post.destroy!
11 | expect { Jobs::CreateGithubLinkback.new.execute(post_id: post.id) }.not_to raise_error
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/spec/jobs/replace_github_non_permalinks_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "rails_helper"
4 |
5 | describe Jobs::ReplaceGithubNonPermalinks do
6 | let(:job) { described_class.new }
7 | let(:github_url) do
8 | "https://github.com/test/onebox/blob/master/lib/onebox/engine/github_blob_onebox.rb"
9 | end
10 | let(:github_permanent_url) do
11 | "https://github.com/test/onebox/blob/815ea9c0a8ffebe7bd7fcd34c10ff28c7a6b6974/lib/onebox/engine/github_blob_onebox.rb"
12 | end
13 | let(:github_url2) { "https://github.com/test/discourse/blob/master/app/models/tag.rb#L1-L3" }
14 | let(:github_permanent_url2) do
15 | "https://github.com/test/discourse/blob/7e4edcfae8a3c0e664b836ee7c5f28b47853a2f8/app/models/tag.rb#L1-L3"
16 | end
17 | let(:broken_github_url) do
18 | "https://github.com/test/oneblob/blob/master/lib/onebox/engine/nonexistent.rb"
19 | end
20 | let(:github_response_body) { { sha: "815ea9c0a8ffebe7bd7fcd34c10ff28c7a6b6974", commit: {} } }
21 | let(:github_response_body2) { { sha: "7e4edcfae8a3c0e664b836ee7c5f28b47853a2f8", commit: {} } }
22 |
23 | before do
24 | stub_request(:get, "https://api.github.com/repos/test/onebox/commits/master").to_return(
25 | status: 200,
26 | body: github_response_body.to_json,
27 | headers: {
28 | },
29 | )
30 | stub_request(
31 | :get,
32 | "https://api.github.com/repos/test/onebox/commits/815ea9c0a8ffebe7bd7fcd34c10ff28c7a6b6974",
33 | ).to_return(status: 200, body: github_response_body.to_json, headers: {})
34 | stub_request(:get, "https://api.github.com/repos/test/oneblob/commits/master").to_return(
35 | status: 404,
36 | )
37 | stub_request(:get, "https://api.github.com/repos/test/discourse/commits/master").to_return(
38 | status: 200,
39 | body: github_response_body2.to_json,
40 | headers: {
41 | },
42 | )
43 | end
44 |
45 | describe "#execute" do
46 | before do
47 | Jobs.run_immediately!
48 | SiteSetting.github_permalinks_enabled = true
49 | end
50 |
51 | it "replaces link with permanent link" do
52 | stub_request(:head, github_permanent_url).to_return(status: 200, body: "", headers: {})
53 | stub_request(
54 | :get,
55 | "https://raw.githubusercontent.com/test/onebox/815ea9c0a8ffebe7bd7fcd34c10ff28c7a6b6974/lib/onebox/engine/github_blob_onebox.rb",
56 | ).to_return(status: 200, body: "", headers: {})
57 |
58 | post = Fabricate(:post, raw: github_url)
59 | job.execute(post_id: post.id)
60 | post.reload
61 |
62 | expect(post.raw).to eq(github_permanent_url)
63 | end
64 |
65 | it "doesn't replace the link if it's already permanent" do
66 | post = Fabricate(:post, raw: github_permanent_url)
67 | job.execute(post_id: post.id)
68 | post.reload
69 |
70 | expect(post.raw).to eq(github_permanent_url)
71 | end
72 |
73 | it "doesn't change the post if link is broken" do
74 | post = Fabricate(:post, raw: broken_github_url)
75 | job.execute(post_id: post.id)
76 | post.reload
77 |
78 | expect(post.raw).to eq(broken_github_url)
79 | end
80 |
81 | it "works with multiple github urls in the post" do
82 | stub_request(:get, github_permanent_url).to_return(status: 200, body: "")
83 | stub_request(:get, github_permanent_url2.gsub(/#.+$/, "")).to_return(status: 200, body: "")
84 | post = Fabricate(:post, raw: "#{github_url} #{github_url2} htts://github.com")
85 | job.execute(post_id: post.id)
86 | post.reload
87 |
88 | updated_post = "#{github_permanent_url} #{github_permanent_url2} htts://github.com"
89 | expect(post.raw).to eq(updated_post)
90 | end
91 | end
92 |
93 | describe "#excluded?" do
94 | before do
95 | SiteSetting.github_permalinks_exclude =
96 | "README.md|discourse/discourse/directory/file.rb|discourse/onebox/docs/*|discourse/anotherRepo/*|someUser/*"
97 | end
98 |
99 | it "returns true when it should be excluded" do
100 | expect(job.excluded?("discourse", "discourse", "README.md")).to be true
101 | expect(job.excluded?("discourse", "discourse", "directory/file.rb")).to be true
102 | expect(job.excluded?("discourse", "onebox", "docs/file.rb")).to be true
103 | expect(job.excluded?("discourse", "anotherRepo", "directory/file.rb")).to be true
104 | expect(job.excluded?("someUser", "someRepo", "file.rb")).to be true
105 | end
106 |
107 | it "return false when url should be replaced" do
108 | expect(job.excluded?("discourse", "discourse", "directory/file2.rb")).to be false
109 | expect(job.excluded?("discourse", "onebox", "directory/file.rb")).to be false
110 | expect(job.excluded?("discourse", "discourse", "directory/included.rb")).to be false
111 | end
112 | end
113 | end
114 |
--------------------------------------------------------------------------------
/spec/lib/commits_populator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "rails_helper"
4 |
5 | describe DiscourseGithubPlugin::CommitsPopulator do
6 | subject(:populator) { described_class.new(repo) }
7 |
8 | let(:repo) { DiscourseGithubPlugin::GithubRepo.new(name: "discourse/discourse") }
9 | let!(:site_admin1) { Fabricate(:admin) }
10 | let!(:site_admin2) { Fabricate(:admin) }
11 |
12 | before { SiteSetting.github_badges_enabled = true }
13 |
14 | context "when invalid credentials have been provided for octokit" do
15 | before { Octokit::Client.any_instance.expects(:branches).raises(Octokit::Unauthorized) }
16 |
17 | it "disables github badges and sends a PM to the admin of the site to inform them" do
18 | populator.populate!
19 | expect(SiteSetting.github_badges_enabled).to eq(false)
20 | sent_pm =
21 | Post
22 | .joins(:topic)
23 | .includes(:topic)
24 | .where("topics.archetype = ?", Archetype.private_message)
25 | .last
26 | expect(sent_pm.topic.allowed_users.include?(site_admin1)).to eq(true)
27 | expect(sent_pm.topic.allowed_users.include?(site_admin2)).to eq(true)
28 | expect(sent_pm.topic.title).to eq(
29 | I18n.t("github_commits_populator.errors.invalid_octokit_credentials_pm_title"),
30 | )
31 | expect(sent_pm.raw).to eq(
32 | I18n.t(
33 | "github_commits_populator.errors.invalid_octokit_credentials_pm",
34 | base_path: Discourse.base_path,
35 | ).strip,
36 | )
37 | end
38 | end
39 |
40 | context "when the repository is not found" do
41 | before { Octokit::Client.any_instance.expects(:branches).raises(Octokit::NotFound) }
42 |
43 | it "disables github badges and sends a PM to the admin of the site to inform them" do
44 | populator.populate!
45 | expect(SiteSetting.github_badges_enabled).to eq(false)
46 | sent_pm =
47 | Post
48 | .joins(:topic)
49 | .includes(:topic)
50 | .where("topics.archetype = ?", Archetype.private_message)
51 | .last
52 | expect(sent_pm.topic.allowed_users.include?(site_admin1)).to eq(true)
53 | expect(sent_pm.topic.allowed_users.include?(site_admin2)).to eq(true)
54 | expect(sent_pm.topic.title).to eq(
55 | I18n.t("github_commits_populator.errors.repository_not_found_pm_title"),
56 | )
57 | expect(sent_pm.raw).to eq(
58 | I18n.t(
59 | "github_commits_populator.errors.repository_not_found_pm",
60 | repo_name: repo.name,
61 | base_path: Discourse.base_path,
62 | ).strip,
63 | )
64 | end
65 | end
66 |
67 | context "when the repository identifier is invalid" do
68 | before { Octokit::Client.any_instance.expects(:branches).raises(Octokit::InvalidRepository) }
69 |
70 | it "disables github badges and sends a PM to the admin of the site to inform them" do
71 | populator.populate!
72 | expect(SiteSetting.github_badges_enabled).to eq(false)
73 | sent_pm =
74 | Post
75 | .joins(:topic)
76 | .includes(:topic)
77 | .where("topics.archetype = ?", Archetype.private_message)
78 | .last
79 | expect(sent_pm.topic.allowed_users.include?(site_admin1)).to eq(true)
80 | expect(sent_pm.topic.allowed_users.include?(site_admin2)).to eq(true)
81 | expect(sent_pm.topic.title).to eq(
82 | I18n.t("github_commits_populator.errors.repository_identifier_invalid_pm_title"),
83 | )
84 | expect(sent_pm.raw).to eq(
85 | I18n.t(
86 | "github_commits_populator.errors.repository_identifier_invalid_pm",
87 | repo_name: repo.name,
88 | base_path: Discourse.base_path,
89 | ).strip,
90 | )
91 | end
92 | end
93 |
94 | context "if some other octokit error is raised" do
95 | before { Octokit::Client.any_instance.expects(:branches).raises(Octokit::Error) }
96 |
97 | it "simply logs the error and does nothing else" do
98 | populator.populate!
99 | expect(SiteSetting.github_badges_enabled).to eq(true)
100 | end
101 | end
102 |
103 | context "if GraphQL returns no data" do
104 | before do
105 | branches_body = <<~JSON
106 | [
107 | {
108 | "name": "add-group-css-properties",
109 | "commit": {
110 | "sha": "0d67b6307042803c351599de715023841cfa9356",
111 | "url": "https://api.github.com/repos/discourse/discourse/commits/0d67b6307042803c351599de715023841cfa9356"
112 | },
113 | "protected": false
114 | }
115 | ]
116 | JSON
117 |
118 | graphql_response = <<~JSON
119 | {
120 | "message": "Bad credentials",
121 | "documentation_url": "https://docs.github.com/graphql"
122 | }
123 | JSON
124 |
125 | stub_request(
126 | :get,
127 | "https://api.github.com/repos/discourse/discourse/branches?per_page=100",
128 | ).to_return(status: 200, body: branches_body)
129 | stub_request(:post, "https://api.github.com/graphql").to_return(
130 | status: 200,
131 | body: graphql_response,
132 | headers: {
133 | "content-type": "application/json",
134 | },
135 | )
136 | end
137 |
138 | it "simply logs the error and does nothing else" do
139 | expect { populator.populate! }.to raise_error(described_class::GraphQLError)
140 | end
141 | end
142 |
143 | context "if github_badges_enabled is false" do
144 | before { SiteSetting.github_badges_enabled = false }
145 |
146 | it "early returns before attempting to execute any of the commit fetching, because the plugin likely disabled itself" do
147 | Octokit::Client.any_instance.expects(:branches).never
148 | populator.populate!
149 | end
150 | end
151 | end
152 |
--------------------------------------------------------------------------------
/spec/lib/github_badges_repo_setting_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "rails_helper"
4 |
5 | describe GithubBadgesRepoSettingValidator do
6 | subject(:validator) { described_class.new }
7 |
8 | describe "#valid_value?" do
9 | context "when a github URL is provided" do
10 | let(:value) { "https://github.com/discourse/discourse/" }
11 |
12 | it "is ok" do
13 | expect(validator.valid_value?(value)).to eq(true)
14 | end
15 | end
16 |
17 | context "when a github repo in the format user/repo is provided" do
18 | let(:value) { "discourse/discourse-github" }
19 |
20 | it "is ok" do
21 | expect(validator.valid_value?(value)).to eq(true)
22 | end
23 | end
24 |
25 | context "when a github repo name by itself is provided" do
26 | let(:value) { "some-repo" }
27 |
28 | it "is not ok" do
29 | expect(validator.valid_value?(value)).to eq(false)
30 | end
31 | end
32 |
33 | context "when multiple valid settings are provided" do
34 | let(:value) { "discourse/discourse-github|https://github.com/discourse/discourse/" }
35 |
36 | it "is ok" do
37 | expect(validator.valid_value?(value)).to eq(true)
38 | end
39 | end
40 |
41 | context "when multiple valid settings with one invalid setting is provided" do
42 | let(:value) { "discourse/discourse-github|https://github.com/discourse/discourse/|bad-dog" }
43 |
44 | it "is not ok" do
45 | expect(validator.valid_value?(value)).to eq(false)
46 | end
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/spec/lib/github_badges_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "rails_helper"
4 |
5 | describe DiscourseGithubPlugin::GithubBadges do
6 | let(:bronze_user) { Fabricate(:user) }
7 | let(:bronze_user_repo_2) { Fabricate(:user) }
8 | let(:silver_user) { Fabricate(:user) }
9 | let(:contributor) { Fabricate(:user) }
10 | let(:private_email_contributor) { Fabricate(:user) }
11 | let(:private_email_contributor2) { Fabricate(:user) }
12 | let(:merge_commit_user) { Fabricate(:user) }
13 | let(:staged_user) { Fabricate(:user, staged: true) }
14 |
15 | describe "committer and contributor badges" do
16 | before do
17 | roles = DiscourseGithubPlugin::CommitsPopulator::ROLES
18 | SiteSetting.github_badges_repos =
19 | "https://github.com/org/repo1.git|https://github.com/org/repo2.git"
20 | repo1 = DiscourseGithubPlugin::GithubRepo.repos.find { |repo| repo.name == "org/repo1" }
21 | repo2 = DiscourseGithubPlugin::GithubRepo.repos.find { |repo| repo.name == "org/repo2" }
22 | repo1.commits.create!(
23 | sha: "1",
24 | email: bronze_user.email,
25 | committed_at: 1.day.ago,
26 | role_id: roles[:committer],
27 | )
28 | repo1.commits.create!(
29 | sha: "2",
30 | email: merge_commit_user.email,
31 | merge_commit: true,
32 | committed_at: 1.day.ago,
33 | role_id: roles[:committer],
34 | )
35 | repo1.commits.create!(
36 | sha: "3",
37 | email: contributor.email,
38 | committed_at: 1.day.ago,
39 | role_id: roles[:contributor],
40 | )
41 | 25.times do |n|
42 | repo1.commits.create!(
43 | sha: "blah#{n}",
44 | email: silver_user.email,
45 | committed_at: 1.day.ago,
46 | role_id: roles[:committer],
47 | )
48 | end
49 | repo2.commits.create!(
50 | sha: "4",
51 | email: bronze_user_repo_2.email,
52 | committed_at: 2.day.ago,
53 | role_id: roles[:committer],
54 | )
55 |
56 | UserAssociatedAccount.create!(
57 | provider_name: "github",
58 | user_id: private_email_contributor.id,
59 | info: {
60 | nickname: "bob",
61 | },
62 | provider_uid: 100,
63 | )
64 | repo1.commits.create!(
65 | sha: "123",
66 | email: "100+bob@users.noreply.github.com",
67 | committed_at: 1.day.ago,
68 | role_id: roles[:contributor],
69 | )
70 |
71 | UserAssociatedAccount.create!(
72 | provider_name: "github",
73 | user_id: private_email_contributor2.id,
74 | info: {
75 | nickname: "joe",
76 | },
77 | provider_uid: 101,
78 | )
79 | repo1.commits.create!(
80 | sha: "124",
81 | email: "joe@users.noreply.github.com",
82 | committed_at: 1.day.ago,
83 | role_id: roles[:contributor],
84 | )
85 |
86 | repo1.commits.create!(
87 | sha: "5",
88 | email: staged_user.email,
89 | committed_at: 1.day.ago,
90 | role_id: roles[:contributor],
91 | )
92 | end
93 |
94 | it "granted correctly" do
95 | # initial run to seed badges and then enable them
96 | DiscourseGithubPlugin::GithubBadges.grant!
97 |
98 | contributor_bronze = DiscourseGithubPlugin::GithubBadges::BADGE_NAME_BRONZE
99 | committer_bronze = DiscourseGithubPlugin::GithubBadges::COMMITTER_BADGE_NAME_BRONZE
100 | committer_silver = DiscourseGithubPlugin::GithubBadges::COMMITTER_BADGE_NAME_SILVER
101 |
102 | users = [
103 | bronze_user,
104 | bronze_user_repo_2,
105 | silver_user,
106 | contributor,
107 | staged_user,
108 | private_email_contributor,
109 | private_email_contributor2,
110 | merge_commit_user,
111 | ]
112 | users.each { |u| u.badges.destroy_all }
113 |
114 | [committer_bronze, committer_silver].each do |name|
115 | Badge.find_by(name: name).update!(enabled: true)
116 | end
117 |
118 | DiscourseGithubPlugin::GithubBadges.grant!
119 | users.each(&:reload)
120 |
121 | expect(merge_commit_user.badges).to eq([])
122 | [bronze_user, bronze_user_repo_2].each_with_index do |u, ind|
123 | expect(u.badges.pluck(:name)).to eq([committer_bronze])
124 | end
125 | expect(contributor.badges.pluck(:name)).to eq([contributor_bronze])
126 | expect(private_email_contributor.badges.pluck(:name)).to eq([contributor_bronze])
127 | expect(private_email_contributor2.badges.pluck(:name)).to eq([contributor_bronze])
128 | expect(silver_user.badges.pluck(:name)).to contain_exactly(committer_bronze, committer_silver)
129 |
130 | # does not grant badges to staged users
131 | expect(staged_user.badges.first).to eq(nil)
132 | end
133 |
134 | it "does not update user title if badge is not allowed to be used as a title" do
135 | DiscourseGithubPlugin::GithubBadges.grant!
136 | silver_committer_badge =
137 | Badge.find_by(name: DiscourseGithubPlugin::GithubBadges::COMMITTER_BADGE_NAME_SILVER)
138 |
139 | silver_committer_badge.update!(enabled: true)
140 | DiscourseGithubPlugin::GithubBadges.grant!
141 | expect(silver_user.reload.title).to eq(nil)
142 |
143 | silver_committer_badge.update!(allow_title: true)
144 | DiscourseGithubPlugin::GithubBadges.grant!
145 | expect(silver_user.reload.title).to eq(silver_committer_badge.name)
146 | end
147 |
148 | it "updates existing badges" do
149 | badge = Badge.create!(name: "Great contributor", badge_type_id: 2)
150 | DiscourseGithubPlugin::GithubBadges.contributor_badges
151 |
152 | expect(badge.reload.name).to eq("Great Contributor")
153 | end
154 | end
155 | end
156 |
--------------------------------------------------------------------------------
/spec/lib/github_linkback_access_token_setting_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "rails_helper"
4 |
5 | describe GithubLinkbackAccessTokenSettingValidator do
6 | subject(:validator) { described_class.new }
7 |
8 | let(:value) { SecureRandom.hex(10) }
9 |
10 | describe "#valid_value?" do
11 | context "when an Octokit::Unauthorized error is raised, meaning the access token cannot access a repo" do
12 | before do
13 | setup_repos
14 | Octokit::Client.any_instance.expects(:branches).raises(Octokit::Unauthorized)
15 | end
16 |
17 | it "should fail" do
18 | expect(validator.valid_value?(value)).to eq(false)
19 | end
20 | end
21 |
22 | context "when no Octokit::Unauthorized error is raised" do
23 | it "should pass, without repos defined" do
24 | expect(validator.valid_value?(value)).to eq(true)
25 | end
26 |
27 | context "when there are repos defined" do
28 | before do
29 | setup_repos
30 | Octokit::Client.any_instance.expects(:branches).returns([])
31 | end
32 |
33 | it "should pass if all the repos are accessible" do
34 | expect(validator.valid_value?(value)).to eq(true)
35 | end
36 | end
37 | end
38 | end
39 |
40 | def setup_repos
41 | SiteSetting.github_badges_repos = "discourse/discourse"
42 | DiscourseGithubPlugin::GithubRepo.repos
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/spec/lib/github_linkback_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "rails_helper"
4 |
5 | describe GithubLinkback do
6 | let(:github_commit_link) do
7 | "https://github.com/discourse/discourse/commit/76981605fa10975e2e7af457e2f6a31909e0c811"
8 | end
9 | let(:github_commit_link_with_anchor) { "#{github_commit_link}#anchor" }
10 | let(:github_issue_link) { "https://github.com/discourse/discourse/issues/123" }
11 | let(:github_pr_link) { "https://github.com/discourse/discourse/pull/701" }
12 | let(:github_pr_files_link) { "https://github.com/discourse/discourse/pull/701/files" }
13 | let(:github_pr_link_wildcard) { "https://github.com/discourse/discourse-github-linkback/pull/3" }
14 |
15 | let(:post) { Fabricate(:post, raw: <<~RAW) }
16 | cool post
17 |
18 | #{github_commit_link}
19 |
20 | https://eviltrout.com/not-a-gh-link
21 |
22 | #{github_commit_link}
23 |
24 | #{github_commit_link_with_anchor}
25 |
26 | https://github.com/eviltrout/tis-100/commit/e22b23f354e3a1c31bc7ad37a6a309fd6daf18f4
27 |
28 | #{github_issue_link}
29 |
30 | #{github_pr_link}
31 |
32 | #{github_pr_files_link}
33 |
34 | i have no idea what i'm linking back to
35 |
36 | #{github_pr_link_wildcard}
37 |
38 | end_of_transmission
39 |
40 | RAW
41 |
42 | describe "#should_enqueue?" do
43 | let(:post_without_link) { Fabricate.build(:post, raw: "Hello github!") }
44 | let(:small_action_post) do
45 | Fabricate.build(
46 | :post,
47 | post_type: Post.types[:small_action],
48 | raw:
49 | "https://github.com/discourse/discourse/commit/5be9bee2307dd517c26e6ef269471aceba5d5acf",
50 | )
51 | end
52 | let(:post_with_link) do
53 | Fabricate.build(
54 | :post,
55 | raw:
56 | "https://github.com/discourse/discourse/commit/5be9bee2307dd517c26e6ef269471aceba5d5acf",
57 | )
58 | end
59 |
60 | it "returns false when the feature is disabled" do
61 | SiteSetting.github_linkback_enabled = false
62 | expect(GithubLinkback.new(post_with_link).should_enqueue?).to eq(false)
63 | end
64 |
65 | it "returns false without a post" do
66 | SiteSetting.github_linkback_enabled = true
67 | expect(GithubLinkback.new(nil).should_enqueue?).to eq(false)
68 | end
69 |
70 | it "returns false if the post is not a regular post" do
71 | SiteSetting.github_linkback_enabled = true
72 | expect(GithubLinkback.new(small_action_post).should_enqueue?).to eq(false)
73 | end
74 |
75 | it "returns false when the post doesn't have the `github.com` in it" do
76 | SiteSetting.github_linkback_enabled = true
77 | expect(GithubLinkback.new(post_without_link).should_enqueue?).to eq(false)
78 | end
79 |
80 | it "returns true when the feature is enabled" do
81 | SiteSetting.github_linkback_enabled = true
82 | expect(GithubLinkback.new(post_with_link).should_enqueue?).to eq(true)
83 | end
84 |
85 | describe "private_message" do
86 | it "doesn't enqueue private messages" do
87 | SiteSetting.github_linkback_enabled = true
88 | private_topic = Fabricate(:private_message_topic)
89 | private_post =
90 | Fabricate(
91 | :post,
92 | topic: private_topic,
93 | raw: "this post http://github.com should not enqueue",
94 | )
95 | expect(GithubLinkback.new(private_post).should_enqueue?).to eq(false)
96 | end
97 | end
98 |
99 | describe "unlisted topics" do
100 | it "doesn't enqueue unlisted topics" do
101 | SiteSetting.github_linkback_enabled = true
102 | unlisted_topic = Fabricate(:topic, visible: false)
103 | unlisted_post =
104 | Fabricate(
105 | :post,
106 | topic: unlisted_topic,
107 | raw: "this post http://github.com should not enqueue",
108 | )
109 | expect(GithubLinkback.new(unlisted_post).should_enqueue?).to eq(false)
110 | end
111 | end
112 | end
113 |
114 | describe "#github_links" do
115 | it "returns an empty array with no projects" do
116 | SiteSetting.github_linkback_projects = ""
117 | links = GithubLinkback.new(post).github_links
118 | expect(links).to eq([])
119 | end
120 |
121 | it "doesn't return links that have already been posted" do
122 | SiteSetting.github_linkback_projects =
123 | "discourse/discourse|eviltrout/ember-performance|discourse/*"
124 |
125 | post.custom_fields[GithubLinkback.field_for(github_commit_link)] = "true"
126 | post.custom_fields[GithubLinkback.field_for(github_issue_link)] = "true"
127 | post.custom_fields[GithubLinkback.field_for(github_pr_link)] = "true"
128 | post.custom_fields[GithubLinkback.field_for(github_pr_link_wildcard)] = "true"
129 | post.save_custom_fields
130 |
131 | links = GithubLinkback.new(post).github_links
132 | expect(links.size).to eq(0)
133 | end
134 |
135 | it "should return the urls for the selected projects" do
136 | SiteSetting.github_linkback_projects =
137 | "discourse/discourse|eviltrout/ember-performance|discourse/*"
138 | links = GithubLinkback.new(post).github_links
139 | expect(links.size).to eq(4)
140 |
141 | expect(links[0].url).to eq(github_commit_link)
142 | expect(links[0].project).to eq("discourse/discourse")
143 | expect(links[0].sha).to eq("76981605fa10975e2e7af457e2f6a31909e0c811")
144 | expect(links[0].type).to eq(:commit)
145 |
146 | expect(links[1].url).to eq(github_issue_link)
147 | expect(links[1].project).to eq("discourse/discourse")
148 | expect(links[1].issue_number).to eq(123)
149 | expect(links[1].type).to eq(:issue)
150 |
151 | expect(links[2].url).to eq(github_pr_link)
152 | expect(links[2].project).to eq("discourse/discourse")
153 | expect(links[2].pr_number).to eq(701)
154 | expect(links[2].type).to eq(:pr)
155 |
156 | expect(links[3].url).to eq(github_pr_link_wildcard)
157 | expect(links[3].project).to eq("discourse/discourse-github-linkback")
158 | expect(links[3].pr_number).to eq(3)
159 | expect(links[3].type).to eq(:pr)
160 | end
161 | end
162 |
163 | describe "#create" do
164 | before { SiteSetting.github_linkback_projects = "discourse/discourse|discourse/*" }
165 |
166 | it "returns an empty array without an access token" do
167 | expect(GithubLinkback.new(post).create).to be_blank
168 | end
169 |
170 | context "with an access token" do
171 | let(:headers) do
172 | {
173 | "Authorization" => "token abcdef",
174 | "Content-Type" => "application/json",
175 | "Host" => "api.github.com",
176 | "User-Agent" => "Discourse-Github-Linkback",
177 | }
178 | end
179 |
180 | before do
181 | SiteSetting.github_linkback_access_token = "abcdef"
182 |
183 | stub_request(
184 | :post,
185 | "https://api.github.com/repos/discourse/discourse/commits/76981605fa10975e2e7af457e2f6a31909e0c811/comments",
186 | ).with(headers: headers).to_return(status: 200, body: "", headers: {})
187 |
188 | stub_request(
189 | :post,
190 | "https://api.github.com/repos/discourse/discourse/issues/123/comments",
191 | ).with(headers: headers).to_return(status: 200, body: "", headers: {})
192 |
193 | stub_request(
194 | :post,
195 | "https://api.github.com/repos/discourse/discourse/issues/701/comments",
196 | ).with(headers: headers).to_return(status: 200, body: "", headers: {})
197 |
198 | stub_request(
199 | :post,
200 | "https://api.github.com/repos/discourse/discourse-github-linkback/issues/3/comments",
201 | ).with(headers: headers).to_return(status: 200, body: "", headers: {})
202 | end
203 |
204 | it "returns the URLs it linked to and creates custom fields" do
205 | links = GithubLinkback.new(post).create
206 | expect(links.size).to eq(4)
207 |
208 | expect(links[0].url).to eq(github_commit_link)
209 | field = GithubLinkback.field_for(github_commit_link)
210 | expect(post.custom_fields[field]).to be_present
211 |
212 | expect(links[1].url).to eq(github_issue_link)
213 | field = GithubLinkback.field_for(github_issue_link)
214 | expect(post.custom_fields[field]).to be_present
215 |
216 | expect(links[2].url).to eq(github_pr_link)
217 | field = GithubLinkback.field_for(github_pr_link)
218 | expect(post.custom_fields[field]).to be_present
219 |
220 | expect(links[3].url).to eq(github_pr_link_wildcard)
221 | field = GithubLinkback.field_for(github_pr_link_wildcard)
222 | expect(post.custom_fields[field]).to be_present
223 | end
224 |
225 | it "should create linkback for <= SiteSetting.github_linkback_maximum_links urls" do
226 | SiteSetting.github_linkback_maximum_links = 2
227 | post = Fabricate(:post, raw: "#{github_pr_link} #{github_issue_link}")
228 | links = GithubLinkback.new(post).create
229 | expect(links.size).to eq(2)
230 | end
231 |
232 | it "should skip linkback for > SiteSetting.github_linkback_maximum_links urls" do
233 | SiteSetting.github_linkback_maximum_links = 1
234 | post = Fabricate(:post, raw: "#{github_pr_link} #{github_issue_link}")
235 | links = GithubLinkback.new(post).create
236 | expect(links.size).to eq(0)
237 | end
238 |
239 | it "should create linkback for <= SiteSetting.github_linkback_maximum_links unique urls" do
240 | SiteSetting.github_linkback_maximum_links = 1
241 | post = Fabricate(:post, raw: "#{github_pr_link} #{github_pr_link} #{github_pr_link}")
242 | links = GithubLinkback.new(post).create
243 | expect(links.size).to eq(1)
244 | end
245 | end
246 | end
247 | end
248 |
--------------------------------------------------------------------------------
/spec/lib/github_permalinks_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "rails_helper"
4 |
5 | describe GithubPermalinks do
6 | context "when it doesn't contain github link to the file" do
7 | let(:post) { Fabricate(:post, raw: "there is no github link") }
8 |
9 | it "it does not run the job" do
10 | Jobs.expects(:cancel_scheduled_job).never
11 | GithubPermalinks.replace_github_non_permalinks(post)
12 | end
13 | end
14 |
15 | context "when it contains github link" do
16 | let(:post) do
17 | Fabricate(
18 | :post,
19 | raw: "https://github.com/discourse/onebox/blob/master/lib/onebox/engine/gfycat_onebox.rb",
20 | )
21 | end
22 |
23 | it "ensures only one job is scheduled right after the editing_grace_period" do
24 | freeze_time
25 |
26 | Jobs
27 | .expects(:cancel_scheduled_job)
28 | .with(:replace_github_non_permalinks, post_id: post.id)
29 | .once
30 | delay = SiteSetting.editing_grace_period + 1
31 |
32 | expect_enqueued_with(
33 | job: :replace_github_non_permalinks,
34 | args: {
35 | post_id: post.id,
36 | bypass_bump: false,
37 | },
38 | at: Time.zone.now + delay,
39 | ) { GithubPermalinks.replace_github_non_permalinks(post) }
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/spec/models/github_repo_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "rails_helper"
4 |
5 | describe DiscourseGithubPlugin::GithubRepo do
6 | it "strips .git from url" do
7 | SiteSetting.github_badges_repos = "https://github.com/discourse/discourse.git"
8 | repo = DiscourseGithubPlugin::GithubRepo.repos.first
9 | expect(repo.name).to eq("discourse/discourse")
10 | end
11 |
12 | it "strips trailing slash from url" do
13 | SiteSetting.github_badges_repos = "https://github.com/discourse/discourse/"
14 | repo = DiscourseGithubPlugin::GithubRepo.repos.first
15 | expect(repo.name).to eq("discourse/discourse")
16 | end
17 |
18 | it "doesn't raise an error when the site setting follows the user/repo format" do
19 | SiteSetting.github_badges_repos = "discourse/discourse-github"
20 | repo = DiscourseGithubPlugin::GithubRepo.repos.first
21 | expect(repo.name).to eq("discourse/discourse-github")
22 |
23 | SiteSetting.github_badges_repos = "discourse/somerepo_with-numbers7"
24 | repo = DiscourseGithubPlugin::GithubRepo.repos.first
25 | expect(repo.name).to eq("discourse/somerepo_with-numbers7")
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/stylelint.config.mjs:
--------------------------------------------------------------------------------
1 | export default {
2 | extends: ["@discourse/lint-configs/stylelint"],
3 | };
4 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------