Commit 41fe9edc authored by Shinya Maeda's avatar Shinya Maeda

Merge branch 'master-ce' into scheduled-manual-jobs

parents e5e307dd 42822a7d
...@@ -67,10 +67,7 @@ stages: ...@@ -67,10 +67,7 @@ stages:
.use-pg: &use-pg .use-pg: &use-pg
services: services:
# As of Jan 2018, we don't have a strong reason to upgrade to 9.6 for CI yet, - postgres:9.6
# so using the least common denominator ensures backwards compatibility
# (as many users are still using 9.2).
- postgres:9.2
- redis:alpine - redis:alpine
.use-mysql: &use-mysql .use-mysql: &use-mysql
...@@ -444,10 +441,10 @@ setup-test-env: ...@@ -444,10 +441,10 @@ setup-test-env:
- vendor/gitaly-ruby - vendor/gitaly-ruby
danger-review: danger-review:
<<: *pull-cache
image: registry.gitlab.com/gitlab-org/gitlab-build-images:danger image: registry.gitlab.com/gitlab-org/gitlab-build-images:danger
stage: test stage: test
allow_failure: true allow_failure: true
cache: {}
dependencies: [] dependencies: []
before_script: [] before_script: []
only: only:
...@@ -461,6 +458,8 @@ danger-review: ...@@ -461,6 +458,8 @@ danger-review:
- $CI_COMMIT_REF_NAME =~ /.*-stable(-ee)?-prepare-.*/ - $CI_COMMIT_REF_NAME =~ /.*-stable(-ee)?-prepare-.*/
script: script:
- git version - git version
- node --version
- yarn install --frozen-lockfile --cache-folder .yarn-cache
- danger --fail-on-errors=true - danger --fail-on-errors=true
rspec-pg 0 30: *rspec-metadata-pg rspec-pg 0 30: *rspec-metadata-pg
......
...@@ -7,3 +7,5 @@ danger.import_dangerfile(path: 'danger/database') ...@@ -7,3 +7,5 @@ danger.import_dangerfile(path: 'danger/database')
danger.import_dangerfile(path: 'danger/documentation') danger.import_dangerfile(path: 'danger/documentation')
danger.import_dangerfile(path: 'danger/frozen_string') danger.import_dangerfile(path: 'danger/frozen_string')
danger.import_dangerfile(path: 'danger/commit_messages') danger.import_dangerfile(path: 'danger/commit_messages')
danger.import_dangerfile(path: 'danger/prettier')
danger.import_dangerfile(path: 'danger/eslint')
...@@ -113,7 +113,7 @@ ...@@ -113,7 +113,7 @@
} }
.avatar-container { .avatar-container {
margin-right: 0; margin: 0 auto;
} }
} }
......
...@@ -19,6 +19,17 @@ ...@@ -19,6 +19,17 @@
} }
} }
// leave enough space for the close icon
.modal-title {
&.mw-100,
&.w-100 {
// after upgrading to Bootstrap 4.2 we can use $modal-header-padding-x here
// https://github.com/twbs/bootstrap/pull/26976
margin-right: -2rem;
padding-right: 2rem;
}
}
.page-title { .page-title {
margin-top: 0; margin-top: 0;
} }
......
...@@ -14,6 +14,8 @@ class Projects::ArtifactsController < Projects::ApplicationController ...@@ -14,6 +14,8 @@ class Projects::ArtifactsController < Projects::ApplicationController
before_action :entry, only: [:file] before_action :entry, only: [:file]
def download def download
return render_404 unless artifacts_file
send_upload(artifacts_file, attachment: artifacts_file.filename) send_upload(artifacts_file, attachment: artifacts_file.filename)
end end
...@@ -100,7 +102,7 @@ class Projects::ArtifactsController < Projects::ApplicationController ...@@ -100,7 +102,7 @@ class Projects::ArtifactsController < Projects::ApplicationController
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
def artifacts_file def artifacts_file
@artifacts_file ||= build.artifacts_file @artifacts_file ||= build.artifacts_file_for_type(params[:file_type] || :archive)
end end
def entry def entry
......
...@@ -327,11 +327,15 @@ module IssuablesHelper ...@@ -327,11 +327,15 @@ module IssuablesHelper
end end
def issuable_button_visibility(issuable, closed) def issuable_button_visibility(issuable, closed)
return 'hidden' if issuable_button_hidden?(issuable, closed)
end
def issuable_button_hidden?(issuable, closed)
case issuable case issuable
when Issue when Issue
issue_button_visibility(issuable, closed) issue_button_hidden?(issuable, closed)
when MergeRequest when MergeRequest
merge_request_button_visibility(issuable, closed) merge_request_button_hidden?(issuable, closed)
end end
end end
......
...@@ -64,7 +64,11 @@ module IssuesHelper ...@@ -64,7 +64,11 @@ module IssuesHelper
end end
def issue_button_visibility(issue, closed) def issue_button_visibility(issue, closed)
return 'hidden' if issue.closed? == closed return 'hidden' if issue_button_hidden?(issue, closed)
end
def issue_button_hidden?(issue, closed)
issue.closed? == closed || (!closed && issue.discussion_locked)
end end
def confidential_icon(issue) def confidential_icon(issue)
......
...@@ -80,7 +80,11 @@ module MergeRequestsHelper ...@@ -80,7 +80,11 @@ module MergeRequestsHelper
end end
def merge_request_button_visibility(merge_request, closed) def merge_request_button_visibility(merge_request, closed)
return 'hidden' if merge_request.closed? == closed || (merge_request.merged? == closed && !merge_request.closed?) || merge_request.closed_without_fork? return 'hidden' if merge_request_button_hidden?(merge_request, closed)
end
def merge_request_button_hidden?(merge_request, closed)
merge_request.closed? == closed || (merge_request.merged? == closed && !merge_request.closed?) || merge_request.closed_without_fork?
end end
def merge_request_version_path(project, merge_request, merge_request_diff, start_sha = nil) def merge_request_version_path(project, merge_request, merge_request_diff, start_sha = nil)
......
...@@ -9,4 +9,17 @@ module VersionCheckHelper ...@@ -9,4 +9,17 @@ module VersionCheckHelper
image_url = VersionCheck.new.url image_url = VersionCheck.new.url
image_tag image_url, class: 'js-version-status-badge' image_tag image_url, class: 'js-version-status-badge'
end end
def link_to_version
if Gitlab.pre_release?
commit_link = link_to(Gitlab.revision, Gitlab::COM_URL + namespace_project_commits_path('gitlab-org', source_code_project, Gitlab.revision))
[Gitlab::VERSION, content_tag(:small, commit_link)].join(' ').html_safe
else
link_to Gitlab::VERSION, Gitlab::COM_URL + namespace_project_tag_path('gitlab-org', source_code_project, "v#{Gitlab::VERSION}")
end
end
def source_code_project
'gitlab-ce'
end
end end
...@@ -560,6 +560,13 @@ module Ci ...@@ -560,6 +560,13 @@ module Ci
self.job_artifacts.update_all(expire_at: nil) self.job_artifacts.update_all(expire_at: nil)
end end
def artifacts_file_for_type(type)
file = job_artifacts.find_by(file_type: Ci::JobArtifact.file_types[type])&.file
# TODO: to be removed once legacy artifacts is removed
file ||= legacy_artifacts_file if type == :archive
file
end
def coverage_regex def coverage_regex
super || project.try(:build_coverage_regex) super || project.try(:build_coverage_regex)
end end
......
...@@ -15,6 +15,7 @@ module Ci ...@@ -15,6 +15,7 @@ module Ci
metadata: nil, metadata: nil,
trace: nil, trace: nil,
junit: 'junit.xml', junit: 'junit.xml',
codequality: 'codequality.json',
sast: 'gl-sast-report.json', sast: 'gl-sast-report.json',
dependency_scanning: 'gl-dependency-scanning-report.json', dependency_scanning: 'gl-dependency-scanning-report.json',
container_scanning: 'gl-container-scanning-report.json', container_scanning: 'gl-container-scanning-report.json',
...@@ -26,6 +27,7 @@ module Ci ...@@ -26,6 +27,7 @@ module Ci
metadata: :gzip, metadata: :gzip,
trace: :raw, trace: :raw,
junit: :gzip, junit: :gzip,
codequality: :gzip,
sast: :gzip, sast: :gzip,
dependency_scanning: :gzip, dependency_scanning: :gzip,
container_scanning: :gzip, container_scanning: :gzip,
...@@ -73,7 +75,8 @@ module Ci ...@@ -73,7 +75,8 @@ module Ci
sast: 5, ## EE-specific sast: 5, ## EE-specific
dependency_scanning: 6, ## EE-specific dependency_scanning: 6, ## EE-specific
container_scanning: 7, ## EE-specific container_scanning: 7, ## EE-specific
dast: 8 ## EE-specific dast: 8, ## EE-specific
codequality: 9 ## EE-specific
} }
enum file_format: { enum file_format: {
......
...@@ -15,6 +15,9 @@ module Clusters ...@@ -15,6 +15,9 @@ module Clusters
state :scheduled, value: 1 state :scheduled, value: 1
state :installing, value: 2 state :installing, value: 2
state :installed, value: 3 state :installed, value: 3
state :updating, value: 4
state :updated, value: 5
state :update_errored, value: 6
event :make_scheduled do event :make_scheduled do
transition [:installable, :errored] => :scheduled transition [:installable, :errored] => :scheduled
...@@ -32,6 +35,18 @@ module Clusters ...@@ -32,6 +35,18 @@ module Clusters
transition any => :errored transition any => :errored
end end
event :make_updating do
transition [:installed, :updated, :update_errored] => :updating
end
event :make_updated do
transition [:updating] => :updated
end
event :make_update_errored do
transition any => :update_errored
end
before_transition any => [:scheduled] do |app_status, _| before_transition any => [:scheduled] do |app_status, _|
app_status.status_reason = nil app_status.status_reason = nil
end end
...@@ -40,6 +55,15 @@ module Clusters ...@@ -40,6 +55,15 @@ module Clusters
status_reason = transition.args.first status_reason = transition.args.first
app_status.status_reason = status_reason if status_reason app_status.status_reason = status_reason if status_reason
end end
before_transition any => [:updating] do |app_status, _|
app_status.status_reason = nil
end
before_transition any => [:update_errored] do |app_status, transition|
status_reason = transition.args.first
app_status.status_reason = status_reason if status_reason
end
end end
end end
end end
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
.sub-section .sub-section
.form-group .form-group
.form-check .form-check
= f.check_box :hashed_storage_enabled, class: 'form-check-input' = f.check_box :hashed_storage_enabled, class: 'form-check-input qa-hashed-storage-checkbox'
= f.label :hashed_storage_enabled, class: 'form-check-label' do = f.label :hashed_storage_enabled, class: 'form-check-label' do
Use hashed storage paths for newly created and renamed projects Use hashed storage paths for newly created and renamed projects
.form-text.text-muted .form-text.text-muted
...@@ -48,4 +48,4 @@ ...@@ -48,4 +48,4 @@
.form-text.text-muted .form-text.text-muted
= circuitbreaker_failure_reset_time_help_text = circuitbreaker_failure_reset_time_help_text
= f.submit 'Save changes', class: "btn btn-success" = f.submit 'Save changes', class: "btn btn-success qa-save-changes-button"
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
.settings-content .settings-content
= render partial: 'repository_mirrors_form' = render partial: 'repository_mirrors_form'
%section.settings.as-repository-storage.no-animate#js-repository-storage-settings{ class: ('expanded' if expanded_by_default?) } %section.settings.qa-repository-storage-settings.as-repository-storage.no-animate#js-repository-storage-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header .settings-header
%h4 %h4
= _('Repository storage') = _('Repository storage')
......
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
.settings-content .settings-content
= render 'signin' = render 'signin'
%section.qa-terms-settings.settings.as-terms.no-animate#js-terms-settings{ class: ('expanded' if expanded_by_default?) } %section.settings.as-terms.no-animate#js-terms-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header .settings-header
%h4 %h4
= _('Terms of Service and Privacy Policy') = _('Terms of Service and Privacy Policy')
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
GitLab GitLab
Community Edition Community Edition
- if user_signed_in? - if user_signed_in?
%span= link_to Gitlab::VERSION, Gitlab::COM_URL + namespace_project_tag_path('gitlab-org', 'gitlab-ce', "v#{Gitlab::VERSION}") %span= link_to_version
= version_status_badge = version_status_badge
%hr %hr
......
.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?) } .nav-sidebar.qa-admin-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?) }
.nav-sidebar-inner-scroll .nav-sidebar-inner-scroll
.context-header .context-header
= link_to admin_root_path, title: _('Admin Overview') do = link_to admin_root_path, title: _('Admin Overview') do
...@@ -197,10 +197,10 @@ ...@@ -197,10 +197,10 @@
= link_to admin_application_settings_path do = link_to admin_application_settings_path do
.nav-icon-container .nav-icon-container
= sprite_icon('settings') = sprite_icon('settings')
%span.nav-item-name %span.nav-item-name.qa-admin-settings-item
= _('Settings') = _('Settings')
%ul.sidebar-sub-level-items %ul.sidebar-sub-level-items.qa-admin-sidebar-submenu
= nav_link(controller: :application_settings, html_options: { class: "fly-out-top-item" } ) do = nav_link(controller: :application_settings, html_options: { class: "fly-out-top-item" } ) do
= link_to admin_application_settings_path do = link_to admin_application_settings_path do
%strong.fly-out-top-item-name %strong.fly-out-top-item-name
...@@ -215,7 +215,7 @@ ...@@ -215,7 +215,7 @@
%span %span
= _('Integrations') = _('Integrations')
= nav_link(path: 'application_settings#repository') do = nav_link(path: 'application_settings#repository') do
= link_to repository_admin_application_settings_path, title: _('Repository') do = link_to repository_admin_application_settings_path, title: _('Repository'), class: 'qa-admin-settings-repository-item' do
%span %span
= _('Repository') = _('Repository')
- if template_exists?('admin/application_settings/templates') - if template_exists?('admin/application_settings/templates')
......
- is_current_user = issuable_author_is_current_user(issuable) - is_current_user = issuable_author_is_current_user(issuable)
- display_issuable_type = issuable_display_type(issuable) - display_issuable_type = issuable_display_type(issuable)
- button_method = issuable_close_reopen_button_method(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)
- if can_update - if is_current_user
- if is_current_user - if can_update
= link_to "Close #{display_issuable_type}", close_issuable_path(issuable), method: button_method, = link_to "Close #{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)}", title: "Close #{display_issuable_type}" class: "d-none d-sm-none d-md-block btn btn-grouped btn-close js-btn-issue-action #{issuable_button_visibility(issuable, true)}", title: "Close #{display_issuable_type}"
- else - if can_reopen
= render 'shared/issuable/close_reopen_report_toggle', issuable: issuable
- if can_reopen && is_current_user
= link_to "Reopen #{display_issuable_type}", reopen_issuable_path(issuable), method: button_method, = link_to "Reopen #{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}" 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}"
- else - else
= link_to 'Report abuse', new_abuse_report_path(user_id: issuable.author.id, ref_url: issuable_url(issuable)), - if can_update && !are_close_and_open_buttons_hidden
class: 'd-none d-sm-none d-md-block btn btn-grouped btn-close-color', title: 'Report abuse' = render 'shared/issuable/close_reopen_report_toggle', issuable: issuable
- else
= link_to 'Report abuse', new_abuse_report_path(user_id: issuable.author.id, ref_url: issuable_url(issuable)),
class: 'd-none d-sm-none d-md-block btn btn-grouped btn-close-color', title: 'Report abuse'
---
title: Hides Close Merge request btn on merged Merge request
merge_request: 21840
author: Jacopo Beschi @jacopo-beschi
type: fixed
---
title: Fix migration to avoid an exception during upgrade
merge_request: 22055
author:
type: fixed
---
title: Align collapsed sidebar avatar container
merge_request: 22044
author: George Tsiolis
type: other
---
title: Show SHA for pre-release versions on the help page
merge_request: 22026
author:
type: changed
---
title: Avoid close icon leaving the modal header
merge_request: 21904
author:
type: changed
# frozen_string_literal: true
def get_eslint_files(files)
files.select do |file|
file.end_with?('.js', '.vue') &&
File.read(file).include?('/* eslint-disable')
end
end
eslint_candidates = get_eslint_files(git.added_files + git.modified_files)
return if eslint_candidates.empty?
warn 'This merge request changed files with disabled eslint rules. Please consider fixing them.'
markdown(<<~MARKDOWN)
## Disabled eslint rules
The following files have disabled `eslint` rules. Please consider fixing them:
* #{eslint_candidates.map { |path| "`#{path}`" }.join("\n* ")}
Run the following command for more details
```
node_modules/.bin/eslint --report-unused-disable-directives --no-inline-config \\
#{eslint_candidates.map { |path| " '#{path}'" }.join(" \\\n")}
```
MARKDOWN
# frozen_string_literal: true
def get_prettier_files(files)
files.select do |file|
file.end_with?('.js', '.scss', '.vue')
end
end
prettier_candidates = get_prettier_files(git.added_files + git.modified_files)
return if prettier_candidates.empty?
unpretty = `node_modules/prettier/bin-prettier.js --list-different #{prettier_candidates.join(" ")}`
.split(/$/)
.map(&:strip)
.reject(&:empty?)
return if unpretty.empty?
warn 'This merge request changed frontend files without pretty printing them.'
markdown(<<~MARKDOWN)
## Pretty print Frontend files
The following files should have been pretty printed with `prettier`:
* #{unpretty.map { |path| "`#{path}`" }.join("\n* ")}
Please run
```
node_modules/.bin/prettier --write \\
#{unpretty.map { |path| " '#{path}'" }.join(" \\\n")}
```
Also consider auto-formatting [on-save].
[on-save]: https://docs.gitlab.com/ee/development/new_fe_guide/style/prettier.html
MARKDOWN
...@@ -5,6 +5,8 @@ class RenameLoginRootNamespaces < ActiveRecord::Migration ...@@ -5,6 +5,8 @@ class RenameLoginRootNamespaces < ActiveRecord::Migration
DOWNTIME = false DOWNTIME = false
disable_ddl_transaction!
# We're taking over the /login namespace as part of a fix for the Jira integration # We're taking over the /login namespace as part of a fix for the Jira integration
def up def up
disable_statement_timeout do disable_statement_timeout do
......
# GitLab quick actions # GitLab quick actions
Quick actions are textual shortcuts for common actions on issues, merge requests Quick actions are textual shortcuts for common actions on issues, epics, merge requests,
or commits that are usually done by clicking buttons or dropdowns in GitLab's UI. and commits that are usually done by clicking buttons or dropdowns in GitLab's UI.
You can enter these commands while creating a new issue or merge request, and You can enter these commands while creating a new issue or merge request, or
in comments. Each command should be on a separate line in order to be properly in comments of issues, epics, merge requests, and commits. Each command should be
detected and executed. The commands are removed from the issue, merge request or on a separate line in order to be properly detected and executed. Once executed,
comment body before it is saved and will not be visible to anyone else. the commands are removed from the text body and not visible to anyone else.
Below is a list of all of the available commands and descriptions about what they ## Quick actions for issues and merge requests
do.
The following quick actions are applicable to both issues and merge requests threads,
| Command | Action | discussions, and descriptions:
|:---------------------------|:-------------|
| `/close` | Close the issue or merge request | | Command | Action | Issue | Merge request |
| `/reopen` | Reopen the issue or merge request | |:---------------------------|:------------------------------ |:------|:--------------|
| `/merge` | Merge (when pipeline succeeds) | | `/tableflip <Comment>` | Append the comment with `(╯°□°)╯︵ ┻━┻` | ✓ | ✓ |
| `/title <New title>` | Change title | | `/shrug <Comment>` | Append the comment with `¯\_(ツ)_/¯` | ✓ | ✓ |
| `/assign @username` | Assign | | `/todo` | Add a todo | ✓ | ✓ |
| `/unassign` | Remove assignee | | `/done` | Mark todo as done | ✓ | ✓ |
| `/milestone %milestone` | Set milestone | | `/subscribe` | Subscribe | ✓ | ✓ |
| `/remove_milestone` | Remove milestone | | `/unsubscribe` | Unsubscribe | ✓ | ✓ |
| `/label ~foo ~"bar baz"` | Add label(s) | | `/close` | Close | ✓ | ✓ |
| `/unlabel ~foo ~"bar baz"` | Remove all or specific label(s) | | `/reopen` | Reopen | ✓ | ✓ |
| `/relabel ~foo ~"bar baz"` | Replace all label(s) | | `/title <New title>` | Change title | ✓ | ✓ |
| `/todo` | Add a todo | | `/award :emoji:` | Toggle emoji award | ✓ | ✓ |
| `/done` | Mark todo as done | | `/assign @user` | Assign one user | ✓ | ✓ |
| `/subscribe` | Subscribe | | `/assign @user1 @user2` | Assign multiple users **[STARTER]** | ✓ | |
| `/unsubscribe` | Unsubscribe | | `/unassign` | Remove assignee(s) | ✓ | ✓ |
| <code>/due &lt;in 2 days &#124; this Friday &#124; December 31st&gt;</code> | Set due date | | `/reassign @user1 @user2` | Change assignee | ✓ | ✓ |
| `/remove_due_date` | Remove due date | | `/milestone %milestone` | Set milestone | ✓ | ✓ |
| `/wip` | Toggle the Work In Progress status | | `/remove_milestone` | Remove milestone | ✓ | ✓ |
| <code>/estimate &lt;1w 3d 2h 14m&gt;</code> | Set time estimate | | `/label ~label1 ~label2` | Add label(s) | ✓ | ✓ |
| `/remove_estimate` | Remove estimated time | | `/unlabel ~label1 ~label2` | Remove all or specific label(s)| ✓ | ✓ |
| <code>/spend &lt;time(1h 30m &#124; -1h 5m)&gt; &lt;date(YYYY-MM-DD)&gt;</code> | Add or subtract spent time; optionally, specify the date that time was spent on | | `/relabel ~label1 ~label2` | Replace label | ✓ | ✓ |
| `/remove_time_spent` | Remove time spent | | <code>/copy_metadata #issue &#124; !merge_request</code> | Copy labels and milestone from other issue or merge request | ✓ | ✓ |
| `/target_branch <Branch Name>` | Set target branch for current merge request | | <code>/estimate &lt;1w 3d 2h 14m&gt;</code> | Set time estimate | ✓ | ✓ |
| `/award :emoji:` | Toggle award for :emoji: | | `/remove_estimate` | Remove time estimate | ✓ | ✓ |
| `/board_move ~column` | Move issue to column on the board | | <code>/spend &lt;time(1h 30m &#124; -1h 5m)&gt; &lt;date(YYYY-MM-DD)&gt;</code> | Add or subtract spent time; optionally, specify the date that time was spent on | ✓ | ✓ |
| `/duplicate #issue` | Closes this issue and marks it as a duplicate of another issue | | `/remove_time_spent` | Remove time spent | ✓ | ✓ |
| `/move path/to/project` | Moves issue to another project | | <code>/due &lt;in 2 days &#124; this Friday &#124; December 31st&gt;</code>| Set due date | ✓ |
| `/tag v1.2.3 <message>` | Tags a commit with a given tag name and optional message | | `/remove_due_date` | Remove due date | ✓ | |
| `/tableflip` | Append the comment with `(╯°□°)╯︵ ┻━┻` | | `/weight 0,1,2, ...` | Set weight **[STARTER]** | ✓ | |
| `/shrug` | Append the comment with `¯\_(ツ)_/¯` | | `/clear_weight` | Clears weight **[STARTER]** | ✓ | |
| <code>/copy_metadata #issue &#124; !merge_request</code> | Copy labels and milestone from other issue or merge request | | `/epic <group&epic &#124; Epic URL>` | Add to epic **[ULTIMATE]** | ✓ | |
| `/confidential` | Makes the issue confidential | | `/remove_epic` | Removes from epic **[ULTIMATE]** | ✓ | |
| `/lock` | Lock the discussion | | `/confidential` | Make confidential | ✓ | |
| `/unlock` | Unlock the discussion | | `/duplicate #issue` | Mark this issue as a duplicate of another issue | ✓ |
| `/move path/to/project` | Move this issue to another project | ✓ | |
| `/target_branch <Local branch Name>` | Set target branch | | ✓ |
| `/wip` | Toggle the Work In Progress status | | ✓ |
| `/merge` | Merge (when pipeline succeeds) | | ✓ |
## Quick actions for commit messages
The following quick actions are applicable for commit messages:
| Command | Action |
|:------------------------|:------------------------------------------|
| `/tag v1.2.3 <message>` | Tags this commit with an optional message |
## Quick actions for Epics **[ULTIMATE]**
The following quick actions are applicable for epics threads and description:
| Command | Action |
|:---------------------------|:----------------------------------------|
| `/tableflip <Comment>` | Append the comment with `(╯°□°)╯︵ ┻━┻` |
| `/shrug <Comment>` | Append the comment with `¯\_(ツ)_/¯` |
| `/todo` | Add a todo |
| `/done` | Mark todo as done |
| `/subscribe` | Subscribe |
| `/unsubscribe` | Unsubscribe |
| `/close` | Close |
| `/reopen` | Reopen |
| `/title <New title>` | Change title |
| `/award :emoji:` | Toggle emoji award |
| `/label ~label1 ~label2` | Add label(s) |
| `/unlabel ~label1 ~label2` | Remove all or specific label(s) |
| `/relabel ~label1 ~label2` | Replace label |
\ No newline at end of file
...@@ -47,4 +47,8 @@ module Gitlab ...@@ -47,4 +47,8 @@ module Gitlab
def self.dev_env_or_com? def self.dev_env_or_com?
Rails.env.development? || org? || com? Rails.env.development? || org? || com?
end end
def self.pre_release?
VERSION.include?('pre')
end
end end
...@@ -11,7 +11,7 @@ module Gitlab ...@@ -11,7 +11,7 @@ module Gitlab
include Validatable include Validatable
include Attributable include Attributable
ALLOWED_KEYS = %i[junit sast dependency_scanning container_scanning dast].freeze ALLOWED_KEYS = %i[junit codequality sast dependency_scanning container_scanning dast].freeze
attributes ALLOWED_KEYS attributes ALLOWED_KEYS
...@@ -21,6 +21,7 @@ module Gitlab ...@@ -21,6 +21,7 @@ module Gitlab
with_options allow_nil: true do with_options allow_nil: true do
validates :junit, array_of_strings_or_string: true validates :junit, array_of_strings_or_string: true
validates :codequality, array_of_strings_or_string: true
validates :sast, array_of_strings_or_string: true validates :sast, array_of_strings_or_string: true
validates :dependency_scanning, array_of_strings_or_string: true validates :dependency_scanning, array_of_strings_or_string: true
validates :container_scanning, array_of_strings_or_string: true validates :container_scanning, array_of_strings_or_string: true
......
...@@ -17,6 +17,12 @@ module Gitlab ...@@ -17,6 +17,12 @@ module Gitlab
kubeclient.create_pod(command.pod_resource) kubeclient.create_pod(command.pod_resource)
end end
def update(command)
namespace.ensure_exists!
update_config_map(command)
kubeclient.create_pod(command.pod_resource)
end
## ##
# Returns Pod phase # Returns Pod phase
# #
...@@ -36,6 +42,12 @@ module Gitlab ...@@ -36,6 +42,12 @@ module Gitlab
kubeclient.delete_pod(pod_name, namespace.name) kubeclient.delete_pod(pod_name, namespace.name)
end end
def get_config_map(config_map_name)
namespace.ensure_exists!
kubeclient.get_config_map(config_map_name, namespace.name)
end
private private
attr_reader :kubeclient, :namespace attr_reader :kubeclient, :namespace
...@@ -46,6 +58,12 @@ module Gitlab ...@@ -46,6 +58,12 @@ module Gitlab
end end
end end
def update_config_map(command)
command.config_map_resource.tap do |config_map_resource|
kubeclient.update_config_map(config_map_resource)
end
end
def create_service_account(command) def create_service_account(command)
command.service_account_resource.tap do |service_account_resource| command.service_account_resource.tap do |service_account_resource|
break unless service_account_resource break unless service_account_resource
......
# frozen_string_literal: true
module Gitlab
module Kubernetes
module Helm
class UpgradeCommand
include BaseCommand
attr_reader :name, :chart, :version, :repository, :files
def initialize(name, chart:, files:, rbac:, version: nil, repository: nil)
@name = name
@chart = chart
@rbac = rbac
@version = version
@files = files
@repository = repository
end
def generate_script
super + [
init_command,
repository_command,
script_command
].compact.join("\n")
end
def rbac?
@rbac
end
def pod_name
"upgrade-#{name}"
end
private
def init_command
'helm init --client-only >/dev/null'
end
def repository_command
"helm repo add #{name} #{repository}" if repository
end
def script_command
upgrade_flags = "#{optional_version_flag}#{optional_tls_flags}" \
" --reset-values" \
" --install" \
" --namespace #{::Gitlab::Kubernetes::Helm::NAMESPACE}" \
" -f /data/helm/#{name}/config/values.yaml"
"helm upgrade #{name} #{chart}#{upgrade_flags} >/dev/null\n"
end
def optional_version_flag
" --version #{version}" if version
end
def optional_tls_flags
return unless files.key?(:'ca.pem')
" --tls" \
" --tls-ca-cert #{files_dir}/ca.pem" \
" --tls-cert #{files_dir}/cert.pem" \
" --tls-key #{files_dir}/key.pem"
end
end
end
end
end
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -236,8 +236,11 @@ module QA ...@@ -236,8 +236,11 @@ module QA
module Admin module Admin
module Settings module Settings
autoload :RepositoryStorage, 'qa/page/admin/settings/repository_storage' autoload :Repository, 'qa/page/admin/settings/repository'
autoload :Main, 'qa/page/admin/settings/main'
module Component
autoload :RepositoryStorage, 'qa/page/admin/settings/component/repository_storage'
end
end end
end end
......
# frozen_string_literal: true
module QA
module Page
module Admin
module Settings
module Component
class RepositoryStorage < Page::Base
view 'app/views/admin/application_settings/_repository_storage.html.haml' do
element :hashed_storage_checkbox
element :save_changes_button
end
def enable_hashed_storage
check_element :hashed_storage_checkbox
end
def save_settings
click_element :save_changes_button
end
end
end
end
end
end
end
# frozen_string_literal: true
module QA module QA
module Page module Page
module Admin module Admin
module Settings module Settings
class Main < Page::Base class Repository < Page::Base
include QA::Page::Settings::Common include QA::Page::Settings::Common
view 'app/views/admin/application_settings/show.html.haml' do view 'app/views/admin/application_settings/repository.html.haml' do
element :terms_settings element :repository_storage_settings
end end
def expand_repository_storage(&block) def expand_repository_storage(&block)
expand_section(:terms_settings) do expand_section(:repository_storage_settings) do
RepositoryStorage.perform(&block) Component::RepositoryStorage.perform(&block)
end end
end end
end end
......
module QA
module Page
module Admin
module Settings
class RepositoryStorage < Page::Base
view 'app/views/admin/application_settings/_repository_storage.html.haml' do
element :submit, "submit 'Save changes'"
element :hashed_storage,
'Use hashed storage paths for newly created and renamed projects'
end
def enable_hashed_storage
check 'Use hashed storage paths for newly created and renamed projects'
end
def save_settings
click_button 'Save changes'
end
end
end
end
end
end
...@@ -68,6 +68,10 @@ module QA ...@@ -68,6 +68,10 @@ module QA
all(element_selector_css(name)) all(element_selector_css(name))
end end
def check_element(name)
find_element(name).set(true)
end
def click_element(name) def click_element(name)
find_element(name).click find_element(name).click
end end
...@@ -86,6 +90,10 @@ module QA ...@@ -86,6 +90,10 @@ module QA
end end
end end
def scroll_to_element(name, *args)
scroll_to(element_selector_css(name), *args)
end
def element_selector_css(name) def element_selector_css(name)
Page::Element.new(name).selector_css Page::Element.new(name).selector_css
end end
......
...@@ -3,11 +3,41 @@ module QA ...@@ -3,11 +3,41 @@ module QA
module Menu module Menu
class Admin < Page::Base class Admin < Page::Base
view 'app/views/layouts/nav/sidebar/_admin.html.haml' do view 'app/views/layouts/nav/sidebar/_admin.html.haml' do
element :settings, "_('Settings')" element :admin_sidebar
element :admin_sidebar_submenu
element :admin_settings_item
element :admin_settings_repository_item
end end
def go_to_settings def go_to_repository_settings
click_link 'Settings' hover_settings do
within_submenu do
click_element :admin_settings_repository_item
end
end
end
private
def hover_settings
within_sidebar do
scroll_to_element(:admin_settings_item)
find_element(:admin_settings_item).hover
yield
end
end
def within_sidebar
within_element(:admin_sidebar) do
yield
end
end
def within_submenu
within_element(:admin_sidebar_submenu) do
yield
end
end end
end end
end end
......
...@@ -30,7 +30,7 @@ describe QA::Page::Validator do ...@@ -30,7 +30,7 @@ describe QA::Page::Validator do
let(:view) { spy('view') } let(:view) { spy('view') }
before do before do
allow(QA::Page::Admin::Settings::Main) allow(QA::Page::Admin::Settings::Repository)
.to receive(:views).and_return([view]) .to receive(:views).and_return([view])
end end
......
...@@ -19,10 +19,42 @@ describe Projects::ArtifactsController do ...@@ -19,10 +19,42 @@ describe Projects::ArtifactsController do
end end
describe 'GET download' do describe 'GET download' do
it 'sends the artifacts file' do subject { get :download, namespace_id: project.namespace, project_id: project, job_id: job, file_type: file_type }
expect(controller).to receive(:send_file).with(job.artifacts_file.path, hash_including(disposition: 'attachment')).and_call_original
get :download, namespace_id: project.namespace, project_id: project, job_id: job context 'when no file type is supplied' do
let(:file_type) { nil }
it 'sends the artifacts file' do
expect(controller).to receive(:send_file).with(job.artifacts_file.path, hash_including(disposition: 'attachment')).and_call_original
subject
end
end
context 'when a file type is supplied' do
context 'when an invalid file type is supplied' do
let(:file_type) { 'invalid' }
it 'returns 404' do
subject
expect(response).to have_gitlab_http_status(404)
end
end
context 'when codequality file type is supplied' do
let(:file_type) { 'codequality' }
before do
create(:ci_job_artifact, :codequality, job: job)
end
it 'sends the codequality report' do
expect(controller).to receive(:send_file).with(job.job_artifacts_codequality.file.path, hash_including(disposition: 'attachment')).and_call_original
subject
end
end
end end
end end
......
...@@ -117,6 +117,16 @@ FactoryBot.define do ...@@ -117,6 +117,16 @@ FactoryBot.define do
end end
end end
trait :codequality do
file_type :codequality
file_format :gzip
after(:build) do |artifact, evaluator|
artifact.file = fixture_file_upload(
Rails.root.join('spec/fixtures/codequality/codequality.json.gz'), 'application/x-gzip')
end
end
trait :correct_checksum do trait :correct_checksum do
after(:build) do |artifact, evaluator| after(:build) do |artifact, evaluator|
artifact.file_sha256 = Digest::SHA256.file(artifact.file.path).hexdigest artifact.file_sha256 = Digest::SHA256.file(artifact.file.path).hexdigest
......
...@@ -22,11 +22,24 @@ FactoryBot.define do ...@@ -22,11 +22,24 @@ FactoryBot.define do
status 3 status 3
end end
trait :updating do
status 4
end
trait :updated do
status 5
end
trait :errored do trait :errored do
status(-1) status(-1)
status_reason 'something went wrong' status_reason 'something went wrong'
end end
trait :update_errored do
status(6)
status_reason 'something went wrong'
end
trait :timeouted do trait :timeouted do
installing installing
updated_at ClusterWaitForAppInstallationWorker::TIMEOUT.ago updated_at ClusterWaitForAppInstallationWorker::TIMEOUT.ago
......
...@@ -13,6 +13,10 @@ FactoryBot.define do ...@@ -13,6 +13,10 @@ FactoryBot.define do
state :opened state :opened
end end
trait :locked do
discussion_locked true
end
trait :closed do trait :closed do
state :closed state :closed
closed_at { Time.now } closed_at { Time.now }
......
...@@ -56,6 +56,24 @@ describe 'Issuables Close/Reopen/Report toggle' do ...@@ -56,6 +56,24 @@ describe 'Issuables Close/Reopen/Report toggle' do
end end
it_behaves_like 'an issuable close/reopen/report toggle' it_behaves_like 'an issuable close/reopen/report toggle'
context 'when the issue is closed and locked' do
let(:issuable) { create(:issue, :closed, :locked, project: project) }
it 'hides the reopen button' do
expect(page).not_to have_link('Reopen issue')
end
context 'when the issue author is the current user' do
before do
issuable.update(author: user)
end
it 'hides the reopen button' do
expect(page).not_to have_link('Reopen issue')
end
end
end
end end
context 'when user doesnt have permission to update' do context 'when user doesnt have permission to update' do
...@@ -93,6 +111,28 @@ describe 'Issuables Close/Reopen/Report toggle' do ...@@ -93,6 +111,28 @@ describe 'Issuables Close/Reopen/Report toggle' do
end end
it_behaves_like 'an issuable close/reopen/report toggle' it_behaves_like 'an issuable close/reopen/report toggle'
context 'when the merge request is merged' do
let(:issuable) { create(:merge_request, :merged, source_project: project) }
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')
end
context 'when the merge request author is the current user' do
let(:issuable) { create(:merge_request, :merged, source_project: project, author: user) }
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')
end
end
end
end end
context 'when user doesnt have permission to update' do context 'when user doesnt have permission to update' do
......
This diff is collapsed.
...@@ -33,6 +33,7 @@ describe Gitlab::Ci::Config::Entry::Reports do ...@@ -33,6 +33,7 @@ describe Gitlab::Ci::Config::Entry::Reports do
where(:keyword, :file) do where(:keyword, :file) do
:junit | 'junit.xml' :junit | 'junit.xml'
:codequality | 'codequality.json'
:sast | 'gl-sast-report.json' :sast | 'gl-sast-report.json'
:dependency_scanning | 'gl-dependency-scanning-report.json' :dependency_scanning | 'gl-dependency-scanning-report.json'
:container_scanning | 'gl-container-scanning-report.json' :container_scanning | 'gl-container-scanning-report.json'
......
...@@ -150,6 +150,43 @@ describe Gitlab::Kubernetes::Helm::Api do ...@@ -150,6 +150,43 @@ describe Gitlab::Kubernetes::Helm::Api do
end end
end end
describe '#update' do
let(:rbac) { false }
let(:command) do
Gitlab::Kubernetes::Helm::UpgradeCommand.new(
application_name,
chart: 'chart-name',
files: files,
rbac: rbac
)
end
before do
allow(namespace).to receive(:ensure_exists!).once
allow(client).to receive(:update_config_map).and_return(nil)
allow(client).to receive(:create_pod).and_return(nil)
end
it 'ensures the namespace exists before creating the pod' do
expect(namespace).to receive(:ensure_exists!).once.ordered
expect(client).to receive(:create_pod).once.ordered
subject.update(command)
end
it 'updates the config map on kubeclient when one exists' do
resource = Gitlab::Kubernetes::ConfigMap.new(
application_name, files
).generate
expect(client).to receive(:update_config_map).with(resource).once
subject.update(command)
end
end
describe '#status' do describe '#status' do
let(:phase) { Gitlab::Kubernetes::Pod::RUNNING } let(:phase) { Gitlab::Kubernetes::Pod::RUNNING }
let(:pod) { Kubeclient::Resource.new(status: { phase: phase }) } # partial representation let(:pod) { Kubeclient::Resource.new(status: { phase: phase }) } # partial representation
...@@ -179,4 +216,25 @@ describe Gitlab::Kubernetes::Helm::Api do ...@@ -179,4 +216,25 @@ describe Gitlab::Kubernetes::Helm::Api do
subject.delete_pod!(command.pod_name) subject.delete_pod!(command.pod_name)
end end
end end
describe '#get_config_map' do
before do
allow(namespace).to receive(:ensure_exists!).once
allow(client).to receive(:get_config_map).and_return(nil)
end
it 'ensures the namespace exists before retrieving the config map' do
expect(namespace).to receive(:ensure_exists!).once
subject.get_config_map('example-config-map-name')
end
it 'gets the config map on kubeclient' do
expect(client).to receive(:get_config_map)
.with('example-config-map-name', namespace.name)
.once
subject.get_config_map('example-config-map-name')
end
end
end end
# frozen_string_literal: true
require 'rails_helper'
describe Gitlab::Kubernetes::Helm::UpgradeCommand do
let(:application) { build(:clusters_applications_prometheus) }
let(:files) { { 'ca.pem': 'some file content' } }
let(:namespace) { ::Gitlab::Kubernetes::Helm::NAMESPACE }
let(:rbac) { false }
let(:upgrade_command) do
described_class.new(
application.name,
chart: application.chart,
files: files,
rbac: rbac
)
end
subject { upgrade_command }
it_behaves_like 'helm commands' do
let(:commands) do
<<~EOS
helm init --client-only >/dev/null
helm upgrade #{application.name} #{application.chart} --tls --tls-ca-cert /data/helm/#{application.name}/config/ca.pem --tls-cert /data/helm/#{application.name}/config/cert.pem --tls-key /data/helm/#{application.name}/config/key.pem --reset-values --install --namespace #{namespace} -f /data/helm/#{application.name}/config/values.yaml >/dev/null
EOS
end
end
context 'rbac is true' do
let(:rbac) { true }
it_behaves_like 'helm commands' do
let(:commands) do
<<~EOS
helm init --client-only >/dev/null
helm upgrade #{application.name} #{application.chart} --tls --tls-ca-cert /data/helm/#{application.name}/config/ca.pem --tls-cert /data/helm/#{application.name}/config/cert.pem --tls-key /data/helm/#{application.name}/config/key.pem --reset-values --install --namespace #{namespace} -f /data/helm/#{application.name}/config/values.yaml >/dev/null
EOS
end
end
end
context 'with an application with a repository' do
let(:ci_runner) { create(:ci_runner) }
let(:application) { build(:clusters_applications_runner, runner: ci_runner) }
let(:upgrade_command) do
described_class.new(
application.name,
chart: application.chart,
files: files,
rbac: rbac,
repository: application.repository
)
end
it_behaves_like 'helm commands' do
let(:commands) do
<<~EOS
helm init --client-only >/dev/null
helm repo add #{application.name} #{application.repository}
helm upgrade #{application.name} #{application.chart} --tls --tls-ca-cert /data/helm/#{application.name}/config/ca.pem --tls-cert /data/helm/#{application.name}/config/cert.pem --tls-key /data/helm/#{application.name}/config/key.pem --reset-values --install --namespace #{namespace} -f /data/helm/#{application.name}/config/values.yaml >/dev/null
EOS
end
end
end
context 'when there is no ca.pem file' do
let(:files) { { 'file.txt': 'some content' } }
it_behaves_like 'helm commands' do
let(:commands) do
<<~EOS
helm init --client-only >/dev/null
helm upgrade #{application.name} #{application.chart} --reset-values --install --namespace #{namespace} -f /data/helm/#{application.name}/config/values.yaml >/dev/null
EOS
end
end
end
describe '#pod_resource' do
subject { upgrade_command.pod_resource }
context 'rbac is enabled' do
let(:rbac) { true }
it 'generates a pod that uses the tiller serviceAccountName' do
expect(subject.spec.serviceAccountName).to eq('tiller')
end
end
context 'rbac is not enabled' do
let(:rbac) { false }
it 'generates a pod that uses the default serviceAccountName' do
expect(subject.spec.serviceAcccountName).to be_nil
end
end
end
describe '#config_map_resource' do
let(:metadata) do
{
name: "values-content-configuration-#{application.name}",
namespace: namespace,
labels: { name: "values-content-configuration-#{application.name}" }
}
end
let(:resource) { ::Kubeclient::Resource.new(metadata: metadata, data: files) }
it 'returns a KubeClient resource with config map content for the application' do
expect(subject.config_map_resource).to eq(resource)
end
end
describe '#rbac?' do
subject { upgrade_command.rbac? }
context 'rbac is enabled' do
let(:rbac) { true }
it { is_expected.to be_truthy }
end
context 'rbac is not enabled' do
let(:rbac) { false }
it { is_expected.to be_falsey }
end
end
describe '#pod_name' do
it 'returns the pod name' do
expect(subject.pod_name).to eq("upgrade-#{application.name}")
end
end
end
...@@ -1433,6 +1433,19 @@ describe Ci::Build do ...@@ -1433,6 +1433,19 @@ describe Ci::Build do
end end
end end
describe '#artifacts_file_for_type' do
let(:build) { create(:ci_build, :artifacts) }
let(:file_type) { :archive }
subject { build.artifacts_file_for_type(file_type) }
it 'queries artifacts for type' do
expect(build).to receive_message_chain(:job_artifacts, :find_by).with(file_type: Ci::JobArtifact.file_types[file_type])
subject
end
end
describe '#merge_request' do describe '#merge_request' do
def create_mr(build, pipeline, factory: :merge_request, created_at: Time.now) def create_mr(build, pipeline, factory: :merge_request, created_at: Time.now)
create(factory, source_project: pipeline.project, create(factory, source_project: pipeline.project,
......
...@@ -34,7 +34,7 @@ describe Ci::JobArtifact do ...@@ -34,7 +34,7 @@ describe Ci::JobArtifact do
describe '.erasable' do describe '.erasable' do
subject { described_class.erasable } subject { described_class.erasable }
context 'when there is am erasable artifact' do context 'when there is an erasable artifact' do
let!(:artifact) { create(:ci_job_artifact, :junit) } let!(:artifact) { create(:ci_job_artifact, :junit) }
it { is_expected.to eq([artifact]) } it { is_expected.to eq([artifact]) }
......
...@@ -112,7 +112,7 @@ describe IssuePolicy do ...@@ -112,7 +112,7 @@ describe IssuePolicy do
let(:project) { create(:project, :public) } let(:project) { create(:project, :public) }
let(:issue) { create(:issue, project: project, assignees: [assignee], author: author) } let(:issue) { create(:issue, project: project, assignees: [assignee], author: author) }
let(:issue_no_assignee) { create(:issue, project: project) } let(:issue_no_assignee) { create(:issue, project: project) }
let(:issue_locked) { create(:issue, project: project, discussion_locked: true, author: author, assignees: [assignee]) } let(:issue_locked) { create(:issue, :locked, project: project, author: author, assignees: [assignee]) }
before do before do
project.add_guest(guest) project.add_guest(guest)
......
...@@ -27,7 +27,7 @@ describe Ci::RetryBuildService do ...@@ -27,7 +27,7 @@ describe Ci::RetryBuildService do
job_artifacts_metadata job_artifacts_trace job_artifacts_junit job_artifacts_metadata job_artifacts_trace job_artifacts_junit
job_artifacts_sast job_artifacts_dependency_scanning job_artifacts_sast job_artifacts_dependency_scanning
job_artifacts_container_scanning job_artifacts_dast job_artifacts_container_scanning job_artifacts_dast
scheduled_at].freeze job_artifacts_codequality scheduled_at].freeze
IGNORE_ACCESSORS = IGNORE_ACCESSORS =
%i[type lock_version target_url base_tags trace_sections %i[type lock_version target_url base_tags trace_sections
......
# frozen_string_literal: true
module StubVersion
def stub_version(version, revision)
stub_const('Gitlab::VERSION', version)
allow(Gitlab).to receive(:revision).and_return(revision)
end
end
# frozen_string_literal: true
require 'rails_helper' require 'rails_helper'
describe 'help/index' do describe 'help/index' do
include StubVersion
describe 'version information' do describe 'version information' do
before do
stub_helpers
end
it 'is hidden from guests' do it 'is hidden from guests' do
stub_user(nil) stub_user(nil)
stub_version('8.0.2', 'abcdefg') stub_version('8.0.2', 'abcdefg')
stub_helpers
render render
...@@ -13,15 +20,28 @@ describe 'help/index' do ...@@ -13,15 +20,28 @@ describe 'help/index' do
expect(rendered).not_to match 'abcdefg' expect(rendered).not_to match 'abcdefg'
end end
it 'is shown to users' do context 'when logged in' do
stub_user before do
stub_version('8.0.2', 'abcdefg') stub_user
stub_helpers end
render it 'shows a link to the tag to users' do
stub_version('8.0.2', 'abcdefg')
render
expect(rendered).to match '8.0.2'
expect(rendered).to have_link('8.0.2', href: %r{https://gitlab.com/gitlab-org/gitlab-(ce|ee)/tags/v8.0.2})
end
it 'shows a link to the commit for pre-releases' do
stub_version('8.0.2-pre', 'abcdefg')
expect(rendered).to match '8.0.2' render
expect(rendered).to have_link('8.0.2', href: 'https://gitlab.com/gitlab-org/gitlab-ce/tags/v8.0.2')
expect(rendered).to match '8.0.2'
expect(rendered).to have_link('abcdefg', href: %r{https://gitlab.com/gitlab-org/gitlab-(ce|ee)/commits/abcdefg})
end
end end
end end
...@@ -37,11 +57,6 @@ describe 'help/index' do ...@@ -37,11 +57,6 @@ describe 'help/index' do
allow(view).to receive(:user_signed_in?).and_return(user) allow(view).to receive(:user_signed_in?).and_return(user)
end end
def stub_version(version, revision)
stub_const('Gitlab::VERSION', version)
allow(Gitlab).to receive(:revision).and_return(revision)
end
def stub_helpers def stub_helpers
allow(view).to receive(:markdown).and_return('') allow(view).to receive(:markdown).and_return('')
allow(view).to receive(:version_status_badge).and_return('') allow(view).to receive(:version_status_badge).and_return('')
......
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