From 2ba89db61f0ebde79d12f80d0cc68cf2361452a4 Mon Sep 17 00:00:00 2001 From: Eduardo Navarro Date: Thu, 23 Sep 2021 10:54:07 +0200 Subject: [PATCH] Support push events in configure_repositories step Co-authored-by: Dany Marcoux --- .../workflow/step/configure_repositories.rb | 17 ++- .../step/configure_repositories_spec.rb | 119 ++++++++++++++++-- 2 files changed, 127 insertions(+), 9 deletions(-) diff --git a/src/api/app/models/workflow/step/configure_repositories.rb b/src/api/app/models/workflow/step/configure_repositories.rb index cd914ac09fe..ebb8c0c47c3 100644 --- a/src/api/app/models/workflow/step/configure_repositories.rb +++ b/src/api/app/models/workflow/step/configure_repositories.rb @@ -8,8 +8,11 @@ class Workflow::Step::ConfigureRepositories < Workflow::Step def call(_options = {}) return unless valid? + target_project = Project.get_by_name(target_project_name) + Pundit.authorize(@token.user, target_project, :update?) + step_instructions[:repositories].each do |repository_instructions| - repository = Repository.includes(:architectures).find_or_create_by(name: repository_instructions[:name], project: Project.get_by_name(target_project_name)) + repository = Repository.includes(:architectures).find_or_create_by(name: repository_instructions[:name], project: target_project) target_repository = Repository.find_by_project_and_name(repository_instructions[:target_project], repository_instructions[:target_repository]) repository.path_elements.find_or_create_by(link: target_repository) @@ -26,8 +29,18 @@ def project_name step_instructions[:project] end + # This method needs to be public because it is used in the Workflow model. def target_project_name - "home:#{@token.user.login}:#{project_name}:PR-#{scm_webhook.payload[:pr_number]}" + if scm_webhook.pull_request_event? + case scm_webhook.payload[:scm] + when 'github' + "#{project_name}:#{scm_webhook.payload[:target_repository_full_name]}:PR-#{scm_webhook.payload[:pr_number]}".tr('/', '-') + when 'gitlab' + "#{project_name}:#{scm_webhook.payload[:path_with_namespace]}:PR-#{scm_webhook.payload[:pr_number]}".tr('/', '-') + end + elsif scm_webhook.push_event? + project_name + end end private diff --git a/src/api/spec/models/workflow/step/configure_repositories_spec.rb b/src/api/spec/models/workflow/step/configure_repositories_spec.rb index 1aefbe00d5a..d461b23153c 100644 --- a/src/api/spec/models/workflow/step/configure_repositories_spec.rb +++ b/src/api/spec/models/workflow/step/configure_repositories_spec.rb @@ -1,15 +1,16 @@ require 'rails_helper' RSpec.describe Workflow::Step::ConfigureRepositories do + let(:user) { create(:confirmed_user, :with_home, login: 'Iggy') } + let(:token) { create(:workflow_token, user: user) } + describe '#call' do - let!(:user) { create(:confirmed_user, :with_home, login: 'Iggy') } - let(:token) { create(:workflow_token, user: user) } - let(:project) { create(:project, name: 'openSUSE:Factory', maintainer: user) } + let(:project) { create(:project, name: 'openSUSE:Factory') } let!(:repository) { create(:repository, project: project, name: 'snapshot', architectures: ['i586', 'aarch64']) } let(:target_project_name) do - 'home:Iggy:OBS:Server:Unstable:PR-1' + 'OBS:Server:Unstable:openSUSE-repo123:PR-1' end - let(:target_project) { create(:project, name: target_project_name) } + let(:target_project) { create(:project, name: target_project_name, maintainer: user) } let(:step_instructions) do { project: 'OBS:Server:Unstable', @@ -33,7 +34,8 @@ event: 'pull_request', action: 'opened', pr_number: 1, - source_repository_full_name: 'reponame', + source_repository_full_name: 'openSUSE/repo123', + target_repository_full_name: 'openSUSE/repo123', commit_sha: '123' }) end @@ -47,6 +49,29 @@ token: token) end + context 'when the token user does not have enough permissions' do + let(:another_user) { create(:confirmed_user, :with_home, login: 'Pop') } + let(:token) { create(:workflow_token, user: another_user) } + let(:scm_webhook) do + ScmWebhook.new(payload: { + scm: 'github', + event: 'pull_request', + action: 'opened', + pr_number: 1, + target_repository_full_name: 'openSUSE/repo123', + commit_sha: '123' + }) + end + + before do + target_project + project + login(another_user) + end + + it { expect { subject.call }.to raise_error(Pundit::NotAuthorizedError) } + end + context 'when the target branch project is present' do before do target_project @@ -276,7 +301,87 @@ end it 'raises an error due to an inexistent target project' do - expect { subject.call }.to raise_error(Project::Errors::UnknownObjectError, 'Project not found: home:Iggy:OBS:Server:Unstable:PR-1') + expect { subject.call }.to raise_error(Project::Errors::UnknownObjectError, "Project not found: #{target_project_name}") + end + end + end + + describe '#target_project_name' do + let(:step_instructions) do + { + project: 'OBS:Server:Unstable', + repositories: + [ + { + name: 'openSUSE_Tumbleweed', + target_project: 'openSUSE:Factory', + target_repository: 'snapshot', + architectures: [ + 'x86_64', + 'ppc' + ] + } + ] + } + end + let(:scm_webhook) { ScmWebhook.new(payload: payload) } + + subject do + described_class.new(step_instructions: step_instructions, + scm_webhook: scm_webhook, + token: token).target_project_name + end + + context 'for an unsupported event' do + let(:payload) do + { + scm: 'github', + event: 'unsupported' + } + end + + it { is_expected.to be_nil } + end + + context 'for a pull request webhook event' do + context 'from GitHub' do + let(:payload) do + { + scm: 'github', + event: 'pull_request', + pr_number: 1, + target_repository_full_name: 'openSUSE/repo123' + } + end + + it { is_expected.to eq('OBS:Server:Unstable:openSUSE-repo123:PR-1') } + end + + context 'from GitLab' do + let(:payload) do + { + scm: 'gitlab', + event: 'Merge Request Hook', + pr_number: 1, + path_with_namespace: 'openSUSE/repo123' + } + end + + it { is_expected.to eq('OBS:Server:Unstable:openSUSE-repo123:PR-1') } + end + end + + context 'for a push webhook event' do + context 'from GitHub' do + let(:payload) { { scm: 'github', event: 'push' } } + + it { is_expected.to eq('OBS:Server:Unstable') } + end + + context 'from GitLab' do + let(:payload) { { scm: 'gitlab', event: 'Push Hook' } } + + it { is_expected.to eq('OBS:Server:Unstable') } end end end