diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-18 11:17:02 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-18 11:17:02 +0300 |
commit | b39512ed755239198a9c294b6a45e65c05900235 (patch) | |
tree | d234a3efade1de67c46b9e5a38ce813627726aa7 /app/models/integrations | |
parent | d31474cf3b17ece37939d20082b07f6657cc79a9 (diff) |
Add latest changes from gitlab-org/gitlab@15-3-stable-eev15.3.0-rc42
Diffstat (limited to 'app/models/integrations')
-rw-r--r-- | app/models/integrations/bamboo.rb | 4 | ||||
-rw-r--r-- | app/models/integrations/base_issue_tracker.rb | 4 | ||||
-rw-r--r-- | app/models/integrations/base_slash_commands.rb | 2 | ||||
-rw-r--r-- | app/models/integrations/buildkite.rb | 2 | ||||
-rw-r--r-- | app/models/integrations/datadog.rb | 157 | ||||
-rw-r--r-- | app/models/integrations/discord.rb | 39 | ||||
-rw-r--r-- | app/models/integrations/emails_on_push.rb | 2 | ||||
-rw-r--r-- | app/models/integrations/external_wiki.rb | 11 | ||||
-rw-r--r-- | app/models/integrations/harbor.rb | 7 | ||||
-rw-r--r-- | app/models/integrations/jenkins.rb | 4 | ||||
-rw-r--r-- | app/models/integrations/jira.rb | 36 | ||||
-rw-r--r-- | app/models/integrations/packagist.rb | 13 | ||||
-rw-r--r-- | app/models/integrations/pipelines_email.rb | 4 | ||||
-rw-r--r-- | app/models/integrations/prometheus.rb | 4 | ||||
-rw-r--r-- | app/models/integrations/pumble.rb | 59 | ||||
-rw-r--r-- | app/models/integrations/slack.rb | 17 | ||||
-rw-r--r-- | app/models/integrations/teamcity.rb | 4 |
17 files changed, 264 insertions, 105 deletions
diff --git a/app/models/integrations/bamboo.rb b/app/models/integrations/bamboo.rb index 230dc6bb336..c3a4b84bb2d 100644 --- a/app/models/integrations/bamboo.rb +++ b/app/models/integrations/bamboo.rb @@ -63,11 +63,11 @@ module Integrations end def build_page(sha, ref) - with_reactive_cache(sha, ref) {|cached| cached[:build_page] } + with_reactive_cache(sha, ref) { |cached| cached[:build_page] } end def commit_status(sha, ref) - with_reactive_cache(sha, ref) {|cached| cached[:commit_status] } + with_reactive_cache(sha, ref) { |cached| cached[:commit_status] } end def execute(data) diff --git a/app/models/integrations/base_issue_tracker.rb b/app/models/integrations/base_issue_tracker.rb index fe4a2f43b13..a4cec5f927b 100644 --- a/app/models/integrations/base_issue_tracker.rb +++ b/app/models/integrations/base_issue_tracker.rb @@ -100,8 +100,8 @@ module Integrations message = "#{self.type} received response #{response.code} when attempting to connect to #{self.project_url}" result = true end - rescue Gitlab::HTTP::Error, Timeout::Error, SocketError, Errno::ECONNRESET, Errno::ECONNREFUSED, OpenSSL::SSL::SSLError => error - message = "#{self.type} had an error when trying to connect to #{self.project_url}: #{error.message}" + rescue Gitlab::HTTP::Error, Timeout::Error, SocketError, Errno::ECONNRESET, Errno::ECONNREFUSED, OpenSSL::SSL::SSLError => e + message = "#{self.type} had an error when trying to connect to #{self.project_url}: #{e.message}" end log_info(message) result diff --git a/app/models/integrations/base_slash_commands.rb b/app/models/integrations/base_slash_commands.rb index a0ac5474893..e51d748b562 100644 --- a/app/models/integrations/base_slash_commands.rb +++ b/app/models/integrations/base_slash_commands.rb @@ -8,7 +8,7 @@ module Integrations prop_accessor :token - has_many :chat_names, foreign_key: :service_id, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent + has_many :chat_names, foreign_key: :integration_id, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent def valid_token?(token) self.respond_to?(:token) && diff --git a/app/models/integrations/buildkite.rb b/app/models/integrations/buildkite.rb index def646c6d49..7a48e71b934 100644 --- a/app/models/integrations/buildkite.rb +++ b/app/models/integrations/buildkite.rb @@ -60,7 +60,7 @@ module Integrations end def commit_status(sha, ref) - with_reactive_cache(sha, ref) {|cached| cached[:commit_status] } + with_reactive_cache(sha, ref) { |cached| cached[:commit_status] } end def commit_status_path(sha) diff --git a/app/models/integrations/datadog.rb b/app/models/integrations/datadog.rb index 97e586c0662..bb0fb6b9079 100644 --- a/app/models/integrations/datadog.rb +++ b/app/models/integrations/datadog.rb @@ -15,75 +15,7 @@ module Integrations TAG_KEY_VALUE_RE = %r{\A [\w-]+ : .*\S.* \z}x.freeze - field :datadog_site, - placeholder: DEFAULT_DOMAIN, - help: -> do - ERB::Util.html_escape( - s_('DatadogIntegration|The Datadog site to send data to. To send data to the EU site, use %{codeOpen}datadoghq.eu%{codeClose}.') - ) % { - codeOpen: '<code>'.html_safe, - codeClose: '</code>'.html_safe - } - end - - field :api_url, - title: -> { s_('DatadogIntegration|API URL') }, - help: -> { s_('DatadogIntegration|(Advanced) The full URL for your Datadog site.') } - - field :api_key, - type: 'password', - title: -> { _('API key') }, - non_empty_password_title: -> { s_('ProjectService|Enter new API key') }, - non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current API key') }, - help: -> do - ERB::Util.html_escape( - s_('DatadogIntegration|%{linkOpen}API key%{linkClose} used for authentication with Datadog.') - ) % { - linkOpen: %Q{<a href="#{URL_API_KEYS_DOCS}" target="_blank" rel="noopener noreferrer">}.html_safe, - linkClose: '</a>'.html_safe - } - end, - required: true - - field :archive_trace_events, - type: 'checkbox', - title: -> { s_('Logs') }, - checkbox_label: -> { s_('Enable logs collection') }, - help: -> { s_('When enabled, job logs are collected by Datadog and displayed along with pipeline execution traces.') } - - field :datadog_service, - title: -> { s_('DatadogIntegration|Service') }, - placeholder: 'gitlab-ci', - help: -> { s_('DatadogIntegration|Tag all data from this GitLab instance in Datadog. Useful when managing several self-managed deployments.') } - - field :datadog_env, - title: -> { s_('DatadogIntegration|Environment') }, - placeholder: 'ci', - help: -> do - ERB::Util.html_escape( - s_('DatadogIntegration|For self-managed deployments, set the %{codeOpen}env%{codeClose} tag for all the data sent to Datadog. %{linkOpen}How do I use tags?%{linkClose}') - ) % { - codeOpen: '<code>'.html_safe, - codeClose: '</code>'.html_safe, - linkOpen: '<a href="https://docs.datadoghq.com/getting_started/tagging/#using-tags" target="_blank" rel="noopener noreferrer">'.html_safe, - linkClose: '</a>'.html_safe - } - end - - field :datadog_tags, - type: 'textarea', - title: -> { s_('DatadogIntegration|Tags') }, - placeholder: "tag:value\nanother_tag:value", - help: -> do - ERB::Util.html_escape( - s_('DatadogIntegration|Custom tags in Datadog. Enter one tag per line in the %{codeOpen}key:value%{codeClose} format. %{linkOpen}How do I use tags?%{linkClose}') - ) % { - codeOpen: '<code>'.html_safe, - codeClose: '</code>'.html_safe, - linkOpen: '<a href="https://docs.datadoghq.com/getting_started/tagging/#using-tags" target="_blank" rel="noopener noreferrer">'.html_safe, - linkClose: '</a>'.html_safe - } - end + prop_accessor :datadog_site, :api_url, :api_key, :datadog_service, :datadog_env, :datadog_tags before_validation :strip_properties @@ -145,11 +77,92 @@ module Integrations end def fields + f = [ + { + type: 'text', + name: 'datadog_site', + placeholder: DEFAULT_DOMAIN, + help: ERB::Util.html_escape( + s_('DatadogIntegration|The Datadog site to send data to. To send data to the EU site, use %{codeOpen}datadoghq.eu%{codeClose}.') + ) % { + codeOpen: '<code>'.html_safe, + codeClose: '</code>'.html_safe + }, + required: false + }, + { + type: 'text', + name: 'api_url', + title: s_('DatadogIntegration|API URL'), + help: s_('DatadogIntegration|(Advanced) The full URL for your Datadog site.'), + required: false + }, + { + type: 'password', + name: 'api_key', + title: _('API key'), + non_empty_password_title: s_('ProjectService|Enter new API key'), + non_empty_password_help: s_('ProjectService|Leave blank to use your current API key'), + help: ERB::Util.html_escape( + s_('DatadogIntegration|%{linkOpen}API key%{linkClose} used for authentication with Datadog.') + ) % { + linkOpen: %Q{<a href="#{URL_API_KEYS_DOCS}" target="_blank" rel="noopener noreferrer">}.html_safe, + linkClose: '</a>'.html_safe + }, + required: true + } + ] + if Feature.enabled?(:datadog_integration_logs_collection, parent) - super - else - super.reject { _1.name == 'archive_trace_events' } + f.append({ + type: 'checkbox', + name: 'archive_trace_events', + title: s_('Logs'), + checkbox_label: s_('Enable logs collection'), + help: s_('When enabled, job logs are collected by Datadog and displayed along with pipeline execution traces.'), + required: false + }) end + + f += [ + { + type: 'text', + name: 'datadog_service', + title: s_('DatadogIntegration|Service'), + placeholder: 'gitlab-ci', + help: s_('DatadogIntegration|Tag all data from this GitLab instance in Datadog. Useful when managing several self-managed deployments.') + }, + { + type: 'text', + name: 'datadog_env', + title: s_('DatadogIntegration|Environment'), + placeholder: 'ci', + help: ERB::Util.html_escape( + s_('DatadogIntegration|For self-managed deployments, set the %{codeOpen}env%{codeClose} tag for all the data sent to Datadog. %{linkOpen}How do I use tags?%{linkClose}') + ) % { + codeOpen: '<code>'.html_safe, + codeClose: '</code>'.html_safe, + linkOpen: '<a href="https://docs.datadoghq.com/getting_started/tagging/#using-tags" target="_blank" rel="noopener noreferrer">'.html_safe, + linkClose: '</a>'.html_safe + } + }, + { + type: 'textarea', + name: 'datadog_tags', + title: s_('DatadogIntegration|Tags'), + placeholder: "tag:value\nanother_tag:value", + help: ERB::Util.html_escape( + s_('DatadogIntegration|Custom tags in Datadog. Enter one tag per line in the %{codeOpen}key:value%{codeClose} format. %{linkOpen}How do I use tags?%{linkClose}') + ) % { + codeOpen: '<code>'.html_safe, + codeClose: '</code>'.html_safe, + linkOpen: '<a href="https://docs.datadoghq.com/getting_started/tagging/#using-tags" target="_blank" rel="noopener noreferrer">'.html_safe, + linkClose: '</a>'.html_safe + } + } + ] + + f end override :hook_url diff --git a/app/models/integrations/discord.rb b/app/models/integrations/discord.rb index ecabf23c90b..ec8a12e4760 100644 --- a/app/models/integrations/discord.rb +++ b/app/models/integrations/discord.rb @@ -33,10 +33,21 @@ module Integrations def default_fields [ - { type: "text", name: "webhook", placeholder: "https://discordapp.com/api/webhooks/…", help: "URL to the webhook for the Discord channel." }, - { type: "checkbox", name: "notify_only_broken_pipelines" }, + { + type: 'text', + section: SECTION_TYPE_CONNECTION, + name: 'webhook', + placeholder: 'https://discordapp.com/api/webhooks/…', + help: 'URL to the webhook for the Discord channel.' + }, + { + type: 'checkbox', + section: SECTION_TYPE_CONFIGURATION, + name: 'notify_only_broken_pipelines' + }, { type: 'select', + section: SECTION_TYPE_CONFIGURATION, name: 'branches_to_be_notified', title: s_('Integrations|Branches for which notifications are to be sent'), choices: self.class.branch_choices @@ -44,6 +55,26 @@ module Integrations ] end + def sections + [ + { + type: SECTION_TYPE_CONNECTION, + title: s_('Integrations|Connection details'), + description: help + }, + { + type: SECTION_TYPE_TRIGGER, + title: s_('Integrations|Trigger'), + description: s_('Integrations|An event will be triggered when one of the following items happen.') + }, + { + type: SECTION_TYPE_CONFIGURATION, + title: s_('Integrations|Notification settings'), + description: s_('Integrations|Configure the scope of notifications.') + } + ] + end + private def notify(message, opts) @@ -57,8 +88,8 @@ module Integrations embed.timestamp = Time.now.utc end end - rescue RestClient::Exception => error - log_error(error.message) + rescue RestClient::Exception => e + log_error(e.message) false end diff --git a/app/models/integrations/emails_on_push.rb b/app/models/integrations/emails_on_push.rb index ed12a3a8d63..25bda8c2bf0 100644 --- a/app/models/integrations/emails_on_push.rb +++ b/app/models/integrations/emails_on_push.rb @@ -71,7 +71,7 @@ module Integrations recipients, push_data, send_from_committer_email: send_from_committer_email?, - disable_diffs: disable_diffs? + disable_diffs: disable_diffs? ) end diff --git a/app/models/integrations/external_wiki.rb b/app/models/integrations/external_wiki.rb index bc2ea193a84..75fe6b6f164 100644 --- a/app/models/integrations/external_wiki.rb +++ b/app/models/integrations/external_wiki.rb @@ -5,6 +5,7 @@ module Integrations validates :external_wiki_url, presence: true, public_url: true, if: :activated? field :external_wiki_url, + section: SECTION_TYPE_CONNECTION, title: -> { s_('ExternalWikiService|External wiki URL') }, placeholder: -> { s_('ExternalWikiService|https://example.com/xxx/wiki/...') }, help: -> { s_('ExternalWikiService|Enter the URL to the external wiki.') }, @@ -28,6 +29,16 @@ module Integrations s_('Link an external wiki from the project\'s sidebar. %{docs_link}').html_safe % { docs_link: docs_link.html_safe } end + def sections + [ + { + type: SECTION_TYPE_CONNECTION, + title: s_('Integrations|Connection details'), + description: help + } + ] + end + def execute(_data) response = Gitlab::HTTP.get(properties['external_wiki_url'], verify: true) response.body if response.code == 200 diff --git a/app/models/integrations/harbor.rb b/app/models/integrations/harbor.rb index 82981493822..03913a71d47 100644 --- a/app/models/integrations/harbor.rb +++ b/app/models/integrations/harbor.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true +require 'uri' module Integrations class Harbor < Integration @@ -20,7 +21,7 @@ module Integrations end def help - s_("HarborIntegration|After the Harbor integration is activated, global variables ‘$HARBOR_USERNAME’, ‘$HARBOR_PASSWORD’, ‘$HARBOR_URL’ and ‘$HARBOR_PROJECT’ will be created for CI/CD use.") + s_("HarborIntegration|After the Harbor integration is activated, global variables '$HARBOR_USERNAME', '$HARBOR_HOST', '$HARBOR_OCI', '$HARBOR_PASSWORD', '$HARBOR_URL' and '$HARBOR_PROJECT' will be created for CI/CD use.") end class << self @@ -78,8 +79,12 @@ module Integrations def ci_variables return [] unless activated? + oci_uri = URI.parse(url) + oci_uri.scheme = 'oci' [ { key: 'HARBOR_URL', value: url }, + { key: 'HARBOR_HOST', value: oci_uri.host }, + { key: 'HARBOR_OCI', value: oci_uri.to_s }, { key: 'HARBOR_PROJECT', value: project_name }, { key: 'HARBOR_USERNAME', value: username.gsub(/^robot\$/, 'robot$$') }, { key: 'HARBOR_PASSWORD', value: password, public: false, masked: true } diff --git a/app/models/integrations/jenkins.rb b/app/models/integrations/jenkins.rb index ab39d1f7b77..c68b5fd2a96 100644 --- a/app/models/integrations/jenkins.rb +++ b/app/models/integrations/jenkins.rb @@ -53,8 +53,8 @@ module Integrations begin result = execute(data) return { success: false, result: result[:message] } if result[:http_status] != 200 - rescue StandardError => error - return { success: false, result: error } + rescue StandardError => e + return { success: false, result: e } end { success: true, result: result[:message] } diff --git a/app/models/integrations/jira.rb b/app/models/integrations/jira.rb index 566bbc456f8..3ca514ab1fd 100644 --- a/app/models/integrations/jira.rb +++ b/app/models/integrations/jira.rb @@ -18,6 +18,8 @@ module Integrations SECTION_TYPE_JIRA_TRIGGER = 'jira_trigger' SECTION_TYPE_JIRA_ISSUES = 'jira_issues' + SNOWPLOW_EVENT_CATEGORY = self.name + validates :url, public_url: true, presence: true, if: :activated? validates :api_url, public_url: true, allow_blank: true validates :username, presence: true, if: :activated? @@ -362,13 +364,17 @@ module Integrations ) true - rescue StandardError => error - log_exception(error, message: 'Issue transition failed', client_url: client_url) + rescue StandardError => e + log_exception(e, message: 'Issue transition failed', client_url: client_url) false end def transition_issue_to_done(issue) - transitions = issue.transitions rescue [] + transitions = begin + issue.transitions + rescue StandardError + [] + end transition = transitions.find do |transition| status = transition&.to&.statusCategory @@ -384,6 +390,22 @@ module Integrations key = "i_ecosystem_jira_service_#{action}" Gitlab::UsageDataCounters::HLLRedisCounter.track_event(key, values: user.id) + + return unless Feature.enabled?(:route_hll_to_snowplow_phase2) + + optional_arguments = { + project: project, + namespace: group || project&.namespace + }.compact + + Gitlab::Tracking.event( + SNOWPLOW_EVENT_CATEGORY, + Integration::SNOWPLOW_EVENT_ACTION, + label: Integration::SNOWPLOW_EVENT_LABEL, + property: key, + user: user, + **optional_arguments + ) end def add_issue_solved_comment(issue, commit_id, commit_url) @@ -505,7 +527,7 @@ module Integrations self.project, entity_type.to_sym ], - id: entity_id, + id: entity_id, host: Settings.gitlab.base_url ) end @@ -538,9 +560,9 @@ module Integrations # Handle errors when doing Jira API calls def jira_request yield - rescue StandardError => error - @error = error - log_exception(error, message: 'Error sending message', client_url: client_url) + rescue StandardError => e + @error = e + log_exception(e, message: 'Error sending message', client_url: client_url) nil end diff --git a/app/models/integrations/packagist.rb b/app/models/integrations/packagist.rb index fda4822c19f..f91404dab23 100644 --- a/app/models/integrations/packagist.rb +++ b/app/models/integrations/packagist.rb @@ -6,14 +6,14 @@ module Integrations extend Gitlab::Utils::Override field :username, - title: -> { _('Username') }, + title: -> { s_('Username') }, help: -> { s_('Enter your Packagist username.') }, placeholder: '', required: true field :token, type: 'password', - title: -> { _('Token') }, + title: -> { s_('Token') }, help: -> { s_('Enter your Packagist token.') }, non_empty_password_title: -> { s_('ProjectService|Enter new token') }, non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') }, @@ -21,10 +21,11 @@ module Integrations required: true field :server, - title: -> { _('Server (optional)') }, + title: -> { s_('Server (optional)') }, help: -> { s_('Enter your Packagist server. Defaults to https://packagist.org.') }, placeholder: 'https://packagist.org', - exposes_secrets: true + exposes_secrets: true, + required: false validates :username, presence: true, if: :activated? validates :token, presence: true, if: :activated? @@ -55,8 +56,8 @@ module Integrations begin result = execute(data) return { success: false, result: result[:message] } if result[:http_status] != 202 - rescue StandardError => error - return { success: false, result: error } + rescue StandardError => e + return { success: false, result: e } end { success: true, result: result[:message] } diff --git a/app/models/integrations/pipelines_email.rb b/app/models/integrations/pipelines_email.rb index 77cbba25f2c..55a8ce0be11 100644 --- a/app/models/integrations/pipelines_email.rb +++ b/app/models/integrations/pipelines_email.rb @@ -84,8 +84,8 @@ module Integrations result = execute(data, force: true) { success: true, result: result } - rescue StandardError => error - { success: false, result: error } + rescue StandardError => e + { success: false, result: e } end def should_pipeline_be_notified?(data) diff --git a/app/models/integrations/prometheus.rb b/app/models/integrations/prometheus.rb index e672a985810..142f466018b 100644 --- a/app/models/integrations/prometheus.rb +++ b/app/models/integrations/prometheus.rb @@ -70,8 +70,8 @@ module Integrations prometheus_client.ping { success: true, result: 'Checked API endpoint' } - rescue Gitlab::PrometheusClient::Error => err - { success: false, result: err } + rescue Gitlab::PrometheusClient::Error => e + { success: false, result: e } end def prometheus_client diff --git a/app/models/integrations/pumble.rb b/app/models/integrations/pumble.rb new file mode 100644 index 00000000000..17026410eb1 --- /dev/null +++ b/app/models/integrations/pumble.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +module Integrations + class Pumble < BaseChatNotification + def title + 'Pumble' + end + + def description + s_("PumbleIntegration|Send notifications about project events to Pumble.") + end + + def self.to_param + 'pumble' + end + + def help + docs_link = ActionController::Base.helpers.link_to( + _('Learn more.'), + Rails.application.routes.url_helpers.help_page_url('user/project/integrations/pumble'), + target: '_blank', + rel: 'noopener noreferrer' + ) + # rubocop:disable Layout/LineLength + s_("PumbleIntegration|Send notifications about project events to Pumble. %{docs_link}") % { docs_link: docs_link.html_safe } + # rubocop:enable Layout/LineLength + end + + def default_channel_placeholder + end + + def self.supported_events + %w[push issue confidential_issue merge_request note confidential_note tag_push + pipeline wiki_page] + end + + def default_fields + [ + { type: 'text', name: 'webhook', placeholder: "https://api.pumble.com/workspaces/x/...", required: true }, + { type: 'checkbox', name: 'notify_only_broken_pipelines' }, + { + type: 'select', + name: 'branches_to_be_notified', + title: s_('Integrations|Branches for which notifications are to be sent'), + choices: self.class.branch_choices + } + ] + end + + private + + def notify(message, opts) + header = { 'Content-Type' => 'application/json' } + response = Gitlab::HTTP.post(webhook, headers: header, body: { text: message.summary }.to_json) + + response if response.success? + end + end +end diff --git a/app/models/integrations/slack.rb b/app/models/integrations/slack.rb index 93263229109..c254ea379bb 100644 --- a/app/models/integrations/slack.rb +++ b/app/models/integrations/slack.rb @@ -9,6 +9,7 @@ module Integrations push issue confidential_issue merge_request note confidential_note tag_push wiki_page deployment ].freeze + SNOWPLOW_EVENT_CATEGORY = self.name prop_accessor EVENT_CHANNEL['alert'] @@ -54,6 +55,22 @@ module Integrations key = "i_ecosystem_slack_service_#{event}_notification" Gitlab::UsageDataCounters::HLLRedisCounter.track_event(key, values: user_id) + + return unless Feature.enabled?(:route_hll_to_snowplow_phase2) + + optional_arguments = { + project: project, + namespace: group || project&.namespace + }.compact + + Gitlab::Tracking.event( + SNOWPLOW_EVENT_CATEGORY, + Integration::SNOWPLOW_EVENT_ACTION, + label: Integration::SNOWPLOW_EVENT_LABEL, + property: key, + user: User.find(user_id), + **optional_arguments + ) end override :configurable_channels? diff --git a/app/models/integrations/teamcity.rb b/app/models/integrations/teamcity.rb index e0299c9ac5f..ca7a715f4b3 100644 --- a/app/models/integrations/teamcity.rb +++ b/app/models/integrations/teamcity.rb @@ -67,11 +67,11 @@ module Integrations end def build_page(sha, ref) - with_reactive_cache(sha, ref) {|cached| cached[:build_page] } + with_reactive_cache(sha, ref) { |cached| cached[:build_page] } end def commit_status(sha, ref) - with_reactive_cache(sha, ref) {|cached| cached[:commit_status] } + with_reactive_cache(sha, ref) { |cached| cached[:commit_status] } end def calculate_reactive_cache(sha, ref) |