Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
817adcd0d0
commit
698ab7c4bb
33 changed files with 348 additions and 80 deletions
|
@ -80,12 +80,7 @@ class CloseReopenReportToggle {
|
|||
{
|
||||
input: this.button,
|
||||
valueAttribute: 'data-url',
|
||||
inputAttribute: 'href',
|
||||
},
|
||||
{
|
||||
input: this.button,
|
||||
valueAttribute: 'data-method',
|
||||
inputAttribute: 'data-method',
|
||||
inputAttribute: 'data-endpoint',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@ import { __ } from './locale';
|
|||
|
||||
export default class Issue {
|
||||
constructor() {
|
||||
if ($('a.btn-close').length) this.initIssueBtnEventListeners();
|
||||
if ($('.btn-close, .btn-reopen').length) this.initIssueBtnEventListeners();
|
||||
|
||||
if ($('.js-close-blocked-issue-warning').length) this.initIssueWarningBtnEventListener();
|
||||
|
||||
|
@ -32,8 +32,8 @@ export default class Issue {
|
|||
Issue.initRelatedBranches();
|
||||
}
|
||||
|
||||
this.closeButtons = $('a.btn-close');
|
||||
this.reopenButtons = $('a.btn-reopen');
|
||||
this.closeButtons = $('.btn-close');
|
||||
this.reopenButtons = $('.btn-reopen');
|
||||
|
||||
this.initCloseReopenReport();
|
||||
|
||||
|
@ -103,7 +103,7 @@ export default class Issue {
|
|||
// NOTE: data attribute seems unnecessary but is actually necessary
|
||||
return $('.js-issuable-buttons[data-action="close-reopen"]').on(
|
||||
'click',
|
||||
'a.btn-close, a.btn-reopen, a.btn-close-anyway',
|
||||
'.btn-close, .btn-reopen, .btn-close-anyway',
|
||||
e => {
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
|
@ -120,7 +120,7 @@ export default class Issue {
|
|||
} else {
|
||||
this.disableCloseReopenButton($button);
|
||||
|
||||
const url = $button.attr('href');
|
||||
const url = $button.data('endpoint');
|
||||
|
||||
return axios
|
||||
.put(url)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* eslint-disable func-names, no-underscore-dangle, consistent-return */
|
||||
|
||||
import $ from 'jquery';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import { __ } from '~/locale';
|
||||
import createFlash from '~/flash';
|
||||
import TaskList from './task_list';
|
||||
|
@ -65,9 +66,17 @@ MergeRequest.prototype.showAllCommits = function() {
|
|||
|
||||
MergeRequest.prototype.initMRBtnListeners = function() {
|
||||
const _this = this;
|
||||
return $('a.btn-close, a.btn-reopen').on('click', function(e) {
|
||||
return $('.btn-close, .btn-reopen').on('click', function(e) {
|
||||
const $this = $(this);
|
||||
const shouldSubmit = $this.hasClass('btn-comment');
|
||||
if ($this.hasClass('js-btn-issue-action')) {
|
||||
const url = $this.data('endpoint');
|
||||
return axios
|
||||
.put(url)
|
||||
.then(() => window.location.reload())
|
||||
.catch(() => createFlash(__('Something went wrong.')));
|
||||
}
|
||||
|
||||
if (shouldSubmit && $this.data('submitted')) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -125,9 +125,13 @@ export default {
|
|||
canToggleIssueState() {
|
||||
return (
|
||||
this.getNoteableData.current_user.can_update &&
|
||||
this.getNoteableData.state !== constants.MERGED
|
||||
this.getNoteableData.state !== constants.MERGED &&
|
||||
!this.closedAndLocked
|
||||
);
|
||||
},
|
||||
closedAndLocked() {
|
||||
return !this.isOpen && this.isLocked(this.getNoteableData);
|
||||
},
|
||||
endpoint() {
|
||||
return this.getNoteableData.create_note_path;
|
||||
},
|
||||
|
|
|
@ -205,7 +205,6 @@ export const closeIssue = ({ commit, dispatch, state }) => {
|
|||
commit(types.CLOSE_ISSUE);
|
||||
dispatch('emitStateChangedEvent', data);
|
||||
dispatch('toggleStateButtonLoading', false);
|
||||
dispatch('toggleBlockedIssueWarning', false);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -17,7 +17,10 @@ export default {
|
|||
project: {
|
||||
type: Object,
|
||||
required: true,
|
||||
validator: p => Number.isFinite(p.id) && isString(p.name) && isString(p.name_with_namespace),
|
||||
validator: p =>
|
||||
(Number.isFinite(p.id) || isString(p.id)) &&
|
||||
isString(p.name) &&
|
||||
(isString(p.name_with_namespace) || isString(p.nameWithNamespace)),
|
||||
},
|
||||
selected: {
|
||||
type: Boolean,
|
||||
|
@ -30,8 +33,11 @@ export default {
|
|||
},
|
||||
},
|
||||
computed: {
|
||||
projectNameWithNamespace() {
|
||||
return this.project.nameWithNamespace || this.project.name_with_namespace;
|
||||
},
|
||||
truncatedNamespace() {
|
||||
return truncateNamespace(this.project.name_with_namespace);
|
||||
return truncateNamespace(this.projectNameWithNamespace);
|
||||
},
|
||||
highlightedProjectName() {
|
||||
return highlight(this.project.name, this.matcher);
|
||||
|
@ -58,7 +64,7 @@ export default {
|
|||
<div class="d-flex flex-wrap project-namespace-name-container">
|
||||
<div
|
||||
v-if="truncatedNamespace"
|
||||
:title="project.name_with_namespace"
|
||||
:title="projectNameWithNamespace"
|
||||
class="text-secondary text-truncate js-project-namespace"
|
||||
>
|
||||
{{ truncatedNamespace }}
|
||||
|
|
|
@ -41,7 +41,8 @@ export default {
|
|||
},
|
||||
totalResults: {
|
||||
type: Number,
|
||||
required: true,
|
||||
required: false,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -33,12 +33,13 @@ module Registrations
|
|||
|
||||
def hide_advanced_issues
|
||||
return unless current_user.user_preference.novice?
|
||||
return unless learn_gitlab.available?
|
||||
|
||||
settings = cookies[:onboarding_issues_settings]
|
||||
return unless settings
|
||||
Boards::UpdateService.new(learn_gitlab.project, current_user, label_ids: [learn_gitlab.label.id]).execute(learn_gitlab.board)
|
||||
end
|
||||
|
||||
modified_settings = Gitlab::Json.parse(settings).merge(hideAdvanced: true)
|
||||
cookies[:onboarding_issues_settings] = modified_settings.to_json
|
||||
def learn_gitlab
|
||||
@learn_gitlab ||= LearnGitlab.new(current_user)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -367,15 +367,6 @@ module IssuablesHelper
|
|||
end
|
||||
end
|
||||
|
||||
def issuable_close_reopen_button_method(issuable)
|
||||
case issuable
|
||||
when Issue
|
||||
''
|
||||
when MergeRequest
|
||||
'put'
|
||||
end
|
||||
end
|
||||
|
||||
def issuable_author_is_current_user(issuable)
|
||||
issuable.author == current_user
|
||||
end
|
||||
|
|
|
@ -13,9 +13,6 @@ class Namespace < ApplicationRecord
|
|||
include Gitlab::Utils::StrongMemoize
|
||||
include IgnorableColumns
|
||||
|
||||
ignore_column :plan_id, remove_with: '13.1', remove_after: '2020-06-22'
|
||||
ignore_column :trial_ends_on, remove_with: '13.2', remove_after: '2020-07-22'
|
||||
|
||||
# Prevent users from creating unreasonably deep level of nesting.
|
||||
# The number 20 was taken based on maximum nesting level of
|
||||
# Android repo (15) + some extra backup.
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
- is_current_user = issuable_author_is_current_user(issuable)
|
||||
- display_issuable_type = issuable_display_type(issuable)
|
||||
- button_method = issuable_close_reopen_button_method(issuable)
|
||||
- are_close_and_open_buttons_hidden = issuable_button_hidden?(issuable, true) && issuable_button_hidden?(issuable, false)
|
||||
- add_blocked_class = false
|
||||
- if defined? warn_before_close
|
||||
|
@ -8,11 +7,13 @@
|
|||
|
||||
- if is_current_user
|
||||
- if can_update
|
||||
= link_to _("Close %{display_issuable_type}") % { display_issuable_type: display_issuable_type }, close_issuable_path(issuable), method: button_method,
|
||||
class: "d-none d-sm-none d-md-block btn btn-grouped btn-close js-btn-issue-action #{issuable_button_visibility(issuable, true)} #{(add_blocked_class ? 'btn-issue-blocked' : '')}", title: _("Close %{display_issuable_type}") % { display_issuable_type: display_issuable_type }, data: { qa_selector: 'close_issue_button' }
|
||||
%button{ class: "d-none d-sm-none d-md-block btn btn-grouped btn-close js-btn-issue-action #{issuable_button_visibility(issuable, true)} #{(add_blocked_class ? 'btn-issue-blocked' : '')}",
|
||||
data: { remote: 'true', endpoint: close_issuable_path(issuable), qa_selector: 'close_issue_button' } }
|
||||
= _("Close %{display_issuable_type}") % { display_issuable_type: display_issuable_type }
|
||||
- if can_reopen
|
||||
= link_to _("Reopen %{display_issuable_type}") % { display_issuable_type: display_issuable_type }, reopen_issuable_path(issuable), method: button_method,
|
||||
class: "d-none d-sm-none d-md-block btn btn-grouped btn-reopen js-btn-issue-action #{issuable_button_visibility(issuable, false)}", title: _("Reopen %{display_issuable_type}") % { display_issuable_type: display_issuable_type }, data: { qa_selector: 'reopen_issue_button' }
|
||||
%button{ class: "d-none d-sm-none d-md-block btn btn-grouped btn-reopen js-btn-issue-action #{issuable_button_visibility(issuable, false)}",
|
||||
data: { remote: 'true', endpoint: reopen_issuable_path(issuable), qa_selector: 'reopen_issue_button' } }
|
||||
= _("Reopen %{display_issuable_type}") % { display_issuable_type: display_issuable_type }
|
||||
- else
|
||||
- if can_update && !are_close_and_open_buttons_hidden
|
||||
= render 'shared/issuable/close_reopen_report_toggle', issuable: issuable, warn_before_close: add_blocked_class
|
||||
|
|
|
@ -4,14 +4,13 @@
|
|||
- button_responsive_class = 'd-none d-sm-none d-md-block'
|
||||
- button_class = "#{button_responsive_class} btn btn-grouped js-issuable-close-button js-btn-issue-action issuable-close-button"
|
||||
- toggle_class = "#{button_responsive_class} btn btn-nr dropdown-toggle js-issuable-close-toggle"
|
||||
- button_method = issuable_close_reopen_button_method(issuable)
|
||||
- add_blocked_class = false
|
||||
- if defined? warn_before_close
|
||||
- add_blocked_class = !issuable.closed? && warn_before_close
|
||||
|
||||
.float-left.btn-group.prepend-left-10.issuable-close-dropdown.droplab-dropdown.js-issuable-close-dropdown
|
||||
= link_to "#{display_button_action} #{display_issuable_type}", close_reopen_issuable_path(issuable),
|
||||
method: button_method, class: "#{button_class} btn-#{button_action} #{(add_blocked_class ? 'btn-issue-blocked' : '')}", title: "#{display_button_action} #{display_issuable_type}", data: { qa_selector: 'close_issue_button' }
|
||||
%button{ class: "#{button_class} btn-#{button_action} #{(add_blocked_class ? 'btn-issue-blocked' : '')}", data: { qa_selector: 'close_issue_button', endpoint: close_reopen_issuable_path(issuable) } }
|
||||
#{display_button_action} #{display_issuable_type}
|
||||
|
||||
= button_tag type: 'button', class: "#{toggle_class} btn-#{button_action}-color",
|
||||
data: { 'dropdown-trigger' => '#issuable-close-menu' }, 'aria-label' => _('Toggle dropdown') do
|
||||
|
@ -20,7 +19,7 @@
|
|||
%ul#issuable-close-menu.js-issuable-close-menu.dropdown-menu{ data: { dropdown: true } }
|
||||
%li.close-item{ class: "#{issuable_button_visibility(issuable, true) || 'droplab-item-selected'}",
|
||||
data: { text: _("Close %{display_issuable_type}") % { display_issuable_type: display_issuable_type }, url: close_issuable_path(issuable),
|
||||
button_class: "#{button_class} btn-close", toggle_class: "#{toggle_class} btn-close-color", method: button_method } }
|
||||
button_class: "#{button_class} btn-close", toggle_class: "#{toggle_class} btn-close-color" } }
|
||||
%button.btn.btn-transparent
|
||||
= icon('check', class: 'icon')
|
||||
.description
|
||||
|
@ -30,7 +29,7 @@
|
|||
|
||||
%li.reopen-item{ class: "#{issuable_button_visibility(issuable, false) || 'droplab-item-selected'}",
|
||||
data: { text: _("Reopen %{display_issuable_type}") % { display_issuable_type: display_issuable_type }, url: reopen_issuable_path(issuable),
|
||||
button_class: "#{button_class} btn-reopen", toggle_class: "#{toggle_class} btn-reopen-color", method: button_method } }
|
||||
button_class: "#{button_class} btn-reopen", toggle_class: "#{toggle_class} btn-reopen-color" } }
|
||||
%button.btn.btn-transparent
|
||||
= icon('check', class: 'icon')
|
||||
.description
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove broken hyperlink from close and reopen button
|
||||
merge_request: 22220
|
||||
author: Lee Tickett
|
||||
type: fixed
|
|
@ -0,0 +1,36 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class MigrateVulnerabilityDismissalFeedback < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
disable_ddl_transaction!
|
||||
|
||||
MIGRATION = 'UpdateVulnerabilitiesFromDismissalFeedback'
|
||||
BATCH_SIZE = 500
|
||||
DELAY_INTERVAL = 2.minutes.to_i
|
||||
|
||||
class Vulnerability < ActiveRecord::Base
|
||||
self.table_name = 'vulnerabilities'
|
||||
self.inheritance_column = :_type_disabled
|
||||
|
||||
include ::EachBatch
|
||||
end
|
||||
|
||||
def up
|
||||
return unless Gitlab.ee?
|
||||
|
||||
Vulnerability.select('project_id').group(:project_id).each_batch(of: BATCH_SIZE, column: "project_id") do |project_batch, index|
|
||||
batch_delay = (index - 1) * BATCH_SIZE * DELAY_INTERVAL
|
||||
|
||||
project_batch.each_with_index do |project, project_batch_index|
|
||||
project_delay = project_batch_index * DELAY_INTERVAL
|
||||
migrate_in(batch_delay + project_delay, MIGRATION, project[:project_id])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
# nothing to do
|
||||
end
|
||||
end
|
|
@ -14032,6 +14032,7 @@ COPY "schema_migrations" (version) FROM STDIN;
|
|||
20200519141534
|
||||
20200519171058
|
||||
20200519194042
|
||||
20200519201128
|
||||
20200520103514
|
||||
20200521022725
|
||||
20200521225327
|
||||
|
|
|
@ -201,6 +201,20 @@ project.repository_read_only = true; project.save
|
|||
project.update!(repository_read_only: true)
|
||||
```
|
||||
|
||||
### Transfer project from one namespace to another
|
||||
|
||||
```ruby
|
||||
p= Project.find_by_full_path('')
|
||||
|
||||
# To set the owner of the project
|
||||
current_user= p.creator
|
||||
|
||||
# Namespace where you want this to be moved.
|
||||
namespace = Namespace.find_by_full_path("")
|
||||
|
||||
::Projects::TransferService.new(p, current_user).execute(namespace)
|
||||
```
|
||||
|
||||
### Bulk update service integration password for _all_ projects
|
||||
|
||||
For example, change the Jira user's password for all projects that have the Jira
|
||||
|
|
|
@ -103,7 +103,8 @@ ruby:
|
|||
|
||||
### Go example
|
||||
|
||||
Use the following job in `.gitlab-ci.yml`:
|
||||
Use the following job in `.gitlab-ci.yml`, and ensure you use `-set-exit-code`,
|
||||
otherwise the pipeline will be marked successful, even if the tests fail:
|
||||
|
||||
```yaml
|
||||
## Use https://github.com/jstemmer/go-junit-report to generate a JUnit report with go
|
||||
|
@ -111,7 +112,7 @@ golang:
|
|||
stage: test
|
||||
script:
|
||||
- go get -u github.com/jstemmer/go-junit-report
|
||||
- go test -v 2>&1 | go-junit-report > report.xml
|
||||
- go test -v 2>&1 | go-junit-report -set-exit-code > report.xml
|
||||
artifacts:
|
||||
reports:
|
||||
junit: report.xml
|
||||
|
|
BIN
doc/development/cicd/img/ci_template_selection_v13_1.png
Normal file
BIN
doc/development/cicd/img/ci_template_selection_v13_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
|
@ -2,6 +2,8 @@
|
|||
|
||||
Development guides that are specific to CI/CD are listed here.
|
||||
|
||||
If you are creating new CI/CD templates, please read [the development guide for GitLab CI/CD templates](templates.md).
|
||||
|
||||
## CI Architecture overview
|
||||
|
||||
The following is a simplified diagram of the CI architecture. Some details are left out in order to focus on
|
||||
|
|
66
doc/development/cicd/templates.md
Normal file
66
doc/development/cicd/templates.md
Normal file
|
@ -0,0 +1,66 @@
|
|||
# Development guide for GitLab CI/CD templates
|
||||
|
||||
This document explains how to develop [GitLab CI/CD templates](../../ci/examples/README.md).
|
||||
|
||||
## Place the template file in a relevant directory
|
||||
|
||||
All template files reside in the `lib/gitlab/ci/templates` directory, and are categorized by the following sub-directories:
|
||||
|
||||
| Sub-directroy | Content | [Selectable in UI](#make-sure-the-new-template-can-be-selected-in-ui) |
|
||||
|---------------|--------------------------------------------------------------|-----------------------------------------------------------------------|
|
||||
| `/Jobs/*` | Auto DevOps related jobs | Yes |
|
||||
| `/Pages/*` | Static site generators for GitLab Pages (for example Jekyll) | Yes |
|
||||
| `/Security/*` | Security related jobs | Yes |
|
||||
| `/Verify/*` | Verify/testing related jobs | Yes |
|
||||
| `/Worklows/*` | Common uses of the `workflow:` keyword | No |
|
||||
| `/*` (root) | General templates | Yes |
|
||||
|
||||
## Criteria
|
||||
|
||||
The file must follow the [`.gitlab-ci.yml` syntax](../../ci/yaml/README.md).
|
||||
Verify it's valid by pasting it into the [CI lint tool](https://gitlab.com/gitlab-org/gitlab/-/ci/lint).
|
||||
|
||||
Also, all templates must be named with the `*.gitlab-ci.yml` suffix.
|
||||
|
||||
### Backward compatibility
|
||||
|
||||
A template might be dynamically included with the `include:template:` keyword. If
|
||||
you make a change to an *existing* template, you must make sure that it won't break
|
||||
CI/CD in existing projects.
|
||||
|
||||
## Testing
|
||||
|
||||
Each CI/CD template must be tested in order to make sure that it's safe to be published.
|
||||
|
||||
### Manual QA
|
||||
|
||||
It's always good practice to test the template in a minimal demo project.
|
||||
To do so, please follow the following steps:
|
||||
|
||||
1. Create a public sample project on <http://gitlab.com>.
|
||||
1. Add a `.gitlab-ci.yml` to the project with the proposed template.
|
||||
1. Run pipelines and make sure that everything runs properly, in all possible cases
|
||||
(merge request pipelines, schedules, and so on).
|
||||
1. Link to the project in the description of the merge request that is adding a new template.
|
||||
|
||||
This is useful information for reviewers to make sure the template is safe to be merged.
|
||||
|
||||
### Make sure the new template can be selected in UI
|
||||
|
||||
Templates located under some directories are also [selectable in the **New file** UI](#place-the-template-file-in-a-relevant-directory).
|
||||
When you add a template into one of those directories, make sure that it correctly appears in the dropdown:
|
||||
|
||||
![CI/CD template selection](img/ci_template_selection_v13_1.png)
|
||||
|
||||
### Write an RSpec test
|
||||
|
||||
You should write an RSpec test to make sure that pipeline jobs will be generated correctly:
|
||||
|
||||
1. Add a test file at `spec/lib/gitlab/ci/templates/<template-category>/<template-name>_spec.rb`
|
||||
1. Test that pipeline jobs are properly created via `Ci::CreatePipelineService`.
|
||||
|
||||
## Security
|
||||
|
||||
A template could contain malicious code. For example, a template that contains the `export` shell command in a job
|
||||
might accidentally expose project secret variables in a job log.
|
||||
If you're unsure if it's secure or not, you need to ask security experts for cross-validation.
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module BackgroundMigration
|
||||
# rubocop: disable Style/Documentation
|
||||
class UpdateVulnerabilitiesFromDismissalFeedback
|
||||
def perform(project_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Gitlab::BackgroundMigration::UpdateVulnerabilitiesFromDismissalFeedback.prepend_if_ee('EE::Gitlab::BackgroundMigration::UpdateVulnerabilitiesFromDismissalFeedback')
|
3
lib/gitlab/ci/templates/index.md
Normal file
3
lib/gitlab/ci/templates/index.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Development guide for GitLab CI templates
|
||||
|
||||
Please follow [the development guideline](../../../../doc/development/cicd/templates.md)
|
35
lib/learn_gitlab.rb
Normal file
35
lib/learn_gitlab.rb
Normal file
|
@ -0,0 +1,35 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class LearnGitlab
|
||||
PROJECT_NAME = 'Learn GitLab'.freeze
|
||||
BOARD_NAME = 'GitLab onboarding'.freeze
|
||||
LABEL_NAME = 'Novice'.freeze
|
||||
|
||||
def initialize(current_user)
|
||||
@current_user = current_user
|
||||
end
|
||||
|
||||
def available?
|
||||
project && board && label
|
||||
end
|
||||
|
||||
def project
|
||||
@project ||= current_user.projects.find_by_name(PROJECT_NAME)
|
||||
end
|
||||
|
||||
def board
|
||||
return unless project
|
||||
|
||||
@board ||= project.boards.find_by_name(BOARD_NAME)
|
||||
end
|
||||
|
||||
def label
|
||||
return unless project
|
||||
|
||||
@label ||= project.labels.find_by_name(LABEL_NAME)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :current_user
|
||||
end
|
|
@ -20115,6 +20115,9 @@ msgstr ""
|
|||
msgid "SecurityReports|There was an error while generating the report."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Unable to add %{invalidProjectsMessage}"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Unable to add %{invalidProjects}"
|
||||
msgstr ""
|
||||
|
||||
|
@ -21196,6 +21199,9 @@ msgstr ""
|
|||
msgid "Something went wrong, unable to search projects"
|
||||
msgstr ""
|
||||
|
||||
msgid "Something went wrong."
|
||||
msgstr ""
|
||||
|
||||
msgid "Something went wrong. Please try again."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -99,35 +99,52 @@ describe Registrations::ExperienceLevelsController do
|
|||
end
|
||||
|
||||
describe 'applying the chosen level' do
|
||||
context "when an 'onboarding_issues_settings' cookie does not exist" do
|
||||
let(:params) { super().merge(experience_level: :novice) }
|
||||
|
||||
it 'does not change the cookie' do
|
||||
expect { subject }.not_to change { cookies[:onboarding_issues_settings] }
|
||||
end
|
||||
end
|
||||
|
||||
context "when an 'onboarding_issues_settings' cookie does exist" do
|
||||
context 'when a "Learn GitLab" project is available' do
|
||||
before do
|
||||
request.cookies[:onboarding_issues_settings] = '{}'
|
||||
allow_next_instance_of(LearnGitlab) do |learn_gitlab|
|
||||
allow(learn_gitlab).to receive(:available?).and_return(true)
|
||||
allow(learn_gitlab).to receive(:label).and_return(double(id: 1))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when novice' do
|
||||
let(:params) { super().merge(experience_level: :novice) }
|
||||
|
||||
it "adds a 'hideAdvanced' setting to the cookie" do
|
||||
expect { subject }.to change { Gitlab::Json.parse(cookies[:onboarding_issues_settings])['hideAdvanced'] }.from(nil).to(true)
|
||||
it 'adds a BoardLabel' do
|
||||
expect_next_instance_of(Boards::UpdateService) do |service|
|
||||
expect(service).to receive(:execute)
|
||||
end
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
||||
context 'when experienced' do
|
||||
let(:params) { super().merge(experience_level: :experienced) }
|
||||
|
||||
it 'does not change the cookie' do
|
||||
expect { subject }.not_to change { cookies[:onboarding_issues_settings] }
|
||||
it 'does not add a BoardLabel' do
|
||||
expect(Boards::UpdateService).not_to receive(:new)
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when no "Learn GitLab" project exists' do
|
||||
let(:params) { super().merge(experience_level: :novice) }
|
||||
|
||||
before do
|
||||
allow_next_instance_of(LearnGitlab) do |learn_gitlab|
|
||||
allow(learn_gitlab).to receive(:available?).and_return(false)
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not add a BoardLabel' do
|
||||
expect(Boards::UpdateService).not_to receive(:new)
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do
|
|||
let(:human_model_name) { issuable.model_name.human.downcase }
|
||||
|
||||
it 'shows toggle' do
|
||||
expect(page).to have_link("Close #{human_model_name}")
|
||||
expect(page).to have_button("Close #{human_model_name}")
|
||||
expect(page).to have_selector('.issuable-close-dropdown')
|
||||
end
|
||||
|
||||
|
@ -63,7 +63,7 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do
|
|||
let(:issuable) { create(:issue, :closed, :locked, project: project) }
|
||||
|
||||
it 'hides the reopen button' do
|
||||
expect(page).not_to have_link('Reopen issue')
|
||||
expect(page).not_to have_button('Reopen issue')
|
||||
end
|
||||
|
||||
context 'when the issue author is the current user' do
|
||||
|
@ -72,7 +72,7 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do
|
|||
end
|
||||
|
||||
it 'hides the reopen button' do
|
||||
expect(page).not_to have_link('Reopen issue')
|
||||
expect(page).not_to have_button('Reopen issue')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -91,8 +91,8 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do
|
|||
it 'only shows the `Report abuse` and `New issue` buttons' do
|
||||
expect(page).to have_link('Report abuse')
|
||||
expect(page).to have_link('New issue')
|
||||
expect(page).not_to have_link('Close issue')
|
||||
expect(page).not_to have_link('Reopen issue')
|
||||
expect(page).not_to have_button('Close issue')
|
||||
expect(page).not_to have_button('Reopen issue')
|
||||
expect(page).not_to have_link('Edit')
|
||||
end
|
||||
end
|
||||
|
@ -120,8 +120,8 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do
|
|||
it 'shows only the `Report abuse` and `Edit` button' do
|
||||
expect(page).to have_link('Report abuse')
|
||||
expect(page).to have_link('Edit')
|
||||
expect(page).not_to have_link('Close merge request')
|
||||
expect(page).not_to have_link('Reopen merge request')
|
||||
expect(page).not_to have_button('Close merge request')
|
||||
expect(page).not_to have_button('Reopen merge request')
|
||||
end
|
||||
|
||||
context 'when the merge request author is the current user' do
|
||||
|
@ -130,8 +130,8 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do
|
|||
it 'shows only the `Edit` button' do
|
||||
expect(page).to have_link('Edit')
|
||||
expect(page).not_to have_link('Report abuse')
|
||||
expect(page).not_to have_link('Close merge request')
|
||||
expect(page).not_to have_link('Reopen merge request')
|
||||
expect(page).not_to have_button('Close merge request')
|
||||
expect(page).not_to have_button('Reopen merge request')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -149,8 +149,8 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do
|
|||
|
||||
it 'only shows a `Report abuse` button' do
|
||||
expect(page).to have_link('Report abuse')
|
||||
expect(page).not_to have_link('Close merge request')
|
||||
expect(page).not_to have_link('Reopen merge request')
|
||||
expect(page).not_to have_button('Close merge request')
|
||||
expect(page).not_to have_button('Reopen merge request')
|
||||
expect(page).not_to have_link('Edit')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,7 +15,7 @@ RSpec.describe 'User closes a merge requests', :js do
|
|||
end
|
||||
|
||||
it 'closes a merge request' do
|
||||
click_link('Close merge request', match: :first)
|
||||
click_button('Close merge request', match: :first)
|
||||
|
||||
expect(page).to have_content(merge_request.title)
|
||||
expect(page).to have_content('Closed by')
|
||||
|
|
|
@ -15,7 +15,7 @@ RSpec.describe 'User reopens a merge requests', :js do
|
|||
end
|
||||
|
||||
it 'reopens a merge request' do
|
||||
click_link('Reopen merge request', match: :first)
|
||||
click_button('Reopen merge request', match: :first)
|
||||
|
||||
page.within('.status-box') do
|
||||
expect(page).to have_content('Open')
|
||||
|
|
|
@ -103,7 +103,7 @@ RSpec.describe 'Task Lists' do
|
|||
wait_for_requests
|
||||
|
||||
expect(page).to have_selector(".md .task-list .task-list-item .task-list-item-checkbox")
|
||||
expect(page).to have_selector('a.btn-close')
|
||||
expect(page).to have_selector('.btn-close')
|
||||
end
|
||||
|
||||
it 'is only editable by author' do
|
||||
|
|
|
@ -274,12 +274,7 @@ describe('CloseReopenReportToggle', () => {
|
|||
{
|
||||
input: button,
|
||||
valueAttribute: 'data-url',
|
||||
inputAttribute: 'href',
|
||||
},
|
||||
{
|
||||
input: button,
|
||||
valueAttribute: 'data-method',
|
||||
inputAttribute: 'data-method',
|
||||
inputAttribute: 'data-endpoint',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -74,6 +74,16 @@ describe('ProjectListItem component', () => {
|
|||
expect(renderedNamespace).toBe('a / ... / e /');
|
||||
});
|
||||
|
||||
it(`renders a simple namespace name of a GraphQL project`, () => {
|
||||
options.propsData.project.name_with_namespace = undefined;
|
||||
options.propsData.project.nameWithNamespace = 'test';
|
||||
|
||||
wrapper = shallowMount(Component, options);
|
||||
const renderedNamespace = trimText(wrapper.find('.js-project-namespace').text());
|
||||
|
||||
expect(renderedNamespace).toBe('test /');
|
||||
});
|
||||
|
||||
it(`renders the project name`, () => {
|
||||
options.propsData.project.name = 'my-test-project';
|
||||
|
||||
|
|
61
spec/lib/learn_gitlab_spec.rb
Normal file
61
spec/lib/learn_gitlab_spec.rb
Normal file
|
@ -0,0 +1,61 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe LearnGitlab do
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
let_it_be(:learn_gitlab_project) { create(:project, name: LearnGitlab::PROJECT_NAME) }
|
||||
let_it_be(:learn_gitlab_board) { create(:board, project: learn_gitlab_project, name: LearnGitlab::BOARD_NAME) }
|
||||
let_it_be(:learn_gitlab_label) { create(:label, project: learn_gitlab_project, name: LearnGitlab::LABEL_NAME) }
|
||||
|
||||
before do
|
||||
learn_gitlab_project.add_developer(current_user)
|
||||
end
|
||||
|
||||
describe '.available?' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
where(:project, :board, :label, :expected_result) do
|
||||
nil | nil | nil | nil
|
||||
nil | nil | true | nil
|
||||
nil | true | nil | nil
|
||||
nil | true | true | nil
|
||||
true | nil | nil | nil
|
||||
true | nil | true | nil
|
||||
true | true | nil | nil
|
||||
true | true | true | true
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
allow_next_instance_of(described_class) do |learn_gitlab|
|
||||
allow(learn_gitlab).to receive(:project).and_return(project)
|
||||
allow(learn_gitlab).to receive(:board).and_return(board)
|
||||
allow(learn_gitlab).to receive(:label).and_return(label)
|
||||
end
|
||||
end
|
||||
|
||||
subject { described_class.new(current_user).available? }
|
||||
|
||||
it { is_expected.to be expected_result }
|
||||
end
|
||||
end
|
||||
|
||||
describe '.project' do
|
||||
subject { described_class.new(current_user).project }
|
||||
|
||||
it { is_expected.to eq learn_gitlab_project }
|
||||
end
|
||||
|
||||
describe '.board' do
|
||||
subject { described_class.new(current_user).board }
|
||||
|
||||
it { is_expected.to eq learn_gitlab_board }
|
||||
end
|
||||
|
||||
describe '.label' do
|
||||
subject { described_class.new(current_user).label }
|
||||
|
||||
it { is_expected.to eq learn_gitlab_label }
|
||||
end
|
||||
end
|
BIN
vendor/project_templates/learn_gitlab.tar.gz
vendored
BIN
vendor/project_templates/learn_gitlab.tar.gz
vendored
Binary file not shown.
Loading…
Reference in a new issue