Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-10-30 03:08:51 +00:00
parent 42883e12f1
commit 3b1798cdfa
12 changed files with 415 additions and 23 deletions

View file

@ -1 +1 @@
6aabab39e06f8a4f786a99449a49d5f0cb332310
a193b76fa6cbf33108c6a5ed36a99cc5fdc215c3

View file

@ -27,7 +27,7 @@ class Projects::BranchesController < Projects::ApplicationController
@refs_pipelines = @project.ci_pipelines.latest_successful_for_refs(@branches.map(&:name))
@merged_branch_names = repository.merged_branch_names(@branches.map(&:name))
@branch_pipeline_statuses = branch_pipeline_statuses
@branch_pipeline_statuses = Ci::CommitStatusesFinder.new(@project, repository, current_user, @branches).execute
# https://gitlab.com/gitlab-org/gitlab/-/issues/22851
Gitlab::GitalyClient.allow_n_plus_1_calls do
@ -197,15 +197,4 @@ class Projects::BranchesController < Projects::ApplicationController
confidential_issue_project
end
def branch_pipeline_statuses
latest_commits = @branches.map do |branch|
[branch.name, repository.commit(branch.dereferenced_target).sha]
end.to_h
latest_pipelines = project.ci_pipelines.latest_pipeline_per_commit(latest_commits.values)
latest_commits.transform_values do |commit_sha|
latest_pipelines[commit_sha]&.detailed_status(current_user)
end.compact
end
end

View file

@ -24,6 +24,7 @@ class Projects::TagsController < Projects::ApplicationController
tag_names = @tags.map(&:name)
@tags_pipelines = @project.ci_pipelines.latest_successful_for_refs(tag_names)
@releases = project.releases.where(tag: tag_names)
@tag_pipeline_statuses = Ci::CommitStatusesFinder.new(@project, @repository, current_user, @tags).execute
respond_to do |format|
format.html

View file

@ -0,0 +1,40 @@
# frozen_string_literal: true
module Ci
class CommitStatusesFinder
include ::Gitlab::Utils::StrongMemoize
def initialize(project, repository, current_user, refs)
@project = project
@repository = repository
@current_user = current_user
@refs = refs
end
def execute
return [] unless Ability.allowed?(@current_user, :read_pipeline, @project)
commit_statuses
end
private
def latest_commits
strong_memoize(:latest_commits) do
refs.map do |ref|
[ref.name, @repository.commit(ref.dereferenced_target).sha]
end.to_h
end
end
def commit_statuses
latest_pipelines = project.ci_pipelines.latest_pipeline_per_commit(latest_commits.values)
latest_commits.transform_values do |commit_sha|
latest_pipelines[commit_sha]&.detailed_status(current_user)
end.compact
end
attr_reader :project, :repository, :current_user, :refs
end
end

View file

@ -1,5 +1,6 @@
- commit = @repository.commit(tag.dereferenced_target)
- release = @releases.find { |release| release.tag == tag.name }
- commit_status = @tag_pipeline_statuses[tag.name] unless @tag_pipeline_statuses.nil?
%li.flex-row.allow-wrap.js-tag-list
.row-main-content
@ -34,6 +35,12 @@
- if tag.has_signature?
= render partial: 'projects/commit/signature', object: tag.signature
- if commit_status
= render 'ci/status/icon', size: 24, status: commit_status, option_css_classes: 'gl-display-inline-flex gl-vertical-align-middle gl-mr-5'
- elsif @tag_pipeline_statuses && @tag_pipeline_statuses.any?
.gl-display-inline-flex.gl-vertical-align-middle.gl-mr-5
%svg.s24
= render 'projects/buttons/download', project: @project, ref: tag.name, pipeline: @tags_pipelines[tag.name]
- if can?(current_user, :admin_tag, @project)

View file

@ -0,0 +1,5 @@
---
title: Show build status in tag list
merge_request: 34307
author: Lee Tickett
type: added

View file

@ -22,7 +22,7 @@ of `state` are:
- `finished`
- `failed`
- `replicated`
- `cleanup_failed`
- `cleanup failed`
To ensure data integrity, projects are put in a temporary read-only state for the
duration of the move. During this time, users receive a `The repository is temporarily

View file

@ -285,7 +285,7 @@ you can use the `MAVEN_CLI_OPTS` environment variable.
Read more on [how to use private Maven repositories](../index.md#using-private-maven-repos).
#### Enabling Kubesec analyzer
### Enabling Kubesec analyzer
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12752) in GitLab Ultimate 12.6.
@ -300,7 +300,7 @@ variables:
SCAN_KUBERNETES_MANIFESTS: "true"
```
#### Pre-compilation
### Pre-compilation
If your project requires custom build configurations, it can be preferable to avoid
compilation during your SAST execution and instead pass all job artifacts from an

View file

@ -0,0 +1,89 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Package', :orchestrated, :packages do
describe 'Conan Repository' do
include Runtime::Fixtures
let(:package_name) { 'conantest' }
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'conan-package-project'
end
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = ["runner-for-#{project.name}"]
runner.executor = :docker
runner.project = project
end
end
let(:gitlab_address_with_port) do
uri = URI.parse(Runtime::Scenario.gitlab_address)
"#{uri.scheme}://#{uri.host}:#{uri.port}"
end
after do
runner.remove_via_api!
end
it 'publishes a conan package and deletes it', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1077' do
Flow::Login.sign_in
Resource::Repository::Commit.fabricate_via_api! do |commit|
commit.project = project
commit.commit_message = 'Add .gitlab-ci.yml'
commit.add_files([{
file_path: '.gitlab-ci.yml',
content:
<<~YAML
image: conanio/gcc7
create_package:
stage: deploy
script:
- "conan remote add gitlab #{gitlab_address_with_port}/api/v4/projects/#{project.id}/packages/conan"
- "conan new #{package_name}/0.1 -t"
- "conan create . mycompany/stable"
- "CONAN_LOGIN_USERNAME=ci_user CONAN_PASSWORD=${CI_JOB_TOKEN} conan upload #{package_name}/0.1@mycompany/stable --all --remote=gitlab"
tags:
- "runner-for-#{project.name}"
YAML
}])
end
project.visit!
Page::Project::Menu.perform(&:click_ci_cd_pipelines)
Page::Project::Pipeline::Index.perform(&:click_on_latest_pipeline)
Page::Project::Pipeline::Show.perform do |pipeline|
pipeline.click_job('create_package')
end
Page::Project::Job::Show.perform do |job|
expect(job).to be_successful(timeout: 800)
end
Page::Project::Menu.perform(&:click_packages_link)
Page::Project::Packages::Index.perform do |index|
expect(index).to have_package(package_name)
index.click_package(package_name)
end
Page::Project::Packages::Show.perform do |package|
package.click_delete
end
Page::Project::Packages::Index.perform do |index|
expect(index).to have_content("Package deleted successfully")
expect(index).to have_no_package(package_name)
end
end
end
end
end

View file

@ -9,18 +9,75 @@ RSpec.describe Projects::TagsController do
let(:user) { create(:user) }
describe 'GET index' do
before do
get :index, params: { namespace_id: project.namespace.to_param, project_id: project }
end
subject { get :index, params: { namespace_id: project.namespace.to_param, project_id: project } }
it 'returns the tags for the page' do
subject
expect(assigns(:tags).map(&:name)).to include('v1.1.0', 'v1.0.0')
end
it 'returns releases matching those tags' do
subject
expect(assigns(:releases)).to include(release)
expect(assigns(:releases)).not_to include(invalid_release)
end
context '@tag_pipeline_status' do
context 'when no pipelines exist' do
it 'is empty' do
subject
expect(assigns(:tag_pipeline_statuses)).to be_empty
end
end
context 'when multiple tags exist' do
before do
create(:ci_pipeline,
project: project,
ref: 'v1.1.0',
sha: project.commit('v1.1.0').sha,
status: :running)
create(:ci_pipeline,
project: project,
ref: 'v1.0.0',
sha: project.commit('v1.0.0').sha,
status: :success)
end
it 'all relevant commit statuses are received' do
subject
expect(assigns(:tag_pipeline_statuses)['v1.1.0'].group).to eq("running")
expect(assigns(:tag_pipeline_statuses)['v1.0.0'].group).to eq("success")
end
end
context 'when a tag has multiple pipelines' do
before do
create(:ci_pipeline,
project: project,
ref: 'v1.0.0',
sha: project.commit('v1.0.0').sha,
status: :running,
created_at: 6.months.ago)
create(:ci_pipeline,
project: project,
ref: 'v1.0.0',
sha: project.commit('v1.0.0').sha,
status: :success,
created_at: 2.months.ago)
end
it 'chooses the latest to determine status' do
subject
expect(assigns(:tag_pipeline_statuses)['v1.0.0'].group).to eq("success")
end
end
end
end
describe 'GET show' do
@ -70,7 +127,8 @@ RSpec.describe Projects::TagsController do
end
let(:release_description) { nil }
let(:request) do
subject(:request) do
post(:create, params: {
namespace_id: project.namespace.to_param,
project_id: project,
@ -81,7 +139,7 @@ RSpec.describe Projects::TagsController do
end
it 'creates tag' do
request
subject
expect(response).to have_gitlab_http_status(:found)
expect(project.repository.find_tag('1.0')).to be_present
@ -92,7 +150,7 @@ RSpec.describe Projects::TagsController do
let(:release_description) { 'some release description' }
it 'creates tag and release' do
request
subject
expect(response).to have_gitlab_http_status(:found)
expect(project.repository.find_tag('1.0')).to be_present
@ -118,7 +176,7 @@ RSpec.describe Projects::TagsController do
expect(service).to receive(:execute).and_call_original
end
request
subject
aggregate_failures do
expect(response).to have_gitlab_http_status(:found)

View file

@ -0,0 +1,178 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Ci::CommitStatusesFinder, '#execute' do
let_it_be(:project) { create(:project, :public, :repository) }
let_it_be(:release) { create(:release, project: project) }
let_it_be(:user) { create(:user) }
context 'tag refs' do
let_it_be(:tags) { TagsFinder.new(project.repository, {}).execute }
let(:subject) { described_class.new(project, project.repository, user, tags).execute }
context 'no pipelines' do
it 'returns nil' do
expect(subject).to be_blank
end
end
context 'when multiple tags exist' do
before do
create(:ci_pipeline,
project: project,
ref: 'v1.1.0',
sha: project.commit('v1.1.0').sha,
status: :running)
create(:ci_pipeline,
project: project,
ref: 'v1.0.0',
sha: project.commit('v1.0.0').sha,
status: :success)
end
it 'all relevant commit statuses are received' do
expect(subject['v1.1.0'].group).to eq("running")
expect(subject['v1.0.0'].group).to eq("success")
end
end
context 'when a tag has multiple pipelines' do
before do
create(:ci_pipeline,
project: project,
ref: 'v1.0.0',
sha: project.commit('v1.0.0').sha,
status: :running,
created_at: 6.months.ago)
create(:ci_pipeline,
project: project,
ref: 'v1.0.0',
sha: project.commit('v1.0.0').sha,
status: :success,
created_at: 2.months.ago)
end
it 'chooses the latest to determine status' do
expect(subject['v1.0.0'].group).to eq("success")
end
end
end
context 'branch refs' do
let(:subject) { described_class.new(project, project.repository, user, branches).execute }
before do
project.add_developer(user)
end
context 'no pipelines' do
let(:branches) { BranchesFinder.new(project.repository, {}).execute }
it 'returns nil' do
expect(subject).to be_blank
end
end
context 'when a branch has multiple pipelines' do
let(:branches) { BranchesFinder.new(project.repository, {}).execute }
before do
sha = project.repository.create_file(user, generate(:branch), 'content', message: 'message', branch_name: 'master')
create(:ci_pipeline,
project: project,
user: user,
ref: "master",
sha: sha,
status: :running,
created_at: 6.months.ago)
create(:ci_pipeline,
project: project,
user: user,
ref: "master",
sha: sha,
status: :success,
created_at: 2.months.ago)
end
it 'chooses the latest to determine status' do
expect(subject["master"].group).to eq("success")
end
end
context 'when multiple branches exist' do
let(:branches) { BranchesFinder.new(project.repository, {}).execute }
before do
master_sha = project.repository.create_file(user, generate(:branch), 'content', message: 'message', branch_name: 'master')
create(:ci_pipeline,
project: project,
user: user,
ref: "master",
sha: master_sha,
status: :running,
created_at: 6.months.ago)
test_sha = project.repository.create_file(user, generate(:branch), 'content', message: 'message', branch_name: 'test')
create(:ci_pipeline,
project: project,
user: user,
ref: "test",
sha: test_sha,
status: :success,
created_at: 2.months.ago)
end
it 'all relevant commit statuses are received' do
expect(subject["master"].group).to eq("running")
expect(subject["test"].group).to eq("success")
end
end
end
context 'CI pipelines visible to' do
let_it_be(:tags) { TagsFinder.new(project.repository, {}).execute }
let(:subject) { described_class.new(project, project.repository, user, tags).execute }
before do
create(:ci_pipeline,
project: project,
ref: 'v1.1.0',
sha: project.commit('v1.1.0').sha,
status: :running)
end
context 'everyone' do
it 'returns something' do
expect(subject).not_to be_blank
end
end
context 'project members only' do
before do
project.project_feature.update!(builds_access_level: ProjectFeature::PRIVATE)
end
it 'returns nil' do
expect(subject).to be_empty
end
end
context 'when not a member of a private project' do
let(:private_project) { create(:project, :private, :repository) }
let(:private_tags) { TagsFinder.new(private_tags.repository, {}).execute }
let(:private_subject) { described_class.new(private_project, private_project.repository, user, tags).execute }
before do
create(:ci_pipeline,
project: private_project,
ref: 'v1.1.0',
sha: private_project.commit('v1.1.0').sha,
status: :running)
end
it 'returns nil' do
expect(private_subject).to be_empty
end
end
end
end

View file

@ -57,4 +57,29 @@ RSpec.describe 'projects/tags/index.html.haml' do
expect(rendered).not_to have_link(href: latest_succeeded_project_artifacts_path(project, "#{pipeline.ref}/download", job: 'test'))
end
end
context 'build stats' do
let(:tag) { 'v1.0.0' }
let(:page) { Capybara::Node::Simple.new(rendered) }
it 'shows build status or placeholder when pipelines present' do
create(:ci_pipeline,
project: project,
ref: tag,
sha: project.commit(tag).sha,
status: :success)
assign(:tag_pipeline_statuses, Ci::CommitStatusesFinder.new(project, project.repository, project.namespace.owner, tags).execute)
render
expect(page.find('.tags .content-list li', text: tag)).to have_css 'a.ci-status-icon-success'
expect(page.all('.tags .content-list li')).to all(have_css('svg.s24'))
end
it 'shows no build status or placeholder when no pipelines present' do
render
expect(page.all('.tags .content-list li')).not_to have_css 'svg.s24'
end
end
end