From 8b573c94895dc0ac0e1d9d59cf3e8745e8b539ca Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 17 Dec 2020 11:59:07 +0000 Subject: Add latest changes from gitlab-org/gitlab@13-7-stable-ee --- lib/atlassian/jira_connect/client.rb | 75 ++++++++++++----- .../jira_connect/serializers/base_entity.rb | 6 ++ .../jira_connect/serializers/build_entity.rb | 94 ++++++++++++++++++++++ 3 files changed, 156 insertions(+), 19 deletions(-) create mode 100644 lib/atlassian/jira_connect/serializers/build_entity.rb (limited to 'lib/atlassian') diff --git a/lib/atlassian/jira_connect/client.rb b/lib/atlassian/jira_connect/client.rb index f81ed462174..da24d0e20ee 100644 --- a/lib/atlassian/jira_connect/client.rb +++ b/lib/atlassian/jira_connect/client.rb @@ -12,31 +12,68 @@ module Atlassian @shared_secret = shared_secret end + def send_info(project:, update_sequence_id: nil, **args) + common = { project: project, update_sequence_id: update_sequence_id } + dev_info = args.slice(:commits, :branches, :merge_requests) + build_info = args.slice(:pipelines) + + responses = [] + + responses << store_dev_info(**common, **dev_info) if dev_info.present? + responses << store_build_info(**common, **build_info) if build_info.present? + raise ArgumentError, 'Invalid arguments' if responses.empty? + + responses.compact + end + + private + + def store_build_info(project:, pipelines:, update_sequence_id: nil) + return unless Feature.enabled?(:jira_sync_builds, project) + + builds = pipelines.map do |pipeline| + build = Serializers::BuildEntity.represent( + pipeline, + update_sequence_id: update_sequence_id + ) + next if build.issue_keys.empty? + + build + end.compact + return if builds.empty? + + post('/rest/builds/0.1/bulk', { builds: builds }) + end + def store_dev_info(project:, commits: nil, branches: nil, merge_requests: nil, update_sequence_id: nil) - dev_info_json = { - repositories: [ - Serializers::RepositoryEntity.represent( - project, - commits: commits, - branches: branches, - merge_requests: merge_requests, - user_notes_count: user_notes_count(merge_requests), - update_sequence_id: update_sequence_id - ) - ] - }.to_json - - uri = URI.join(@base_uri, '/rest/devinfo/0.10/bulk') - - headers = { + repo = Serializers::RepositoryEntity.represent( + project, + commits: commits, + branches: branches, + merge_requests: merge_requests, + user_notes_count: user_notes_count(merge_requests), + update_sequence_id: update_sequence_id + ) + + post('/rest/devinfo/0.10/bulk', { repositories: [repo] }) + end + + def post(path, payload) + uri = URI.join(@base_uri, path) + + self.class.post(uri, headers: headers(uri), body: metadata.merge(payload).to_json) + end + + def headers(uri) + { 'Authorization' => "JWT #{jwt_token('POST', uri)}", 'Content-Type' => 'application/json' } - - self.class.post(uri, headers: headers, body: dev_info_json) end - private + def metadata + { providerMetadata: { product: "GitLab #{Gitlab::VERSION}" } } + end def user_notes_count(merge_requests) return unless merge_requests diff --git a/lib/atlassian/jira_connect/serializers/base_entity.rb b/lib/atlassian/jira_connect/serializers/base_entity.rb index 94deb174a45..640337c0399 100644 --- a/lib/atlassian/jira_connect/serializers/base_entity.rb +++ b/lib/atlassian/jira_connect/serializers/base_entity.rb @@ -11,6 +11,12 @@ module Atlassian expose :update_sequence_id, as: :updateSequenceId + def eql(other) + other.is_a?(self.class) && to_json == other.to_json + end + + alias_method :==, :eql + private def update_sequence_id diff --git a/lib/atlassian/jira_connect/serializers/build_entity.rb b/lib/atlassian/jira_connect/serializers/build_entity.rb new file mode 100644 index 00000000000..3eb8b1f1978 --- /dev/null +++ b/lib/atlassian/jira_connect/serializers/build_entity.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +module Atlassian + module JiraConnect + module Serializers + # A Jira 'build' represents what we call a 'pipeline' + class BuildEntity < Grape::Entity + include Gitlab::Routing + + format_with(:iso8601, &:iso8601) + + expose :schema_version, as: :schemaVersion + expose :pipeline_id, as: :pipelineId + expose :iid, as: :buildNumber + expose :update_sequence_id, as: :updateSequenceNumber + expose :source_ref, as: :displayName + expose :url + expose :state + expose :updated_at, as: :lastUpdated, format_with: :iso8601 + expose :issue_keys, as: :issueKeys + expose :test_info, as: :testInfo + expose :references + + def issue_keys + # extract Jira issue keys from either the source branch/ref or the + # merge request title. + @issue_keys ||= begin + src = "#{pipeline.source_ref} #{pipeline.merge_request&.title}" + JiraIssueKeyExtractor.new(src).issue_keys + end + end + + private + + alias_method :pipeline, :object + delegate :project, to: :object + + def url + project_pipeline_url(project, pipeline) + end + + # translate to Jira status + def state + case pipeline.status + when 'scheduled', 'created', 'pending', 'preparing', 'waiting_for_resource' then 'pending' + when 'running' then 'in_progress' + when 'success' then 'successful' + when 'failed' then 'failed' + when 'canceled', 'skipped' then 'cancelled' + else + 'unknown' + end + end + + def pipeline_id + pipeline.ensure_ci_ref! + + pipeline.ci_ref.id.to_s + end + + def schema_version + '1.0' + end + + def test_info + builds = pipeline.builds.pluck(:status) # rubocop: disable CodeReuse/ActiveRecord + n = builds.size + passed = builds.count { |s| s == 'success' } + failed = builds.count { |s| s == 'failed' } + + { + totalNumber: n, + numberPassed: passed, + numberFailed: failed, + numberSkipped: n - (passed + failed) + } + end + + def references + ref = pipeline.source_ref + + [{ + commit: { id: pipeline.sha, repositoryUri: project_url(project) }, + ref: { name: ref, uri: project_commits_url(project, ref) } + }] + end + + def update_sequence_id + options[:update_sequence_id] || Client.generate_update_sequence_id + end + end + end + end +end -- cgit v1.2.1