Commit 83ad5de6 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'master' into fl-eslint-vue-house-keeping

* master: (47 commits)
  Bumping gitlab-gollum-lib and gitlab-gollum-rugged_adapter
  i18n: document how to use links without splitting sentences
  Resolve "[Rails5] `ActionView::MissingTemplate` in spec/features/projects/wiki/user_views_wiki_page_spec.rb"
  Add CI job to check Gemfile.rails5.lock
  Add navigation theme documentation
  Move Gitaly branch/tag/ref RPC's to opt-out
  Add CI_{PIPELINE,JOB}_URL
  Resolve "Update docs as GKE cluster creation label has changed from "project ID" to "project""
  fixed/enhanced command-line documentation
  Use nip.io instead of xip.io
  [Rails5] Update Gitlab.rails5.lock
  Fix typo in doc/development/README.md
  Update import screenshot without LFS warning
  Hide overflow on hr
  Resolve "Milestone and labels dropdowns are misplaced with collapsed sidebar"
  Fix collapse sidebar button color
  Remove .row and .col-sm-12
  Relax expectation in spec/models/project_spec.rb
  fix padding in commit info
  GitHub Rake importer: Fail with a clearer explanation if GitLab username is wrong
  ...
parents 7f570348 d94b1621
...@@ -415,6 +415,7 @@ setup-test-env: ...@@ -415,6 +415,7 @@ setup-test-env:
script: script:
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init' - bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
- scripts/gitaly-test-build # Do not use 'bundle exec' here - scripts/gitaly-test-build # Do not use 'bundle exec' here
- BUNDLE_GEMFILE=Gemfile.rails5 bundle install $BUNDLE_INSTALL_FLAGS
artifacts: artifacts:
expire_in: 7d expire_in: 7d
paths: paths:
...@@ -590,6 +591,12 @@ downtime_check: ...@@ -590,6 +591,12 @@ downtime_check:
- /(^docs[\/-].*|.*-docs$)/ - /(^docs[\/-].*|.*-docs$)/
- /(^qa[\/-].*|.*-qa$)/ - /(^qa[\/-].*|.*-qa$)/
rails5_gemfile_lock_check:
<<: *dedicated-no-docs-no-db-pull-cache-job
<<: *except-docs-and-qa
script:
- scripts/rails5-gemfile-lock-check
ee_compat_check: ee_compat_check:
<<: *rake-exec <<: *rake-exec
except: except:
......
...@@ -296,7 +296,7 @@ GEM ...@@ -296,7 +296,7 @@ GEM
flowdock (~> 0.7) flowdock (~> 0.7)
gitlab-grit (>= 2.4.1) gitlab-grit (>= 2.4.1)
multi_json multi_json
gitlab-gollum-lib (4.2.7.2) gitlab-gollum-lib (4.2.7.4)
gemojione (~> 3.2) gemojione (~> 3.2)
github-markup (~> 1.6) github-markup (~> 1.6)
gollum-grit_adapter (~> 1.0) gollum-grit_adapter (~> 1.0)
...@@ -304,7 +304,7 @@ GEM ...@@ -304,7 +304,7 @@ GEM
rouge (~> 3.1) rouge (~> 3.1)
sanitize (~> 2.1) sanitize (~> 2.1)
stringex (~> 2.6) stringex (~> 2.6)
gitlab-gollum-rugged_adapter (0.4.4) gitlab-gollum-rugged_adapter (0.4.4.1)
mime-types (>= 1.15) mime-types (>= 1.15)
rugged (~> 0.25) rugged (~> 0.25)
gitlab-grit (2.8.2) gitlab-grit (2.8.2)
......
...@@ -315,7 +315,7 @@ GEM ...@@ -315,7 +315,7 @@ GEM
diff-lcs (~> 1.1) diff-lcs (~> 1.1)
mime-types (>= 1.16) mime-types (>= 1.16)
posix-spawn (~> 0.3) posix-spawn (~> 0.3)
gitlab-markup (1.6.3) gitlab-markup (1.6.4)
gitlab-styles (2.3.2) gitlab-styles (2.3.2)
rubocop (~> 0.51) rubocop (~> 0.51)
rubocop-gitlab-security (~> 0.1.0) rubocop-gitlab-security (~> 0.1.0)
...@@ -751,36 +751,36 @@ GEM ...@@ -751,36 +751,36 @@ GEM
chunky_png chunky_png
rqrcode-rails3 (0.1.7) rqrcode-rails3 (0.1.7)
rqrcode (>= 0.4.2) rqrcode (>= 0.4.2)
rspec (3.6.0) rspec (3.7.0)
rspec-core (~> 3.6.0) rspec-core (~> 3.7.0)
rspec-expectations (~> 3.6.0) rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.6.0) rspec-mocks (~> 3.7.0)
rspec-core (3.6.0) rspec-core (3.7.1)
rspec-support (~> 3.6.0) rspec-support (~> 3.7.0)
rspec-expectations (3.6.0) rspec-expectations (3.7.0)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.6.0) rspec-support (~> 3.7.0)
rspec-mocks (3.6.0) rspec-mocks (3.7.0)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.6.0) rspec-support (~> 3.7.0)
rspec-parameterized (0.4.0) rspec-parameterized (0.4.0)
binding_of_caller binding_of_caller
parser parser
proc_to_ast proc_to_ast
rspec (>= 2.13, < 4) rspec (>= 2.13, < 4)
unparser unparser
rspec-rails (3.6.0) rspec-rails (3.7.2)
actionpack (>= 3.0) actionpack (>= 3.0)
activesupport (>= 3.0) activesupport (>= 3.0)
railties (>= 3.0) railties (>= 3.0)
rspec-core (~> 3.6.0) rspec-core (~> 3.7.0)
rspec-expectations (~> 3.6.0) rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.6.0) rspec-mocks (~> 3.7.0)
rspec-support (~> 3.6.0) rspec-support (~> 3.7.0)
rspec-retry (0.4.5) rspec-retry (0.4.5)
rspec-core rspec-core
rspec-set (0.1.3) rspec-set (0.1.3)
rspec-support (3.6.0) rspec-support (3.7.1)
rspec_profiling (0.0.5) rspec_profiling (0.0.5)
activerecord activerecord
pg pg
...@@ -1054,7 +1054,7 @@ DEPENDENCIES ...@@ -1054,7 +1054,7 @@ DEPENDENCIES
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-gollum-lib (~> 4.2) gitlab-gollum-lib (~> 4.2)
gitlab-gollum-rugged_adapter (~> 0.4.4) gitlab-gollum-rugged_adapter (~> 0.4.4)
gitlab-markup (~> 1.6.2) gitlab-markup (~> 1.6.4)
gitlab-styles (~> 2.3) gitlab-styles (~> 2.3)
gitlab_omniauth-ldap (~> 2.0.4) gitlab_omniauth-ldap (~> 2.0.4)
gon (~> 6.2) gon (~> 6.2)
...@@ -1152,7 +1152,7 @@ DEPENDENCIES ...@@ -1152,7 +1152,7 @@ DEPENDENCIES
rouge (~> 3.1) rouge (~> 3.1)
rqrcode-rails3 (~> 0.1.7) rqrcode-rails3 (~> 0.1.7)
rspec-parameterized rspec-parameterized
rspec-rails (~> 3.6.0) rspec-rails (~> 3.7.0)
rspec-retry (~> 0.4.5) rspec-retry (~> 0.4.5)
rspec-set (~> 0.1.3) rspec-set (~> 0.1.3)
rspec_profiling (~> 0.0.5) rspec_profiling (~> 0.0.5)
......
...@@ -185,11 +185,7 @@ next patch release. ...@@ -185,11 +185,7 @@ next patch release.
If a merge request is to be picked into more than one release it will need one If a merge request is to be picked into more than one release it will need one
`Pick into X.Y` label per release where the merge request should be back-ported `Pick into X.Y` label per release where the merge request should be back-ported
to. to. For example:
For example, if the current patch release is `10.1.1` and a regression fix needs
to be backported down to the `9.5` release, you will need to assign it the
`10.1` milestone and the following labels:
- `Pick into 10.1` - `Pick into 10.1`
- `Pick into 10.0` - `Pick into 10.0`
......
...@@ -8,4 +8,5 @@ export default { ...@@ -8,4 +8,5 @@ export default {
OK: 200, OK: 200,
MULTIPLE_CHOICES: 300, MULTIPLE_CHOICES: 300,
BAD_REQUEST: 400, BAD_REQUEST: 400,
NOT_FOUND: 404,
}; };
...@@ -89,6 +89,10 @@ a { ...@@ -89,6 +89,10 @@ a {
color: $gl-link-color; color: $gl-link-color;
} }
hr {
overflow: hidden;
}
.form-group.row .col-form-label { .form-group.row .col-form-label {
// Bootstrap 4 aligns labels to the left // Bootstrap 4 aligns labels to the left
// for horizontal forms // for horizontal forms
...@@ -209,6 +213,10 @@ table { ...@@ -209,6 +213,10 @@ table {
border-bottom: 1px solid $well-inner-border; border-bottom: 1px solid $well-inner-border;
} }
} }
.badge.badge-gray {
background-color: $well-expand-item;
}
} }
.card { .card {
...@@ -258,9 +266,17 @@ pre code { ...@@ -258,9 +266,17 @@ pre code {
.alert-danger { .alert-danger {
background-color: $red-500; background-color: $red-500;
border-color: $red-500; border-color: $red-500;
}
.alert-warning,
.alert-danger,
.flash-notice {
border-radius: 0;
color: $white-light; color: $white-light;
h4 { h4,
a,
.alert-link {
color: $white-light; color: $white-light;
} }
} }
...@@ -268,3 +284,11 @@ pre code { ...@@ -268,3 +284,11 @@ pre code {
input[type=color].form-control { input[type=color].form-control {
height: $input-height; height: $input-height;
} }
.toggle-sidebar-button {
.collapse-text,
.icon-angle-double-left,
.icon-angle-double-right {
color: $gl-text-color-secondary;
}
}
...@@ -305,14 +305,6 @@ img.emoji { ...@@ -305,14 +305,6 @@ img.emoji {
margin-bottom: 10px; margin-bottom: 10px;
} }
.btn-sign-in {
text-shadow: none;
@include media-breakpoint-up(sm) {
margin-top: 8px;
}
}
.side-filters { .side-filters {
fieldset { fieldset {
margin-bottom: 15px; margin-bottom: 15px;
......
...@@ -170,7 +170,7 @@ label { ...@@ -170,7 +170,7 @@ label {
} }
.form-control::-webkit-input-placeholder { .form-control::-webkit-input-placeholder {
color: $gl-text-color-secondary; color: $placeholder-text-color;
} }
.input-group { .input-group {
......
...@@ -447,12 +447,16 @@ ...@@ -447,12 +447,16 @@
.btn-sign-in { .btn-sign-in {
background-color: $indigo-100; background-color: $indigo-100;
color: $indigo-900; color: $indigo-900;
margin-top: 3px;
font-weight: $gl-font-weight-bold; font-weight: $gl-font-weight-bold;
line-height: 18px;
&:hover { &:hover {
background-color: $white-light; background-color: $white-light;
} }
@include media-breakpoint-down(xs) {
margin-top: $gl-padding-4;
}
} }
.navbar-nav { .navbar-nav {
......
...@@ -4,3 +4,11 @@ ...@@ -4,3 +4,11 @@
text-decoration: none; text-decoration: none;
} }
} }
.page-item {
&.active {
.page-link {
z-index: 3;
}
}
}
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
padding: 0; padding: 0;
&::before { &::before {
@include notes-media('max', map-get($grid-breakpoints, xs)) { @include notes-media('max', map-get($grid-breakpoints, sm)) {
background: none; background: none;
} }
} }
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
.timeline-entry-inner { .timeline-entry-inner {
position: relative; position: relative;
@include notes-media('max', map-get($grid-breakpoints, xs)) { @include notes-media('max', map-get($grid-breakpoints, sm)) {
.timeline-icon { .timeline-icon {
display: none; display: none;
} }
......
...@@ -99,7 +99,7 @@ $theme-gray-200: #dfdfdf; ...@@ -99,7 +99,7 @@ $theme-gray-200: #dfdfdf;
$theme-gray-300: #cccccc; $theme-gray-300: #cccccc;
$theme-gray-400: #bababa; $theme-gray-400: #bababa;
$theme-gray-500: #a7a7a7; $theme-gray-500: #a7a7a7;
$theme-gray-600: #949494; $theme-gray-600: #919191;
$theme-gray-700: #707070; $theme-gray-700: #707070;
$theme-gray-800: #4f4f4f; $theme-gray-800: #4f4f4f;
$theme-gray-900: #2e2e2e; $theme-gray-900: #2e2e2e;
...@@ -191,7 +191,7 @@ $gl-font-weight-normal: 400; ...@@ -191,7 +191,7 @@ $gl-font-weight-normal: 400;
$gl-font-weight-bold: 600; $gl-font-weight-bold: 600;
$gl-text-color: #2e2e2e; $gl-text-color: #2e2e2e;
$gl-text-color-secondary: #707070; $gl-text-color-secondary: #707070;
$gl-text-color-tertiary: #949494; $gl-text-color-tertiary: #919191;
$gl-text-color-quaternary: #d6d6d6; $gl-text-color-quaternary: #d6d6d6;
$gl-text-color-inverted: rgba(255, 255, 255, 1); $gl-text-color-inverted: rgba(255, 255, 255, 1);
$gl-text-color-secondary-inverted: rgba(255, 255, 255, 0.85); $gl-text-color-secondary-inverted: rgba(255, 255, 255, 0.85);
...@@ -434,6 +434,22 @@ $gl-btn-horz-padding: 12px; ...@@ -434,6 +434,22 @@ $gl-btn-horz-padding: 12px;
$badge-bg: rgba(0, 0, 0, 0.07); $badge-bg: rgba(0, 0, 0, 0.07);
$badge-color: $gl-text-color-secondary; $badge-color: $gl-text-color-secondary;
/*
* Pagination
*/
$pagination-padding-y: 6px;
$pagination-padding-x: 16px;
$pagination-line-height: 20px;
$pagination-border-color: $border-color;
$pagination-active-bg: $blue-600;
$pagination-active-border-color: $blue-600;
$pagination-hover-bg: $blue-50;
$pagination-hover-border-color: $border-color;
$pagination-hover-color: $gl-text-color;
$pagination-disabled-color: #cdcdcd;
$pagination-disabled-bg: $gray-light;
$pagination-disabled-border-color: $border-color;
/* /*
* Status icons * Status icons
*/ */
......
...@@ -1129,7 +1129,7 @@ ...@@ -1129,7 +1129,7 @@
.ide-context-header { .ide-context-header {
.avatar { .avatar {
flex: 0 0 40px; flex: 0 0 38px;
} }
.ide-merge-requests-dropdown.dropdown-menu { .ide-merge-requests-dropdown.dropdown-menu {
......
...@@ -29,7 +29,7 @@ input[type="checkbox"]:hover { ...@@ -29,7 +29,7 @@ input[type="checkbox"]:hover {
} }
.search { .search {
margin: 4px 8px 0; margin: 0 8px;
form { form {
@extend .form-control; @extend .form-control;
......
...@@ -611,6 +611,7 @@ module Ci ...@@ -611,6 +611,7 @@ module Ci
variables variables
.concat(pipeline.persisted_variables) .concat(pipeline.persisted_variables)
.append(key: 'CI_JOB_ID', value: id.to_s) .append(key: 'CI_JOB_ID', value: id.to_s)
.append(key: 'CI_JOB_URL', value: Gitlab::Routing.url_helpers.project_job_url(project, self))
.append(key: 'CI_JOB_TOKEN', value: token, public: false) .append(key: 'CI_JOB_TOKEN', value: token, public: false)
.append(key: 'CI_BUILD_ID', value: id.to_s) .append(key: 'CI_BUILD_ID', value: id.to_s)
.append(key: 'CI_BUILD_TOKEN', value: token, public: false) .append(key: 'CI_BUILD_TOKEN', value: token, public: false)
......
...@@ -549,7 +549,10 @@ module Ci ...@@ -549,7 +549,10 @@ module Ci
def persisted_variables def persisted_variables
Gitlab::Ci::Variables::Collection.new.tap do |variables| Gitlab::Ci::Variables::Collection.new.tap do |variables|
variables.append(key: 'CI_PIPELINE_ID', value: id.to_s) if persisted? break variables unless persisted?
variables.append(key: 'CI_PIPELINE_ID', value: id.to_s)
variables.append(key: 'CI_PIPELINE_URL', value: Gitlab::Routing.url_helpers.project_pipeline_url(project, self))
end end
end end
......
...@@ -1616,6 +1616,7 @@ class Project < ActiveRecord::Base ...@@ -1616,6 +1616,7 @@ class Project < ActiveRecord::Base
def after_import def after_import
repository.after_import repository.after_import
wiki.repository.after_import
import_finish import_finish
remove_import_jid remove_import_jid
update_project_counter_caches update_project_counter_caches
...@@ -2139,10 +2140,14 @@ class Project < ActiveRecord::Base ...@@ -2139,10 +2140,14 @@ class Project < ActiveRecord::Base
check_access = -> do check_access = -> do
next false if empty_repo? next false if empty_repo?
merge_request = source_of_merge_requests.opened merge_requests = source_of_merge_requests.opened
.where(allow_collaboration: true) .where(allow_collaboration: true)
.find_by(source_branch: branch_name)
merge_request&.can_be_merged_by?(user) if branch_name
merge_requests.find_by(source_branch: branch_name)&.can_be_merged_by?(user)
else
merge_requests.any? { |merge_request| merge_request.can_be_merged_by?(user) }
end
end end
if RequestStore.active? if RequestStore.active?
......
...@@ -22,10 +22,10 @@ module ObjectStorage ...@@ -22,10 +22,10 @@ module ObjectStorage
module RecordsUploads module RecordsUploads
extend ActiveSupport::Concern extend ActiveSupport::Concern
def prepended(base) prepended do |base|
raise "#{base} must include ObjectStorage::Concern to use extensions." unless base < Concern raise "#{base} must include ObjectStorage::Concern to use extensions." unless base < Concern
base.include(RecordsUploads::Concern) base.include(::RecordsUploads::Concern)
end end
def retrieve_from_store!(identifier) def retrieve_from_store!(identifier)
......
...@@ -43,5 +43,6 @@ ...@@ -43,5 +43,6 @@
%span.toggle-icon %span.toggle-icon
= sprite_icon('status_success_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-checked') = sprite_icon('status_success_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-checked')
= sprite_icon('status_failed_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-unchecked') = sprite_icon('status_failed_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-unchecked')
= render_if_exists 'ci/variables/environment_scope', form_field: form_field, variable: variable
%button.js-row-remove-button.ci-variable-row-remove-button{ type: 'button', 'aria-label': s_('CiVariables|Remove variable row') } %button.js-row-remove-button.ci-variable-row-remove-button{ type: 'button', 'aria-label': s_('CiVariables|Remove variable row') }
= icon('minus-circle') = icon('minus-circle')
...@@ -37,6 +37,6 @@ ...@@ -37,6 +37,6 @@
.form-group .form-group
= file_field_tag :file, class: '' = file_field_tag :file, class: ''
.row .row
.form-actions .form-actions.col-sm-12
= submit_tag 'Import project', class: 'btn btn-create' = submit_tag 'Import project', class: 'btn btn-create'
= link_to 'Cancel', new_project_path, class: 'btn btn-cancel' = link_to 'Cancel', new_project_path, class: 'btn btn-cancel'
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
- if header_link?(:sign_in) - if header_link?(:sign_in)
%li.nav-item %li.nav-item
%div %div
= link_to "Sign in / Register", new_session_path(:user, redirect_to_referer: 'yes'), class: 'nav-link btn btn-sign-in' = link_to "Sign in / Register", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in'
%button.navbar-toggler.d-block.d-sm-none{ type: 'button' } %button.navbar-toggler.d-block.d-sm-none{ type: 'button' }
%span.sr-only Toggle navigation %span.sr-only Toggle navigation
......
...@@ -20,11 +20,11 @@ ...@@ -20,11 +20,11 @@
%span{ "aria-hidden": true } &times; %span{ "aria-hidden": true } &times;
.modal-body .modal-body
- if description - if description
%p.append-bottom-20= description %p= description
= form_tag [type.underscore, @project.namespace.becomes(Namespace), @project, commit], method: :post, remote: false, class: "js-#{type}-form js-requires-input" do = form_tag [type.underscore, @project.namespace.becomes(Namespace), @project, commit], method: :post, remote: false, class: "js-#{type}-form js-requires-input" do
.form-group.row.branch .form-group.branch
= label_tag 'start_branch', branch_label, class: 'col-form-label col-sm-2' = label_tag 'start_branch', branch_label, class: 'label-light'
.col-sm-10
= hidden_field_tag :start_branch, @project.default_branch, id: 'start_branch' = hidden_field_tag :start_branch, @project.default_branch, id: 'start_branch'
= dropdown_tag(@project.default_branch, options: { title: s_("BranchSwitcherTitle|Switch branch"), filter: true, placeholder: s_("BranchSwitcherPlaceholder|Search branches"), toggle_class: 'js-project-refs-dropdown dynamic', dropdown_class: 'dropdown-menu-selectable', data: { field_name: "start_branch", selected: @project.default_branch, start_branch: @project.default_branch, refs_url: project_branches_path(@project), submit_form_on_click: false } }) = dropdown_tag(@project.default_branch, options: { title: s_("BranchSwitcherTitle|Switch branch"), filter: true, placeholder: s_("BranchSwitcherPlaceholder|Search branches"), toggle_class: 'js-project-refs-dropdown dynamic', dropdown_class: 'dropdown-menu-selectable', data: { field_name: "start_branch", selected: @project.default_branch, start_branch: @project.default_branch, refs_url: project_branches_path(@project), submit_form_on_click: false } })
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
- if @branches.any? || @tags.any? || @tags_limit_exceeded - if @branches.any? || @tags.any? || @tags_limit_exceeded
%span %span
= link_to "#", class: "js-details-expand label label-gray ref-name" do = link_to "#", class: "js-details-expand badge badge-gray ref-name" do
= sprite_icon('ellipsis_h', size: 12, css_class: 'vertical-align-middle') = sprite_icon('ellipsis_h', size: 12, css_class: 'vertical-align-middle')
%span.js-details-content.hide %span.js-details-content.hide
= commit_branches_links(@project, @branches) = commit_branches_links(@project, @branches)
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
= form_for(@release, method: :put, url: project_tag_release_path(@project, @tag.name), html: { class: 'common-note-form release-form js-quick-submit' }) do |f| = form_for(@release, method: :put, url: project_tag_release_path(@project, @tag.name), html: { class: 'common-note-form release-form js-quick-submit' }) do |f|
= render layout: 'projects/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do = render layout: 'projects/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do
= render 'projects/zen', f: f, attr: :description, classes: 'note-textarea', placeholder: "Write your release notes or drag files here..." = render 'projects/zen', f: f, attr: :description, classes: 'note-textarea', placeholder: "Write your release notes or drag files here"
= render 'shared/notes/hints' = render 'shared/notes/hints'
.error-alert .error-alert
.prepend-top-default .prepend-top-default
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
= label_tag :release_description, s_('TagsPage|Release notes'), class: 'col-form-label col-sm-2' = label_tag :release_description, s_('TagsPage|Release notes'), class: 'col-form-label col-sm-2'
.col-sm-10 .col-sm-10
= render layout: 'projects/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do = render layout: 'projects/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do
= render 'projects/zen', attr: :release_description, classes: 'note-textarea', placeholder: s_('TagsPage|Write your release notes or drag files here...'), current_text: @release_description = render 'projects/zen', attr: :release_description, classes: 'note-textarea', placeholder: s_('TagsPage|Write your release notes or drag files here'), current_text: @release_description
= render 'shared/notes/hints' = render 'shared/notes/hints'
.form-text.text-muted .form-text.text-muted
= s_('TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page.') = s_('TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page.')
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
.col-sm-12= f.label :content, class: 'control-label-full-width' .col-sm-12= f.label :content, class: 'control-label-full-width'
.col-sm-12 .col-sm-12
= render layout: 'projects/md_preview', locals: { url: project_wiki_preview_markdown_path(@project, @page.slug) } do = render layout: 'projects/md_preview', locals: { url: project_wiki_preview_markdown_path(@project, @page.slug) } do
= render 'projects/zen', f: f, attr: :content, classes: 'note-textarea', placeholder: s_("WikiPage|Write your content or drag files here...") = render 'projects/zen', f: f, attr: :content, classes: 'note-textarea', placeholder: s_("WikiPage|Write your content or drag files here")
= render 'shared/notes/hints' = render 'shared/notes/hints'
.clearfix .clearfix
......
.form-check .form-check.prepend-top-8
- nonce = SecureRandom.hex - nonce = SecureRandom.hex
= check_box_tag 'create_merge_request', 1, true, class: 'js-create-merge-request form-check-input', id: "create_merge_request-#{nonce}" = check_box_tag 'create_merge_request', 1, true, class: 'js-create-merge-request form-check-input', id: "create_merge_request-#{nonce}"
= label_tag "create_merge_request-#{nonce}", class: 'form-check-label' do = label_tag "create_merge_request-#{nonce}", class: 'form-check-label' do
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
= render layout: 'projects/md_preview', locals: { url: preview_url, referenced_users: true } do = render layout: 'projects/md_preview', locals: { url: preview_url, referenced_users: true } do
= render 'projects/zen', f: form, attr: :description, = render 'projects/zen', f: form, attr: :description,
classes: 'note-textarea qa-issuable-form-description', classes: 'note-textarea qa-issuable-form-description',
placeholder: "Write a comment or drag your files here...", placeholder: "Write a comment or drag your files here",
supports_quick_actions: supports_quick_actions supports_quick_actions: supports_quick_actions
= render 'shared/notes/hints', supports_quick_actions: supports_quick_actions = render 'shared/notes/hints', supports_quick_actions: supports_quick_actions
.clearfix .clearfix
......
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
.selectbox.hide-collapsed .selectbox.hide-collapsed
= f.hidden_field 'milestone_id', value: issuable.milestone_id, id: nil = f.hidden_field 'milestone_id', value: issuable.milestone_id, id: nil
= dropdown_tag('Milestone', options: { title: _('Assign milestone'), toggle_class: 'js-milestone-select js-extra-options', filter: true, dropdown_class: 'dropdown-menu-selectable', placeholder: _('Search milestones'), data: { show_no: true, field_name: "#{issuable.to_ability_name}[milestone_id]", project_id: @project.id, issuable_id: issuable.id, milestones: project_milestones_path(@project, :json), ability_name: issuable.to_ability_name, issue_update: issuable_json_path(issuable), use_id: true, default_no: true, selected: (issuable.milestone.name if issuable.milestone), null_default: true }}) = dropdown_tag('Milestone', options: { title: _('Assign milestone'), toggle_class: 'js-milestone-select js-extra-options', filter: true, dropdown_class: 'dropdown-menu-selectable', placeholder: _('Search milestones'), data: { show_no: true, field_name: "#{issuable.to_ability_name}[milestone_id]", project_id: @project.id, issuable_id: issuable.id, milestones: project_milestones_path(@project, :json), ability_name: issuable.to_ability_name, issue_update: issuable_json_path(issuable), use_id: true, default_no: true, selected: (issuable.milestone.name if issuable.milestone), null_default: true, display: 'static' }})
- if issuable.has_attribute?(:time_estimate) - if issuable.has_attribute?(:time_estimate)
#issuable-time-tracker.block #issuable-time-tracker.block
// Fallback while content is loading // Fallback while content is loading
...@@ -77,7 +77,7 @@ ...@@ -77,7 +77,7 @@
.selectbox.hide-collapsed .selectbox.hide-collapsed
= f.hidden_field :due_date, value: issuable.due_date.try(:strftime, 'yy-mm-dd') = f.hidden_field :due_date, value: issuable.due_date.try(:strftime, 'yy-mm-dd')
.dropdown .dropdown
%button.dropdown-menu-toggle.js-due-date-select{ type: 'button', data: { toggle: 'dropdown', field_name: "#{issuable.to_ability_name}[due_date]", ability_name: issuable.to_ability_name, issue_update: issuable_json_path(issuable) } } %button.dropdown-menu-toggle.js-due-date-select{ type: 'button', data: { toggle: 'dropdown', field_name: "#{issuable.to_ability_name}[due_date]", ability_name: issuable.to_ability_name, issue_update: issuable_json_path(issuable), display: 'static' } }
%span.dropdown-toggle-text %span.dropdown-toggle-text
= _('Due date') = _('Due date')
= icon('chevron-down', 'aria-hidden': 'true') = icon('chevron-down', 'aria-hidden': 'true')
...@@ -109,7 +109,7 @@ ...@@ -109,7 +109,7 @@
- selected_labels.each do |label| - selected_labels.each do |label|
= hidden_field_tag "#{issuable.to_ability_name}[label_names][]", label.id, id: nil = hidden_field_tag "#{issuable.to_ability_name}[label_names][]", label.id, id: nil
.dropdown .dropdown
%button.dropdown-menu-toggle.js-label-select.js-multiselect.js-label-sidebar-dropdown{ type: "button", data: {toggle: "dropdown", default_label: "Labels", field_name: "#{issuable.to_ability_name}[label_names][]", ability_name: issuable.to_ability_name, show_no: "true", show_any: "true", namespace_path: @project.try(:namespace).try(:full_path), project_path: @project.try(:path), issue_update: issuable_json_path(issuable), labels: (labels_filter_path(false) if @project) } } %button.dropdown-menu-toggle.js-label-select.js-multiselect.js-label-sidebar-dropdown{ type: "button", data: {toggle: "dropdown", default_label: "Labels", field_name: "#{issuable.to_ability_name}[label_names][]", ability_name: issuable.to_ability_name, show_no: "true", show_any: "true", namespace_path: @project.try(:namespace).try(:full_path), project_path: @project.try(:path), issue_update: issuable_json_path(issuable), labels: (labels_filter_path(false) if @project), display: 'static' } }
%span.dropdown-toggle-text{ class: ("is-default" if selected_labels.empty?) } %span.dropdown-toggle-text{ class: ("is-default" if selected_labels.empty?) }
= multi_label_name(selected_labels, "Labels") = multi_label_name(selected_labels, "Labels")
= icon('chevron-down', 'aria-hidden': 'true') = icon('chevron-down', 'aria-hidden': 'true')
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
- issuable.assignees.each do |assignee| - issuable.assignees.each do |assignee|
= hidden_field_tag "#{issuable.to_ability_name}[assignee_ids][]", assignee.id, id: nil, data: { avatar_url: assignee.avatar_url, name: assignee.name, username: assignee.username } = hidden_field_tag "#{issuable.to_ability_name}[assignee_ids][]", assignee.id, id: nil, data: { avatar_url: assignee.avatar_url, name: assignee.name, username: assignee.username }
- options = { toggle_class: 'js-user-search js-author-search', title: _('Assign to'), filter: true, dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author', placeholder: _('Search users'), data: { first_user: current_user&.username, current_user: true, project_id: @project&.id, author_id: issuable.author_id, field_name: "#{issuable.to_ability_name}[assignee_ids][]", issue_update: issuable_json_path(issuable), ability_name: issuable.to_ability_name, null_user: true } } - options = { toggle_class: 'js-user-search js-author-search', title: _('Assign to'), filter: true, dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author', placeholder: _('Search users'), data: { first_user: current_user&.username, current_user: true, project_id: @project&.id, author_id: issuable.author_id, field_name: "#{issuable.to_ability_name}[assignee_ids][]", issue_update: issuable_json_path(issuable), ability_name: issuable.to_ability_name, null_user: true, display: 'static' } }
- title = _('Select assignee') - title = _('Select assignee')
- if issuable.is_a?(Issue) - if issuable.is_a?(Issue)
......
...@@ -7,11 +7,11 @@ ...@@ -7,11 +7,11 @@
%hr %hr
.form-group .form-group.row
.col-form-label %label.col-form-label.col-sm-2
= _('Contribution') = _('Contribution')
.col-sm-10 .col-sm-10
.form-check .form-check.prepend-top-5
= form.check_box :allow_collaboration, disabled: !issuable.can_allow_collaboration?(current_user), class: 'form-check-input' = form.check_box :allow_collaboration, disabled: !issuable.can_allow_collaboration?(current_user), class: 'form-check-input'
= form.label :allow_collaboration, class: 'form-check-label' do = form.label :allow_collaboration, class: 'form-check-label' do
= _('Allow commits from members who can merge to the target branch.') = _('Allow commits from members who can merge to the target branch.')
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
= hidden_field_tag :target_id, '', class: 'js-form-target-id' = hidden_field_tag :target_id, '', class: 'js-form-target-id'
= hidden_field_tag :target_type, '', class: 'js-form-target-type' = hidden_field_tag :target_type, '', class: 'js-form-target-type'
= render layout: 'projects/md_preview', locals: { url: preview_markdown_path(project), referenced_users: true } do = render layout: 'projects/md_preview', locals: { url: preview_markdown_path(project), referenced_users: true } do
= render 'projects/zen', attr: 'note[note]', classes: 'note-textarea js-note-text js-task-list-field', placeholder: "Write a comment or drag your files here..." = render 'projects/zen', attr: 'note[note]', classes: 'note-textarea js-note-text js-task-list-field', placeholder: "Write a comment or drag your files here"
= render 'shared/notes/hints' = render 'shared/notes/hints'
.note-form-actions.clearfix .note-form-actions.clearfix
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
= render 'projects/zen', f: f, = render 'projects/zen', f: f,
attr: :note, attr: :note,
classes: 'note-textarea js-note-text', classes: 'note-textarea js-note-text',
placeholder: "Write a comment or drag your files here...", placeholder: "Write a comment or drag your files here",
supports_quick_actions: supports_quick_actions, supports_quick_actions: supports_quick_actions,
supports_autocomplete: supports_autocomplete supports_autocomplete: supports_autocomplete
= render 'shared/notes/hints', supports_quick_actions: supports_quick_actions = render 'shared/notes/hints', supports_quick_actions: supports_quick_actions
......
---
title: Make avatars/icons hidden on mobile
merge_request: 19585
author: Takuya Noguchi
type: fixed
---
title: Add CI job to check Gemfile.rails5.lock
merge_request: 19605
author: "@blackst0ne"
type: other
---
title: Fix bug where maintainer would not be allowed to push to forks with merge requests
that have `Allow maintainer edits` enabled.
merge_request: 18968
author:
type: fixed
---
title: Add Gitlab::SQL:CTE for easily building CTE statements
merge_request:
author:
type: added
---
title: Add CI_PIPELINE_URL and CI_JOB_URL
merge_request: 19618
author:
type: added
---
title: Fixed bug that allowed to remove other wiki pages if the title had wildcard characters
merge_request:
author:
type: fixed
---
title: Move Gitaly branch/tag/ref RPC's to opt-out
merge_request: 19644
author:
type: other
---
title: Expire Wiki content cache after importing a repository
merge_request:
author:
type: fixed
...@@ -6,7 +6,7 @@ scope(controller: :wikis) do ...@@ -6,7 +6,7 @@ scope(controller: :wikis) do
post '/', to: 'wikis#create' post '/', to: 'wikis#create'
end end
scope(path: 'wikis/*id', as: :wiki, format: false) do scope(path: 'wikis/*id', as: :wiki, format: false, defaults: { format: :html }) do
get :edit get :edit
get :history get :history
post :preview_markdown post :preview_markdown
......
...@@ -100,14 +100,14 @@ As it's pointed out before, you will need public access to this machine that ...@@ -100,14 +100,14 @@ As it's pointed out before, you will need public access to this machine that
you've installed Koding and GitLab on. Better to use a domain but a static IP you've installed Koding and GitLab on. Better to use a domain but a static IP
is also fine. is also fine.
For IP based installation you can use [xip.io](https://xip.io) service which is For IP based installation you can use [nip.io](https://nip.io) service which is
free and provides DNS resolution to IP based requests like following; free and provides DNS resolution to IP based requests like following;
- 127.0.0.1.xip.io -> resolves to 127.0.0.1 - 127.0.0.1.nip.io -> resolves to 127.0.0.1
- foo.bar.baz.127.0.0.1.xip.io -> resolves to 127.0.0.1 - foo.bar.baz.127.0.0.1.nip.io -> resolves to 127.0.0.1
- and so on... - and so on...
As Koding needs subdomains for team names; `foo.127.0.0.1.xip.io` requests for As Koding needs subdomains for team names; `foo.127.0.0.1.nip.io` requests for
a running koding instance on `127.0.0.1` server will be handled as `foo` team a running koding instance on `127.0.0.1` server will be handled as `foo` team
requests. requests.
...@@ -127,8 +127,8 @@ your Koding installation. Team called `gitlab` has integration on Koding out ...@@ -127,8 +127,8 @@ your Koding installation. Team called `gitlab` has integration on Koding out
of the box, so if you didn't change anything your team on Koding should be of the box, so if you didn't change anything your team on Koding should be
`gitlab`. `gitlab`.
So, if your Koding is running on `http://1.2.3.4.xip.io:8090` your URL needs So, if your Koding is running on `http://1.2.3.4.nip.io:8090` your URL needs
to be `http://gitlab.1.2.3.4.xip.io:8090`. You need to provide the same host to be `http://gitlab.1.2.3.4.nip.io:8090`. You need to provide the same host
with your Koding installation here. with your Koding installation here.
...@@ -192,7 +192,7 @@ cd koding ...@@ -192,7 +192,7 @@ cd koding
docker-compose run \ docker-compose run \
--service-ports backend \ --service-ports backend \
/opt/koding/scripts/bootstrap-container build \ /opt/koding/scripts/bootstrap-container build \
--host=**YOUR_IP**.xip.io \ --host=**YOUR_IP**.nip.io \
--gitlabHost=**GITLAB_IP** \ --gitlabHost=**GITLAB_IP** \
--gitlabPort=**GITLAB_PORT** \ --gitlabPort=**GITLAB_PORT** \
--gitlabToken=**SECRET_TOKEN** \ --gitlabToken=**SECRET_TOKEN** \
...@@ -224,7 +224,7 @@ cd koding ...@@ -224,7 +224,7 @@ cd koding
docker-compose run \ docker-compose run \
--service-ports backend \ --service-ports backend \
/opt/koding/scripts/bootstrap-container build \ /opt/koding/scripts/bootstrap-container build \
--host=**YOUR_IP**.xip.io \ --host=**YOUR_IP**.nip.io \
``` ```
#### Enable Single Sign On #### Enable Single Sign On
...@@ -233,7 +233,7 @@ Once you restarted your Koding and logged in with your username and password ...@@ -233,7 +233,7 @@ Once you restarted your Koding and logged in with your username and password
you need to activate oauth authentication for your user. To do that you need to activate oauth authentication for your user. To do that
- Navigate to Dashboard on Koding from; - Navigate to Dashboard on Koding from;
`http://gitlab.**YOUR_IP**.xip.io:8090/Home/my-account` `http://gitlab.**YOUR_IP**.nip.io:8090/Home/my-account`
- Scroll down to Integrations section - Scroll down to Integrations section
- Click on toggle to turn On integration in GitLab integration section - Click on toggle to turn On integration in GitLab integration section
......
...@@ -64,6 +64,7 @@ future GitLab releases.** ...@@ -64,6 +64,7 @@ future GitLab releases.**
| **CI_JOB_NAME** | 9.0 | 0.5 | The name of the job as defined in `.gitlab-ci.yml` | | **CI_JOB_NAME** | 9.0 | 0.5 | The name of the job as defined in `.gitlab-ci.yml` |
| **CI_JOB_STAGE** | 9.0 | 0.5 | The name of the stage as defined in `.gitlab-ci.yml` | | **CI_JOB_STAGE** | 9.0 | 0.5 | The name of the stage as defined in `.gitlab-ci.yml` |
| **CI_JOB_TOKEN** | 9.0 | 1.2 | Token used for authenticating with the GitLab Container Registry | | **CI_JOB_TOKEN** | 9.0 | 1.2 | Token used for authenticating with the GitLab Container Registry |
| **CI_JOB_URL** | 11.0 | 0.5 | Job details URL |
| **CI_REPOSITORY_URL** | 9.0 | all | The URL to clone the Git repository | | **CI_REPOSITORY_URL** | 9.0 | all | The URL to clone the Git repository |
| **CI_RUNNER_DESCRIPTION** | 8.10 | 0.5 | The description of the runner as saved in GitLab | | **CI_RUNNER_DESCRIPTION** | 8.10 | 0.5 | The description of the runner as saved in GitLab |
| **CI_RUNNER_ID** | 8.10 | 0.5 | The unique id of runner being used | | **CI_RUNNER_ID** | 8.10 | 0.5 | The unique id of runner being used |
...@@ -81,6 +82,7 @@ future GitLab releases.** ...@@ -81,6 +82,7 @@ future GitLab releases.**
| **CI_PROJECT_NAMESPACE** | 8.10 | 0.5 | The project namespace (username or groupname) that is currently being built | | **CI_PROJECT_NAMESPACE** | 8.10 | 0.5 | The project namespace (username or groupname) that is currently being built |
| **CI_PROJECT_PATH** | 8.10 | 0.5 | The namespace with project name | | **CI_PROJECT_PATH** | 8.10 | 0.5 | The namespace with project name |
| **CI_PROJECT_PATH_SLUG** | 9.3 | all | `$CI_PROJECT_PATH` lowercased and with everything except `0-9` and `a-z` replaced with `-`. Use in URLs and domain names. | | **CI_PROJECT_PATH_SLUG** | 9.3 | all | `$CI_PROJECT_PATH` lowercased and with everything except `0-9` and `a-z` replaced with `-`. Use in URLs and domain names. |
| **CI_PIPELINE_URL** | 11.0 | 0.5 | Pipeline details URL |
| **CI_PROJECT_URL** | 8.10 | 0.5 | The HTTP address to access project | | **CI_PROJECT_URL** | 8.10 | 0.5 | The HTTP address to access project |
| **CI_PROJECT_VISIBILITY** | 10.3 | all | The project visibility (internal, private, public) | | **CI_PROJECT_VISIBILITY** | 10.3 | all | The project visibility (internal, private, public) |
| **CI_REGISTRY** | 8.10 | 0.5 | If the Container Registry is enabled it returns the address of GitLab's Container Registry | | **CI_REGISTRY** | 8.10 | 0.5 | If the Container Registry is enabled it returns the address of GitLab's Container Registry |
......
...@@ -32,7 +32,7 @@ description: 'Learn how to contribute to GitLab.' ...@@ -32,7 +32,7 @@ description: 'Learn how to contribute to GitLab.'
- [GitLab utilities](utilities.md) - [GitLab utilities](utilities.md)
- [API styleguide](api_styleguide.md) Use this styleguide if you are - [API styleguide](api_styleguide.md) Use this styleguide if you are
contributing to the API. contributing to the API.
- [GrapQL API styleguide](api_graphql_styleguide.md) Use this - [GraphQL API styleguide](api_graphql_styleguide.md) Use this
styleguide if you are contribution to the [GraphQL API](../api/graphql/index.md) styleguide if you are contribution to the [GraphQL API](../api/graphql/index.md)
- [Sidekiq guidelines](sidekiq_style_guide.md) for working with Sidekiq workers - [Sidekiq guidelines](sidekiq_style_guide.md) for working with Sidekiq workers
- [Working with Gitaly](gitaly.md) - [Working with Gitaly](gitaly.md)
......
...@@ -233,7 +233,7 @@ This makes use of [`Intl.DateTimeFormat`]. ...@@ -233,7 +233,7 @@ This makes use of [`Intl.DateTimeFormat`].
Please never split a sentence as that would assume the sentence grammar and Please never split a sentence as that would assume the sentence grammar and
structure is the same in all languages. structure is the same in all languages.
For instance, the following For instance, the following:
```js ```js
{{ s__("mrWidget|Set by") }} {{ s__("mrWidget|Set by") }}
...@@ -247,6 +247,27 @@ should be externalized as follows: ...@@ -247,6 +247,27 @@ should be externalized as follows:
{{ sprintf(s__("mrWidget|Set by %{author} to be merged automatically when the pipeline succeeds"), { author: author.name }) }} {{ sprintf(s__("mrWidget|Set by %{author} to be merged automatically when the pipeline succeeds"), { author: author.name }) }}
``` ```
#### Avoid splitting sentences when adding links
This also applies when using links in between translated sentences, otherwise these texts are not translatable in certain languages.
Instead of:
```haml
- zones_link = link_to(s_('ClusterIntegration|zones'), 'https://cloud.google.com/compute/docs/regions-zones/regions-zones', target: '_blank', rel: 'noopener noreferrer')
= s_('ClusterIntegration|Learn more about %{zones_link}').html_safe % { zones_link: zones_link }
```
Set the link starting and ending HTML fragments as variables like so:
```haml
- zones_link_url = 'https://cloud.google.com/compute/docs/regions-zones/regions-zones'
- zones_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: zones_link_url }
= s_('ClusterIntegration|Learn more about %{zones_link_start}zones%{zones_link_end}').html_safe % { zones_link_start: zones_link_start, zones_link_end: '</a>'.html_safe }
```
The reasoning behind this is that in some languages words change depending on context. For example in Japanese は is added to the subject of a sentence and を to the object. This is impossible to translate correctly if we extract individual words from the sentence.
When in doubt, try to follow the best practices described in this [Mozilla When in doubt, try to follow the best practices described in this [Mozilla
Developer documentation][mdn]. Developer documentation][mdn].
......
...@@ -7,17 +7,19 @@ In Git, when you copy a project you say you "clone" it. To work on a git project ...@@ -7,17 +7,19 @@ In Git, when you copy a project you say you "clone" it. To work on a git project
When you are on your Dashboard, click on the project that you'd like to clone. When you are on your Dashboard, click on the project that you'd like to clone.
To work in the project, you can copy a link to the Git repository through a SSH To work in the project, you can copy a link to the Git repository through a SSH
or a HTTPS protocol. SSH is easier to use after it's been or a HTTPS protocol. SSH is easier to use after it's been
[setup](create-your-ssh-keys.md). While you are at the **Project** tab, select [set up](create-your-ssh-keys.md). While you are at the **Project** tab, select
HTTPS or SSH from the dropdown menu and copy the link using the 'Copy to clipboard' HTTPS or SSH from the dropdown menu and copy the link using the _Copy URL to clipboard_
button (you'll have to paste it on your shell in the next step). button (you'll have to paste it on your shell in the next step).
![Copy the HTTPS or SSH](img/project_clone_url.png) ![Copy the HTTPS or SSH](img/project_clone_url.png)
## On the command line ## On the command line
This section has examples of some basic shell commands that you might find useful. For more information, search the web for _bash commands_.
### Clone your project ### Clone your project
Go to your computer's shell and type the following command: Go to your computer's shell and type the following command with your SSH or HTTPS URL:
``` ```
git clone PASTE HTTPS OR SSH HERE git clone PASTE HTTPS OR SSH HERE
...@@ -25,33 +27,45 @@ git clone PASTE HTTPS OR SSH HERE ...@@ -25,33 +27,45 @@ git clone PASTE HTTPS OR SSH HERE
A clone of the project will be created in your computer. A clone of the project will be created in your computer.
>**Note:** If you clone your project via an URL that contains special characters, make sure that they are URL-encoded. >**Note:** If you clone your project via a URL that contains special characters, make sure that characters are URL-encoded.
### Go into a project, directory or file to work in it ### Go into a project directory to work in it
``` ```
cd NAME-OF-PROJECT-OR-FILE cd NAME-OF-PROJECT
``` ```
### Go back one directory or file ### Go back one directory
``` ```
cd ../ cd ..
``` ```
### View what’s in the directory that you are in ### List what’s in the current directory
``` ```
ls ls
``` ```
### Create a directory ### List what’s in the current directory that starts with `a`
```
ls a*
```
### List what’s in the current directory that ends with `.md`
```
ls *.md
```
### Create a new directory
``` ```
mkdir NAME-OF-YOUR-DIRECTORY mkdir NAME-OF-YOUR-DIRECTORY
``` ```
### Create a README.md or file in directory ### Create a README.md file in the current directory
``` ```
touch README.md touch README.md
...@@ -62,6 +76,12 @@ nano README.md ...@@ -62,6 +76,12 @@ nano README.md
#### Press: enter #### Press: enter
``` ```
### Show the contents of the README.md file
```
cat README.md
```
### Remove a file ### Remove a file
``` ```
...@@ -74,12 +94,18 @@ rm NAME-OF-FILE ...@@ -74,12 +94,18 @@ rm NAME-OF-FILE
rm -r NAME-OF-DIRECTORY rm -r NAME-OF-DIRECTORY
``` ```
### View history in the command line ### View command history
``` ```
history history
``` ```
### Execute command 123 from history
```
!123
```
### Carry out commands for which the account you are using lacks authority ### Carry out commands for which the account you are using lacks authority
You will be asked for an administrator’s password. You will be asked for an administrator’s password.
...@@ -88,8 +114,14 @@ You will be asked for an administrator’s password. ...@@ -88,8 +114,14 @@ You will be asked for an administrator’s password.
sudo sudo
``` ```
### Tell where you are ### Show which directory I am in
``` ```
pwd pwd
``` ```
### Clear the shell window
```
clear
```
...@@ -120,7 +120,7 @@ gitlabConfigStorageSize: 1Gi ...@@ -120,7 +120,7 @@ gitlabConfigStorageSize: 1Gi
Ingress routing and SSL are automatically configured within this Chart. An NGINX ingress is provisioned and configured, and will route traffic to any service. SSL certificates are automatically created and configured by [kube-lego](https://github.com/kubernetes/charts/tree/master/stable/kube-lego). Ingress routing and SSL are automatically configured within this Chart. An NGINX ingress is provisioned and configured, and will route traffic to any service. SSL certificates are automatically created and configured by [kube-lego](https://github.com/kubernetes/charts/tree/master/stable/kube-lego).
> **Note:** > **Note:**
Let's Encrypt limits a single TLD to five certificate requests within a single week. This means that common DNS wildcard services like [xip.io](http://xip.io) and [nip.io](http://nip.io) are unlikely to work. Let's Encrypt limits a single TLD to five certificate requests within a single week. This means that common DNS wildcard services like [nip.io](http://nip.io) and [nip.io](http://nip.io) are unlikely to work.
## Installing GitLab using the Helm Chart ## Installing GitLab using the Helm Chart
> **Note:** > **Note:**
......
...@@ -307,10 +307,10 @@ hostname** and use greater values for the volume sizes. If you don't provide a ...@@ -307,10 +307,10 @@ hostname** and use greater values for the volume sizes. If you don't provide a
password for PostgreSQL, it will be created automatically. password for PostgreSQL, it will be created automatically.
>**Note:** >**Note:**
The `gitlab.apps.10.2.2.2.xip.io` hostname that is used by default will The `gitlab.apps.10.2.2.2.nip.io` hostname that is used by default will
resolve to the host with IP `10.2.2.2` which is the IP our VM uses. It is a resolve to the host with IP `10.2.2.2` which is the IP our VM uses. It is a
trick to have distinct FQDNs pointing to services that are on our local network. trick to have distinct FQDNs pointing to services that are on our local network.
Read more on how this works in <http://xip.io>. Read more on how this works in <http://nip.io>.
Now that we configured this, let's see how to manage and scale GitLab. Now that we configured this, let's see how to manage and scale GitLab.
...@@ -347,7 +347,7 @@ Navigate back to the **Overview** and hopefully all pods will be up and running. ...@@ -347,7 +347,7 @@ Navigate back to the **Overview** and hopefully all pods will be up and running.
![GitLab running](img/gitlab-running.png) ![GitLab running](img/gitlab-running.png)
Congratulations! You can now navigate to your new shinny GitLab instance by Congratulations! You can now navigate to your new shinny GitLab instance by
visiting <http://gitlab.apps.10.2.2.2.xip.io> where you will be asked to visiting <http://gitlab.apps.10.2.2.2.nip.io> where you will be asked to
change the root user password. Login using `root` as username and providing the change the root user password. Login using `root` as username and providing the
password you just set, and start using GitLab! password you just set, and start using GitLab!
......
...@@ -135,9 +135,9 @@ and `1.2.3.4` is the IP address of your load balancer; generally NGINX ...@@ -135,9 +135,9 @@ and `1.2.3.4` is the IP address of your load balancer; generally NGINX
([see requirements](#requirements)). How to set up the DNS record is beyond ([see requirements](#requirements)). How to set up the DNS record is beyond
the scope of this document; you should check with your DNS provider. the scope of this document; you should check with your DNS provider.
Alternatively you can use free public services like [xip.io](http://xip.io) or Alternatively you can use free public services like [nip.io](http://nip.io) or
[nip.io](http://nip.io) which provide automatic wildcard DNS without any [nip.io](http://nip.io) which provide automatic wildcard DNS without any
configuration. Just set the Auto DevOps base domain to `1.2.3.4.xip.io` or configuration. Just set the Auto DevOps base domain to `1.2.3.4.nip.io` or
`1.2.3.4.nip.io`. `1.2.3.4.nip.io`.
Once set up, all requests will hit the load balancer, which in turn will route Once set up, all requests will hit the load balancer, which in turn will route
......
...@@ -7,6 +7,34 @@ To navigate to your profile's preferences, click your avatar icon in the top ...@@ -7,6 +7,34 @@ To navigate to your profile's preferences, click your avatar icon in the top
right corner and select **Settings**. From there on, choose the **Preferences** right corner and select **Settings**. From there on, choose the **Preferences**
tab. tab.
![Profile preferences settings](img/profile_settings_dropdown.png)
## Navigation theme
>**Note:**
Navigation themes have been re-introduced with [GitLab 10.0](https://about.gitlab.com/2017/09/22/gitlab-10-0-released/).
The GitLab navigation theme setting allows you to personalize your GitLab experience.
You can choose from several color themes that add unique colors to the top navigation
and left side navigation.
Using individual color themes might help you differentiate between your different
GitLab instances.
The default palette is Indigo. You can choose between 10 different themes:
- Indigo
- Light Indigo
- Blue
- Light Blue
- Green
- Light Green
- Red
- Light Red
- Dark
- Light
![Profile preferences syntax highlighting themes](img/profile-preferences-syntax-themes.png)
## Syntax highlighting theme ## Syntax highlighting theme
>**Note:** >**Note:**
...@@ -16,7 +44,7 @@ list of supported languages visit the rouge website. ...@@ -16,7 +44,7 @@ list of supported languages visit the rouge website.
Changing this setting allows you to customize the color theme when viewing any Changing this setting allows you to customize the color theme when viewing any
syntax highlighted code on GitLab. syntax highlighted code on GitLab.
The default one is **White**, and you can choose among 5 different colors: The default syntax theme is White, and you can choose among 5 different colors:
- White - White
- Dark - Dark
...@@ -24,6 +52,8 @@ The default one is **White**, and you can choose among 5 different colors: ...@@ -24,6 +52,8 @@ The default one is **White**, and you can choose among 5 different colors:
- Solarized dark - Solarized dark
- Monokai - Monokai
![Profile preferences navigation themes](img/profil-preferences-navigation-theme.png)
## Behavior ## Behavior
The following settings allow you to customize the behavior of GitLab's layout The following settings allow you to customize the behavior of GitLab's layout
...@@ -52,16 +82,16 @@ You have 8 options here that you can use for your default dashboard view: ...@@ -52,16 +82,16 @@ You have 8 options here that you can use for your default dashboard view:
- Assigned Issues - Assigned Issues
- Assigned Merge Requests - Assigned Merge Requests
### Project home page content ### Project overview content
The project home page content setting allows you to choose what content you want to The project overview content setting allows you to choose what content you want to
see on a project’s home page. see on a project’s home page.
You can choose between 3 options: You can choose between 3 options:
- Show the files and the readme (default) - Files and Readme (default)
- Show the readme - Readme
- Show the project’s activity - Activity
[rouge]: http://rouge.jneen.net/ "Rouge website" [rouge]: http://rouge.jneen.net/ "Rouge website"
[todos]: ../../workflow/todos.md [todos]: ../../workflow/todos.md
...@@ -41,20 +41,20 @@ new Kubernetes cluster that will be hosted on GKE to your project: ...@@ -41,20 +41,20 @@ new Kubernetes cluster that will be hosted on GKE to your project:
1. Navigate to your project's **Operations > Kubernetes** page. 1. Navigate to your project's **Operations > Kubernetes** page.
1. Click on **Add Kubernetes cluster**. 1. Click on **Add Kubernetes cluster**.
1. Click on **Create with GKE**. 1. Click on **Create with Google Kubernetes Engine**.
1. Connect your Google account if you haven't done already by clicking the 1. Connect your Google account if you haven't done already by clicking the
**Sign in with Google** button. **Sign in with Google** button.
1. Fill in the requested values: 1. Fill in the requested values:
- **Cluster name** (required) - The name you wish to give the cluster. - **Kubernetes cluster name** - The name you wish to give the cluster.
- **GCP project ID** (required) - The ID of the project you created in your GCP - **Environment scope** - The [associated environment](#setting-the-environment-scope) to this cluster.
- **Google Cloud Platform project** - The project you created in your GCP
console that will host the Kubernetes cluster. This must **not** be confused console that will host the Kubernetes cluster. This must **not** be confused
with the project name. Learn more about [Google Cloud Platform projects](https://cloud.google.com/resource-manager/docs/creating-managing-projects). with the project ID. Learn more about [Google Cloud Platform projects](https://cloud.google.com/resource-manager/docs/creating-managing-projects).
- **Zone** - The [zone](https://cloud.google.com/compute/docs/regions-zones/) - **Zone** - The [zone](https://cloud.google.com/compute/docs/regions-zones/)
under which the cluster will be created. under which the cluster will be created.
- **Number of nodes** - The number of nodes you wish the cluster to have. - **Number of nodes** - The number of nodes you wish the cluster to have.
- **Machine type** - The [machine type](https://cloud.google.com/compute/docs/machine-types) - **Machine type** - The [machine type](https://cloud.google.com/compute/docs/machine-types)
of the Virtual Machine instance that the cluster will be based on. of the Virtual Machine instance that the cluster will be based on.
- **Environment scope** - The [associated environment](#setting-the-environment-scope) to this cluster.
1. Finally, click the **Create Kubernetes cluster** button. 1. Finally, click the **Create Kubernetes cluster** button.
After a few moments, your cluster should be created. If something goes wrong, After a few moments, your cluster should be created. If something goes wrong,
......
...@@ -120,7 +120,7 @@ module Gitlab ...@@ -120,7 +120,7 @@ module Gitlab
# Default branch in the repository # Default branch in the repository
def root_ref def root_ref
@root_ref ||= gitaly_migrate(:root_ref) do |is_enabled| @root_ref ||= gitaly_migrate(:root_ref, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled if is_enabled
gitaly_ref_client.default_branch_name gitaly_ref_client.default_branch_name
else else
...@@ -152,7 +152,7 @@ module Gitlab ...@@ -152,7 +152,7 @@ module Gitlab
# Returns an Array of branch names # Returns an Array of branch names
# sorted by name ASC # sorted by name ASC
def branch_names def branch_names
gitaly_migrate(:branch_names) do |is_enabled| gitaly_migrate(:branch_names, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled if is_enabled
gitaly_ref_client.branch_names gitaly_ref_client.branch_names
else else
...@@ -163,7 +163,7 @@ module Gitlab ...@@ -163,7 +163,7 @@ module Gitlab
# Returns an Array of Branches # Returns an Array of Branches
def branches def branches
gitaly_migrate(:branches) do |is_enabled| gitaly_migrate(:branches, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled if is_enabled
gitaly_ref_client.branches gitaly_ref_client.branches
else else
...@@ -200,7 +200,7 @@ module Gitlab ...@@ -200,7 +200,7 @@ module Gitlab
end end
def local_branches(sort_by: nil) def local_branches(sort_by: nil)
gitaly_migrate(:local_branches) do |is_enabled| gitaly_migrate(:local_branches, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled if is_enabled
gitaly_ref_client.local_branches(sort_by: sort_by) gitaly_ref_client.local_branches(sort_by: sort_by)
else else
...@@ -270,7 +270,7 @@ module Gitlab ...@@ -270,7 +270,7 @@ module Gitlab
# Returns an Array of tag names # Returns an Array of tag names
def tag_names def tag_names
gitaly_migrate(:tag_names) do |is_enabled| gitaly_migrate(:tag_names, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled if is_enabled
gitaly_ref_client.tag_names gitaly_ref_client.tag_names
else else
...@@ -283,7 +283,7 @@ module Gitlab ...@@ -283,7 +283,7 @@ module Gitlab
# #
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/390 # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/390
def tags def tags
gitaly_migrate(:tags) do |is_enabled| gitaly_migrate(:tags, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled if is_enabled
tags_from_gitaly tags_from_gitaly
else else
...@@ -310,7 +310,7 @@ module Gitlab ...@@ -310,7 +310,7 @@ module Gitlab
# #
# name - The name of the tag as a String. # name - The name of the tag as a String.
def tag_exists?(name) def tag_exists?(name)
gitaly_migrate(:ref_exists_tags) do |is_enabled| gitaly_migrate(:ref_exists_tags, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled if is_enabled
gitaly_ref_exists?("refs/tags/#{name}") gitaly_ref_exists?("refs/tags/#{name}")
else else
...@@ -323,7 +323,7 @@ module Gitlab ...@@ -323,7 +323,7 @@ module Gitlab
# #
# name - The name of the branch as a String. # name - The name of the branch as a String.
def branch_exists?(name) def branch_exists?(name)
gitaly_migrate(:ref_exists_branches) do |is_enabled| gitaly_migrate(:ref_exists_branches, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled if is_enabled
gitaly_ref_exists?("refs/heads/#{name}") gitaly_ref_exists?("refs/heads/#{name}")
else else
......
...@@ -42,8 +42,6 @@ module Gitlab ...@@ -42,8 +42,6 @@ module Gitlab
klass.new(project, client, parallel: false).execute klass.new(project, client, parallel: false).execute
end end
project.repository.after_import
true true
end end
end end
......
module Gitlab
module SQL
# Class for easily building CTE statements.
#
# Example:
#
# cte = CTE.new(:my_cte_name)
# ns = Arel::Table.new(:namespaces)
#
# cte << Namespace.
# where(ns[:parent_id].eq(some_namespace_id))
#
# Namespace
# with(cte.to_arel).
# from(cte.alias_to(ns))
class CTE
attr_reader :table, :query
# name - The name of the CTE as a String or Symbol.
def initialize(name, query)
@table = Arel::Table.new(name)
@query = query
end
# Returns the Arel relation for this CTE.
def to_arel
sql = Arel::Nodes::SqlLiteral.new("(#{query.to_sql})")
Arel::Nodes::As.new(table, sql)
end
# Returns an "AS" statement that aliases the CTE name as the given table
# name. This allows one to trick ActiveRecord into thinking it's selecting
# from an actual table, when in reality it's selecting from a CTE.
#
# alias_table - The Arel table to use as the alias.
def alias_to(alias_table)
Arel::Nodes::As.new(table, alias_table)
end
# Applies the CTE to the given relation, returning a new one that will
# query from it.
def apply_to(relation)
relation.except(:where)
.with(to_arel)
.from(alias_to(relation.model.arel_table))
end
end
end
end
...@@ -9,7 +9,10 @@ class GithubImport ...@@ -9,7 +9,10 @@ class GithubImport
def initialize(token, gitlab_username, project_path, extras) def initialize(token, gitlab_username, project_path, extras)
@options = { token: token } @options = { token: token }
@project_path = project_path @project_path = project_path
@current_user = User.find_by_username(gitlab_username) @current_user = User.find_by(username: gitlab_username)
raise "GitLab user #{gitlab_username} not found. Please specify a valid username." unless @current_user
@github_repo = extras.empty? ? nil : extras.first @github_repo = extras.empty? ? nil : extras.first
end end
...@@ -50,7 +53,7 @@ class GithubImport ...@@ -50,7 +53,7 @@ class GithubImport
end end
if import_success if import_success
@project.import_finish @project.after_import
puts "Import finished. Timings: #{timings}".color(:green) puts "Import finished. Timings: #{timings}".color(:green)
else else
puts "Import was not successful. Errors were as follows:" puts "Import was not successful. Errors were as follows:"
......
...@@ -8,8 +8,8 @@ msgid "" ...@@ -8,8 +8,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: gitlab 1.0.0\n" "Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-06-08 18:19+0200\n" "POT-Creation-Date: 2018-06-11 09:18+0200\n"
"PO-Revision-Date: 2018-06-08 18:19+0200\n" "PO-Revision-Date: 2018-06-11 09:18+0200\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n" "Language: \n"
...@@ -4109,7 +4109,7 @@ msgstr "" ...@@ -4109,7 +4109,7 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:" msgid "TagsPage|Use git tag command to add a new one:"
msgstr "" msgstr ""
msgid "TagsPage|Write your release notes or drag files here..." msgid "TagsPage|Write your release notes or drag files here"
msgstr "" msgstr ""
msgid "TagsPage|protected" msgid "TagsPage|protected"
...@@ -4806,7 +4806,7 @@ msgstr "" ...@@ -4806,7 +4806,7 @@ msgstr ""
msgid "WikiPage|Page slug" msgid "WikiPage|Page slug"
msgstr "" msgstr ""
msgid "WikiPage|Write your content or drag files here..." msgid "WikiPage|Write your content or drag files here"
msgstr "" msgstr ""
msgid "Wiki|Create Page" msgid "Wiki|Create Page"
......
require 'pathname'
module QA module QA
module Factory module Factory
module Repository module Repository
......
...@@ -46,6 +46,18 @@ module QA ...@@ -46,6 +46,18 @@ module QA
def sandbox_name def sandbox_name
ENV['GITLAB_SANDBOX_NAME'] ENV['GITLAB_SANDBOX_NAME']
end end
def gcloud_account_key
ENV.fetch("GCLOUD_ACCOUNT_KEY")
end
def gcloud_account_email
ENV.fetch("GCLOUD_ACCOUNT_EMAIL")
end
def gcloud_zone
ENV.fetch('GCLOUD_ZONE')
end
end end
end end
end end
...@@ -20,9 +20,11 @@ module QA ...@@ -20,9 +20,11 @@ module QA
gcloud container clusters gcloud container clusters
create #{cluster_name} create #{cluster_name}
--enable-legacy-authorization --enable-legacy-authorization
--zone us-central1-a --zone #{Runtime::Env.gcloud_zone}
&& gcloud container clusters && gcloud container clusters
get-credentials #{cluster_name} get-credentials
--zone #{Runtime::Env.gcloud_zone}
#{cluster_name}
CMD CMD
@api_url = `kubectl config view --minify -o jsonpath='{.clusters[].cluster.server}'` @api_url = `kubectl config view --minify -o jsonpath='{.clusters[].cluster.server}'`
...@@ -32,7 +34,12 @@ module QA ...@@ -32,7 +34,12 @@ module QA
end end
def remove! def remove!
shell("gcloud container clusters delete #{cluster_name} --quiet --async") shell <<~CMD.tr("\n", ' ')
gcloud container clusters delete
--zone #{Runtime::Env.gcloud_zone}
#{cluster_name}
--quiet --async
CMD
end end
private private
...@@ -54,9 +61,9 @@ module QA ...@@ -54,9 +61,9 @@ module QA
def attempt_login_with_env_vars def attempt_login_with_env_vars
puts "No gcloud account. Attempting to login from env vars GCLOUD_ACCOUNT_EMAIL and GCLOUD_ACCOUNT_KEY." puts "No gcloud account. Attempting to login from env vars GCLOUD_ACCOUNT_EMAIL and GCLOUD_ACCOUNT_KEY."
gcloud_account_key = Tempfile.new('gcloud-account-key') gcloud_account_key = Tempfile.new('gcloud-account-key')
gcloud_account_key.write(ENV.fetch("GCLOUD_ACCOUNT_KEY")) gcloud_account_key.write(Runtime::Env.gcloud_account_key)
gcloud_account_key.close gcloud_account_key.close
gcloud_account_email = ENV.fetch("GCLOUD_ACCOUNT_EMAIL") gcloud_account_email = Runtime::Env.gcloud_account_email
shell("gcloud auth activate-service-account #{gcloud_account_email} --key-file #{gcloud_account_key.path}") shell("gcloud auth activate-service-account #{gcloud_account_email} --key-file #{gcloud_account_key.path}")
ensure ensure
gcloud_account_key && gcloud_account_key.unlink gcloud_account_key && gcloud_account_key.unlink
......
require 'pathname'
module QA module QA
feature 'Auto Devops', :kubernetes do feature 'Auto Devops', :kubernetes do
after do after do
......
#!/usr/bin/env bash
echo -e "=> Checking if Gemfile.rails5.lock is up-to-date...\\n"
cp Gemfile.rails5.lock Gemfile.rails5.lock.orig
BUNDLE_GEMFILE=Gemfile.rails5 bundle install "$BUNDLE_INSTALL_FLAGS"
diff -u Gemfile.rails5.lock.orig Gemfile.rails5.lock >/dev/null 2>&1
if [ $? == 1 ]
then
diff -u Gemfile.rails5.lock.orig Gemfile.rails5.lock
echo -e "\\n✖ ERROR: Gemfile.rails5.lock is not up-to-date!
Please run 'BUNDLE_GEMFILE=Gemfile.rails5 bundle install'\\n" >&2
exit 1
fi
echo "✔ Gemfile.rails5.lock is up-to-date"
exit 0
...@@ -84,7 +84,7 @@ describe('issue_comment_form component', () => { ...@@ -84,7 +84,7 @@ describe('issue_comment_form component', () => {
it('should render textarea with placeholder', () => { it('should render textarea with placeholder', () => {
expect( expect(
vm.$el.querySelector('.js-main-target-form textarea').getAttribute('placeholder'), vm.$el.querySelector('.js-main-target-form textarea').getAttribute('placeholder'),
).toEqual('Write a comment or drag your files here...'); ).toEqual('Write a comment or drag your files here');
}); });
it('should make textarea disabled while requesting', (done) => { it('should make textarea disabled while requesting', (done) => {
......
...@@ -106,7 +106,7 @@ describe('note_app', () => { ...@@ -106,7 +106,7 @@ describe('note_app', () => {
expect(vm.$el.querySelector('.js-main-target-form').tagName).toEqual('FORM'); expect(vm.$el.querySelector('.js-main-target-form').tagName).toEqual('FORM');
expect( expect(
vm.$el.querySelector('.js-main-target-form textarea').getAttribute('placeholder'), vm.$el.querySelector('.js-main-target-form textarea').getAttribute('placeholder'),
).toEqual('Write a comment or drag your files here...'); ).toEqual('Write a comment or drag your files here');
}); });
it('should render form comment button as disabled', () => { it('should render form comment button as disabled', () => {
...@@ -129,7 +129,7 @@ describe('note_app', () => { ...@@ -129,7 +129,7 @@ describe('note_app', () => {
expect(vm.$el.querySelector('.js-main-target-form').tagName).toEqual('FORM'); expect(vm.$el.querySelector('.js-main-target-form').tagName).toEqual('FORM');
expect( expect(
vm.$el.querySelector('.js-main-target-form textarea').getAttribute('placeholder'), vm.$el.querySelector('.js-main-target-form textarea').getAttribute('placeholder'),
).toEqual('Write a comment or drag your files here...'); ).toEqual('Write a comment or drag your files here');
}); });
}); });
......
...@@ -49,7 +49,7 @@ describe('issue_note_form component', () => { ...@@ -49,7 +49,7 @@ describe('issue_note_form component', () => {
it('should render text area with placeholder', () => { it('should render text area with placeholder', () => {
expect( expect(
vm.$el.querySelector('textarea').getAttribute('placeholder'), vm.$el.querySelector('textarea').getAttribute('placeholder'),
).toEqual('Write a comment or drag your files here...'); ).toEqual('Write a comment or drag your files here');
}); });
it('should link to markdown docs', () => { it('should link to markdown docs', () => {
......
...@@ -25,6 +25,22 @@ describe Gitlab::Git::Wiki do ...@@ -25,6 +25,22 @@ describe Gitlab::Git::Wiki do
end end
end end
describe '#delete_page', :skip_gitaly_mock do
after do
destroy_page('page1')
end
it 'only removes the page with the same path' do
create_page('page1', 'content')
create_page('*', 'content')
subject.delete_page('*', commit_details('whatever'))
expect(subject.pages.count).to eq 1
expect(subject.pages.first.title).to eq 'page1'
end
end
def create_page(name, content) def create_page(name, content)
subject.write_page(name, :markdown, content, commit_details(name)) subject.write_page(name, :markdown, content, commit_details(name))
end end
......
...@@ -30,7 +30,6 @@ describe Gitlab::GithubImport::SequentialImporter do ...@@ -30,7 +30,6 @@ describe Gitlab::GithubImport::SequentialImporter do
expect(instance).to receive(:execute) expect(instance).to receive(:execute)
end end
expect(repository).to receive(:after_import)
expect(importer.execute).to eq(true) expect(importer.execute).to eq(true)
end end
end end
......
require 'spec_helper'
describe Gitlab::SQL::CTE, :postgresql do
describe '#to_arel' do
it 'generates an Arel relation for the CTE body' do
relation = User.where(id: 1)
cte = described_class.new(:cte_name, relation)
sql = cte.to_arel.to_sql
name = ActiveRecord::Base.connection.quote_table_name(:cte_name)
sql1 = ActiveRecord::Base.connection.unprepared_statement do
relation.except(:order).to_sql
end
expect(sql).to eq("#{name} AS (#{sql1})")
end
end
describe '#alias_to' do
it 'returns an alias for the CTE' do
cte = described_class.new(:cte_name, nil)
table = Arel::Table.new(:kittens)
source_name = ActiveRecord::Base.connection.quote_table_name(:cte_name)
alias_name = ActiveRecord::Base.connection.quote_table_name(:kittens)
expect(cte.alias_to(table).to_sql).to eq("#{source_name} AS #{alias_name}")
end
end
describe '#apply_to' do
it 'applies a CTE to an ActiveRecord::Relation' do
user = create(:user)
cte = described_class.new(:cte_name, User.where(id: user.id))
relation = cte.apply_to(User.all)
expect(relation.to_sql).to match(/WITH .+cte_name/)
expect(relation.to_a).to eq(User.where(id: user.id).to_a)
end
end
end
...@@ -1548,7 +1548,9 @@ describe Ci::Build do ...@@ -1548,7 +1548,9 @@ describe Ci::Build do
let(:predefined_variables) do let(:predefined_variables) do
[ [
{ key: 'CI_PIPELINE_ID', value: pipeline.id.to_s, public: true }, { key: 'CI_PIPELINE_ID', value: pipeline.id.to_s, public: true },
{ key: 'CI_PIPELINE_URL', value: project.web_url + "/pipelines/#{pipeline.id}", public: true },
{ key: 'CI_JOB_ID', value: build.id.to_s, public: true }, { key: 'CI_JOB_ID', value: build.id.to_s, public: true },
{ key: 'CI_JOB_URL', value: project.web_url + "/-/jobs/#{build.id}", public: true },
{ key: 'CI_JOB_TOKEN', value: build.token, public: false }, { key: 'CI_JOB_TOKEN', value: build.token, public: false },
{ key: 'CI_BUILD_ID', value: build.id.to_s, public: true }, { key: 'CI_BUILD_ID', value: build.id.to_s, public: true },
{ key: 'CI_BUILD_TOKEN', value: build.token, public: false }, { key: 'CI_BUILD_TOKEN', value: build.token, public: false },
...@@ -2171,6 +2173,7 @@ describe Ci::Build do ...@@ -2171,6 +2173,7 @@ describe Ci::Build do
it 'does not return prohibited variables' do it 'does not return prohibited variables' do
keys = %w[CI_JOB_ID keys = %w[CI_JOB_ID
CI_JOB_URL
CI_JOB_TOKEN CI_JOB_TOKEN
CI_BUILD_ID CI_BUILD_ID
CI_BUILD_TOKEN CI_BUILD_TOKEN
......
...@@ -194,7 +194,7 @@ describe Ci::Pipeline, :mailer do ...@@ -194,7 +194,7 @@ describe Ci::Pipeline, :mailer do
it 'does contains persisted variables' do it 'does contains persisted variables' do
keys = subject.map { |variable| variable[:key] } keys = subject.map { |variable| variable[:key] }
expect(keys).to eq %w[CI_PIPELINE_ID] expect(keys).to eq %w[CI_PIPELINE_ID CI_PIPELINE_URL]
end end
end end
end end
......
...@@ -1733,7 +1733,11 @@ describe Project do ...@@ -1733,7 +1733,11 @@ describe Project do
.with(project.repository_storage, project.disk_path, project.import_url) .with(project.repository_storage, project.disk_path, project.import_url)
.and_return(true) .and_return(true)
expect_any_instance_of(Repository).to receive(:after_import) # Works around https://github.com/rspec/rspec-mocks/issues/910
allow(described_class).to receive(:find).with(project.id).and_return(project)
expect(project.repository).to receive(:after_import)
.and_call_original
expect(project.wiki.repository).to receive(:after_import)
.and_call_original .and_call_original
end end
...@@ -3398,10 +3402,11 @@ describe Project do ...@@ -3398,10 +3402,11 @@ describe Project do
end end
describe '#after_import' do describe '#after_import' do
let(:project) { build(:project) } let(:project) { create(:project) }
it 'runs the correct hooks' do it 'runs the correct hooks' do
expect(project.repository).to receive(:after_import) expect(project.repository).to receive(:after_import)
expect(project.wiki.repository).to receive(:after_import)
expect(project).to receive(:import_finish) expect(project).to receive(:import_finish)
expect(project).to receive(:update_project_counter_caches) expect(project).to receive(:update_project_counter_caches)
expect(project).to receive(:remove_import_jid) expect(project).to receive(:remove_import_jid)
...@@ -3658,6 +3663,11 @@ describe Project do ...@@ -3658,6 +3663,11 @@ describe Project do
.to be_truthy .to be_truthy
end end
it 'allows access when there are merge requests open but no branch name is given' do
expect(project.branch_allows_collaboration?(user, nil))
.to be_truthy
end
it 'does not allow guest users access' do it 'does not allow guest users access' do
guest = create(:user) guest = create(:user)
target_project.add_guest(guest) target_project.add_guest(guest)
......
require "spec_helper" require "spec_helper"
describe 'Git HTTP requests' do describe 'Git HTTP requests' do
include ProjectForksHelper
include TermsHelper include TermsHelper
include GitHttpHelpers include GitHttpHelpers
include WorkhorseHelpers include WorkhorseHelpers
...@@ -305,6 +306,22 @@ describe 'Git HTTP requests' do ...@@ -305,6 +306,22 @@ describe 'Git HTTP requests' do
expect(response.body).to eq(change_access_error(:push_code)) expect(response.body).to eq(change_access_error(:push_code))
end end
end end
context 'when merge requests are open that allow maintainer access' do
let(:canonical_project) { create(:project, :public, :repository) }
let(:project) { fork_project(canonical_project, nil, repository: true) }
before do
canonical_project.add_master(user)
create(:merge_request,
source_project: project,
target_project: canonical_project,
source_branch: 'fixes',
allow_collaboration: true)
end
it_behaves_like 'pushes are allowed'
end
end end
end end
......
...@@ -36,33 +36,36 @@ describe 'project routing' do ...@@ -36,33 +36,36 @@ describe 'project routing' do
shared_examples 'RESTful project resources' do shared_examples 'RESTful project resources' do
let(:actions) { [:index, :create, :new, :edit, :show, :update, :destroy] } let(:actions) { [:index, :create, :new, :edit, :show, :update, :destroy] }
let(:controller_path) { controller } let(:controller_path) { controller }
let(:id) { { id: '1' } }
let(:format) { {} } # response format, e.g. { format: :html }
let(:params) { { namespace_id: 'gitlab', project_id: 'gitlabhq' } }
it 'to #index' do it 'to #index' do
expect(get("/gitlab/gitlabhq/#{controller_path}")).to route_to("projects/#{controller}#index", namespace_id: 'gitlab', project_id: 'gitlabhq') if actions.include?(:index) expect(get("/gitlab/gitlabhq/#{controller_path}")).to route_to("projects/#{controller}#index", params) if actions.include?(:index)
end end
it 'to #create' do it 'to #create' do
expect(post("/gitlab/gitlabhq/#{controller_path}")).to route_to("projects/#{controller}#create", namespace_id: 'gitlab', project_id: 'gitlabhq') if actions.include?(:create) expect(post("/gitlab/gitlabhq/#{controller_path}")).to route_to("projects/#{controller}#create", params) if actions.include?(:create)
end end
it 'to #new' do it 'to #new' do
expect(get("/gitlab/gitlabhq/#{controller_path}/new")).to route_to("projects/#{controller}#new", namespace_id: 'gitlab', project_id: 'gitlabhq') if actions.include?(:new) expect(get("/gitlab/gitlabhq/#{controller_path}/new")).to route_to("projects/#{controller}#new", params) if actions.include?(:new)
end end
it 'to #edit' do it 'to #edit' do
expect(get("/gitlab/gitlabhq/#{controller_path}/1/edit")).to route_to("projects/#{controller}#edit", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') if actions.include?(:edit) expect(get("/gitlab/gitlabhq/#{controller_path}/1/edit")).to route_to("projects/#{controller}#edit", params.merge(**id, **format)) if actions.include?(:edit)
end end
it 'to #show' do it 'to #show' do
expect(get("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#show", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') if actions.include?(:show) expect(get("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#show", params.merge(**id, **format)) if actions.include?(:show)
end end
it 'to #update' do it 'to #update' do
expect(put("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#update", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') if actions.include?(:update) expect(put("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#update", params.merge(id)) if actions.include?(:update)
end end
it 'to #destroy' do it 'to #destroy' do
expect(delete("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#destroy", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') if actions.include?(:destroy) expect(delete("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#destroy", params.merge(**id, **format)) if actions.include?(:destroy)
end end
end end
...@@ -150,12 +153,13 @@ describe 'project routing' do ...@@ -150,12 +153,13 @@ describe 'project routing' do
end end
it 'to #history' do it 'to #history' do
expect(get('/gitlab/gitlabhq/wikis/1/history')).to route_to('projects/wikis#history', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') expect(get('/gitlab/gitlabhq/wikis/1/history')).to route_to('projects/wikis#history', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', format: :html)
end end
it_behaves_like 'RESTful project resources' do it_behaves_like 'RESTful project resources' do
let(:actions) { [:create, :edit, :show, :destroy] } let(:actions) { [:create, :edit, :show, :destroy] }
let(:controller) { 'wikis' } let(:controller) { 'wikis' }
let(:format) { { format: :html } }
end end
end end
......
...@@ -55,10 +55,15 @@ describe RepositoryForkWorker do ...@@ -55,10 +55,15 @@ describe RepositoryForkWorker do
it 'flushes various caches' do it 'flushes various caches' do
expect_fork_repository.and_return(true) expect_fork_repository.and_return(true)
expect_any_instance_of(Repository).to receive(:expire_emptiness_caches) # Works around https://github.com/rspec/rspec-mocks/issues/910
expect(Project).to receive(:find).with(fork_project.id).and_return(fork_project)
expect(fork_project.repository).to receive(:expire_emptiness_caches)
.and_call_original .and_call_original
expect(fork_project.repository).to receive(:expire_exists_cache)
expect_any_instance_of(Repository).to receive(:expire_exists_cache) .and_call_original
expect(fork_project.wiki.repository).to receive(:expire_emptiness_caches)
.and_call_original
expect(fork_project.wiki.repository).to receive(:expire_exists_cache)
.and_call_original .and_call_original
perform! perform!
......
...@@ -22,8 +22,11 @@ describe RepositoryImportWorker do ...@@ -22,8 +22,11 @@ describe RepositoryImportWorker do
expect_any_instance_of(Projects::ImportService).to receive(:execute) expect_any_instance_of(Projects::ImportService).to receive(:execute)
.and_return({ status: :ok }) .and_return({ status: :ok })
expect_any_instance_of(Repository).to receive(:expire_emptiness_caches) # Works around https://github.com/rspec/rspec-mocks/issues/910
expect_any_instance_of(Project).to receive(:import_finish) expect(Project).to receive(:find).with(project.id).and_return(project)
expect(project.repository).to receive(:expire_emptiness_caches)
expect(project.wiki.repository).to receive(:expire_emptiness_caches)
expect(project).to receive(:import_finish)
subject.perform(project.id) subject.perform(project.id)
end end
...@@ -34,9 +37,11 @@ describe RepositoryImportWorker do ...@@ -34,9 +37,11 @@ describe RepositoryImportWorker do
expect_any_instance_of(Projects::ImportService).to receive(:execute) expect_any_instance_of(Projects::ImportService).to receive(:execute)
.and_return({ status: :ok }) .and_return({ status: :ok })
expect_any_instance_of(Project).to receive(:after_import).and_call_original # Works around https://github.com/rspec/rspec-mocks/issues/910
expect_any_instance_of(Repository).to receive(:expire_emptiness_caches) expect(Project).to receive(:find).with(project.id).and_return(project)
expect_any_instance_of(Project).to receive(:import_finish) expect(project.repository).to receive(:expire_emptiness_caches)
expect(project.wiki.repository).to receive(:expire_emptiness_caches)
expect(project).to receive(:import_finish)
subject.perform(project.id) subject.perform(project.id)
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