Commit 8e61e9a1 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents 49551dbc 0b0eddca
......@@ -14,7 +14,7 @@ import {
} from '~/behaviors/shortcuts/keybindings';
import createFlash from '~/flash';
import { isSingleViewStyle } from '~/helpers/diffs_helper';
import { getParameterByName, parseBoolean } from '~/lib/utils/common_utils';
import { parseBoolean } from '~/lib/utils/common_utils';
import { updateHistory } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
import PanelResizer from '~/vue_shared/components/panel_resizer.vue';
......@@ -192,6 +192,7 @@ export default {
'showTreeList',
'isLoading',
'startVersion',
'latestDiff',
'currentDiffFileId',
'isTreeLoaded',
'conflictResolutionPath',
......@@ -234,8 +235,8 @@ export default {
isLimitedContainer() {
return !this.renderFileTree && !this.isParallelView && !this.isFluidLayout;
},
isDiffHead() {
return parseBoolean(getParameterByName('diff_head'));
isFullChangeset() {
return this.startVersion === null && this.latestDiff;
},
showFileByFileNavigation() {
return this.diffFiles.length > 1 && this.viewDiffsFileByFile;
......@@ -258,7 +259,7 @@ export default {
if (this.renderOverflowWarning) {
visible = this.$options.alerts.ALERT_OVERFLOW_HIDDEN;
} else if (this.isDiffHead && this.hasConflicts) {
} else if (this.isFullChangeset && this.hasConflicts) {
visible = this.$options.alerts.ALERT_MERGE_CONFLICT;
} else if (this.whichCollapsedTypes.automatic && !this.viewDiffsFileByFile) {
visible = this.$options.alerts.ALERT_COLLAPSED_FILES;
......
......@@ -9,7 +9,11 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
def index
set_index_vars
@personal_access_token = finder.build
scopes = params[:scopes].split(',').map(&:squish).select(&:present?).map(&:to_sym) unless params[:scopes].nil?
@personal_access_token = finder.build(
name: params[:name],
scopes: scopes
)
end
def create
......
......@@ -11,6 +11,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - [Notifications for expiring tokens](https://gitlab.com/gitlab-org/gitlab/-/issues/3649) added in GitLab 12.6.
> - [Token lifetime limits](https://gitlab.com/gitlab-org/gitlab/-/issues/3649) added in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.6.
> - [Additional notifications for expiring tokens](https://gitlab.com/gitlab-org/gitlab/-/issues/214721) added in GitLab 13.3.
> - [Prefill token name and scopes](https://gitlab.com/gitlab-org/gitlab/-/issues/334664) added in GitLab 14.1.
If you're unable to use [OAuth2](../../api/oauth2.md), you can use a personal access token to authenticate with the [GitLab API](../../api/index.md#personalproject-access-tokens). You can also use a personal access token with Git to authenticate over HTTP.
......@@ -37,6 +38,16 @@ You can create as many personal access tokens as you like.
Save the personal access token somewhere safe. After you leave the page,
you no longer have access to the token.
### Prefill personal access token name and scopes
You can link directly to the Personal Access Token page and have the form prefilled with a name and
list of scopes. To do this, you can append a `name` parameter and a list of comma-separated scopes
to the URL. For example:
```plaintext
https://gitlab.example.com/-/profile/personal_access_tokens?name=Example+Access+token&scopes=api,read_user,read_registry
```
## Revoke a personal access token
At any time, you can revoke a personal access token.
......
......@@ -65,8 +65,10 @@ export default {
return this.projectFullPath && this.pipelineIid && this.securityReportSummary.coverageFuzzing;
},
canCreateIssue() {
const path = this.vulnerability.create_vulnerability_feedback_issue_path;
return Boolean(path);
const gitLabIssuePath = this.vulnerability.create_vulnerability_feedback_issue_path;
const jiraIssueUrl = this.vulnerability.create_jira_issue_url;
return Boolean(gitLabIssuePath || jiraIssueUrl);
},
canCreateMergeRequest() {
const path = this.vulnerability.create_vulnerability_feedback_merge_request_path;
......
......@@ -154,6 +154,7 @@ describe('Security Dashboard component', () => {
givenState | expectedProps
${{ modal: { vulnerability: 'foo' } }} | ${{ modal: { vulnerability: 'foo' }, canCreateIssue: false, canCreateMergeRequest: false, canDismissVulnerability: false, isCreatingIssue: false, isDismissingVulnerability: false, isCreatingMergeRequest: false }}
${{ modal: { vulnerability: { create_vulnerability_feedback_issue_path: 'foo' } } }} | ${expect.objectContaining({ canCreateIssue: true })}
${{ modal: { vulnerability: { create_jira_issue_url: 'foo' } } }} | ${expect.objectContaining({ canCreateIssue: true })}
${{ modal: { vulnerability: { create_vulnerability_feedback_merge_request_path: 'foo' } } }} | ${expect.objectContaining({ canCreateMergeRequest: true })}
${{ modal: { vulnerability: { create_vulnerability_feedback_dismissal_path: 'foo' } } }} | ${expect.objectContaining({ canDismissVulnerability: true })}
${{ isCreatingIssue: true }} | ${expect.objectContaining({ isCreatingIssue: true })}
......
......@@ -6,7 +6,7 @@ RSpec.describe Integrations::Github::StatusMessage do
include Rails.application.routes.url_helpers
let(:project) { double(:project, namespace: "me", to_s: 'example_project') }
let(:service) { double(:service, static_context?: false) }
let(:integration) { double(:integration, static_context?: false) }
before do
stub_config_setting(host: 'instance-host')
......@@ -14,14 +14,14 @@ RSpec.describe Integrations::Github::StatusMessage do
describe '#description' do
it 'includes human readable gitlab status' do
subject = described_class.new(project, service, detailed_status: 'passed')
subject = described_class.new(project, integration, detailed_status: 'passed')
expect(subject.description).to eq "Pipeline passed on GitLab"
end
it 'gets truncated to 140 chars' do
dummy_text = 'a' * 500
subject = described_class.new(project, service, detailed_status: dummy_text)
subject = described_class.new(project, integration, detailed_status: dummy_text)
expect(subject.description.length).to eq 140
end
......@@ -43,7 +43,7 @@ RSpec.describe Integrations::Github::StatusMessage do
with_them do
it 'transforms status' do
subject = described_class.new(project, service, status: gitlab_status)
subject = described_class.new(project, integration, status: gitlab_status)
expect(subject.status).to eq github_status
end
......@@ -51,7 +51,7 @@ RSpec.describe Integrations::Github::StatusMessage do
end
describe '#status_options' do
let(:subject) { described_class.new(project, service, id: 1) }
let(:subject) { described_class.new(project, integration, id: 1) }
it 'includes context' do
expect(subject.status_options[:context]).to be_a String
......@@ -68,12 +68,12 @@ RSpec.describe Integrations::Github::StatusMessage do
describe '#context' do
subject do
described_class.new(project, service, ref: 'some-ref')
described_class.new(project, integration, ref: 'some-ref')
end
context 'when status context is supposed to be dynamic' do
before do
allow(service).to receive(:static_context?).and_return(false)
allow(integration).to receive(:static_context?).and_return(false)
end
it 'appends pipeline reference to the status context' do
......@@ -83,7 +83,7 @@ RSpec.describe Integrations::Github::StatusMessage do
context 'when status context is supposed to be static' do
before do
allow(service).to receive(:static_context?).and_return(true)
allow(integration).to receive(:static_context?).and_return(true)
end
it 'appends instance hostname to the status context' do
......@@ -98,7 +98,7 @@ RSpec.describe Integrations::Github::StatusMessage do
let(:sample_data) { Gitlab::DataBuilder::Pipeline.build(pipeline) }
subject do
described_class.from_pipeline_data(project, service, sample_data)
described_class.from_pipeline_data(project, integration, sample_data)
end
it 'builds an instance of Integrations::Github::StatusMessage' do
......@@ -136,11 +136,11 @@ RSpec.describe Integrations::Github::StatusMessage do
context 'when static context has been configured' do
before do
allow(service).to receive(:static_context?).and_return(true)
allow(integration).to receive(:static_context?).and_return(true)
end
subject do
described_class.from_pipeline_data(project, service, sample_data)
described_class.from_pipeline_data(project, integration, sample_data)
end
it 'appends instance name to the context name' do
......
......@@ -15,6 +15,7 @@ module Gitlab
# worker_class can either be the string or class of the worker being enqueued.
worker_class = worker_class.safe_constantize if worker_class.respond_to?(:safe_constantize)
labels = create_labels(worker_class, queue, job)
labels[:scheduling] = job.key?('at') ? 'delayed' : 'immediate'
@metrics.fetch(ENQUEUED).increment(labels, 1)
......
......@@ -64,5 +64,17 @@ RSpec.describe Profiles::PersonalAccessTokensController do
it "retrieves newly created personal access token value" do
expect(assigns(:new_personal_access_token)).to eql(token_value)
end
it "sets PAT name and scopes" do
name = 'My PAT'
scopes = 'api,read_user'
get :index, params: { name: name, scopes: scopes }
expect(assigns(:personal_access_token)).to have_attributes(
name: eq(name),
scopes: contain_exactly(:api, :read_user)
)
end
end
end
......@@ -149,4 +149,15 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do
expect(page).to have_pushed_frontend_feature_flags(personalAccessTokensScopedToProjects: true)
end
it "prefills token details" do
name = 'My PAT'
scopes = 'api,read_user'
visit profile_personal_access_tokens_path({ name: name, scopes: scopes })
expect(page).to have_field("Token name", with: name)
expect(find("#personal_access_token_scopes_api")).to be_checked
expect(find("#personal_access_token_scopes_read_user")).to be_checked
end
end
......@@ -6,14 +6,19 @@ import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
import { TEST_HOST } from 'spec/test_constants';
import App from '~/diffs/components/app.vue';
import CollapsedFilesWarning from '~/diffs/components/collapsed_files_warning.vue';
import CommitWidget from '~/diffs/components/commit_widget.vue';
import CompareVersions from '~/diffs/components/compare_versions.vue';
import DiffFile from '~/diffs/components/diff_file.vue';
import HiddenFilesWarning from '~/diffs/components/hidden_files_warning.vue';
import NoChanges from '~/diffs/components/no_changes.vue';
import TreeList from '~/diffs/components/tree_list.vue';
/* eslint-disable import/order */
/* You know what: sometimes alphabetical isn't the best order */
import CollapsedFilesWarning from '~/diffs/components/collapsed_files_warning.vue';
import HiddenFilesWarning from '~/diffs/components/hidden_files_warning.vue';
import MergeConflictWarning from '~/diffs/components/merge_conflict_warning.vue';
/* eslint-enable import/order */
import axios from '~/lib/utils/axios_utils';
import * as urlUtils from '~/lib/utils/url_utility';
import createDiffsStore from '../create_diffs_store';
......@@ -541,6 +546,43 @@ describe('diffs/components/app', () => {
expect(getCollapsedFilesWarning(wrapper).exists()).toBe(false);
});
});
describe('merge conflicts', () => {
it('should render the merge conflicts banner if viewing the whole changeset and there are conflicts', () => {
createComponent({}, ({ state }) => {
Object.assign(state.diffs, {
latestDiff: true,
startVersion: null,
hasConflicts: true,
canMerge: false,
conflictResolutionPath: 'path',
});
});
expect(wrapper.find(MergeConflictWarning).exists()).toBe(true);
});
it.each`
prop | value
${'latestDiff'} | ${false}
${'startVersion'} | ${'notnull'}
${'hasConflicts'} | ${false}
`(
"should not render if any of the MR properties aren't correct - like $prop: $value",
({ prop, value }) => {
createComponent({}, ({ state }) => {
Object.assign(state.diffs, {
latestDiff: true,
startVersion: null,
hasConflicts: true,
[prop]: value,
});
});
expect(wrapper.find(MergeConflictWarning).exists()).toBe(false);
},
);
});
});
it('should display commit widget if store has a commit', () => {
......
......@@ -3,11 +3,12 @@
require 'spec_helper'
RSpec.describe Gitlab::SidekiqMiddleware::ClientMetrics do
let(:enqueued_jobs_metric) { double('enqueued jobs metric', increment: true) }
shared_examples "a metrics middleware" do
context "with mocked prometheus" do
let(:enqueued_jobs_metric) { double('enqueued jobs metric', increment: true) }
before do
labels[:scheduling] = 'immediate'
allow(Gitlab::Metrics).to receive(:counter).with(described_class::ENQUEUED, anything).and_return(enqueued_jobs_metric)
end
......@@ -32,4 +33,35 @@ RSpec.describe Gitlab::SidekiqMiddleware::ClientMetrics do
end
it_behaves_like 'metrics middleware with worker attribution'
context 'when mounted' do
before do
stub_const('TestWorker', Class.new)
TestWorker.class_eval do
include Sidekiq::Worker
def perform(*args)
end
end
allow(Gitlab::Metrics).to receive(:counter).and_return(Gitlab::Metrics::NullMetric.instance)
allow(Gitlab::Metrics).to receive(:counter).with(described_class::ENQUEUED, anything).and_return(enqueued_jobs_metric)
end
context 'when scheduling jobs for immediate execution' do
it 'increments enqueued jobs metric with scheduling label set to immediate' do
expect(enqueued_jobs_metric).to receive(:increment).with(a_hash_including(scheduling: 'immediate'), 1)
Sidekiq::Testing.inline! { TestWorker.perform_async }
end
end
context 'when scheduling jobs for future execution' do
it 'increments enqueued jobs metric with scheduling label set to delayed' do
expect(enqueued_jobs_metric).to receive(:increment).with(a_hash_including(scheduling: 'delayed'), 1)
Sidekiq::Testing.inline! { TestWorker.perform_in(1.second) }
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment