summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/merge_request_templates/Security Release.md8
-rw-r--r--app/assets/javascripts/diffs/components/diff_file_header.vue5
-rw-r--r--app/assets/javascripts/environments/components/environments_table.vue2
-rw-r--r--app/assets/javascripts/pipelines/mixins/graph_pipeline_bundle_mixin.js10
-rw-r--r--app/assets/javascripts/pipelines/pipeline_details_bundle.js9
-rw-r--r--app/assets/javascripts/pipelines/stores/pipeline_store.js1
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue2
-rw-r--r--app/assets/stylesheets/framework.scss1
-rw-r--r--app/assets/stylesheets/framework/sortable.scss92
-rw-r--r--app/assets/stylesheets/pages/environments.scss4
-rw-r--r--app/assets/stylesheets/pages/issuable.scss8
-rw-r--r--app/controllers/concerns/authenticates_with_two_factor.rb6
-rw-r--r--app/controllers/concerns/creates_commit.rb25
-rw-r--r--app/controllers/concerns/lfs_request.rb6
-rw-r--r--app/controllers/concerns/membership_actions.rb35
-rw-r--r--app/controllers/concerns/spammable_actions.rb6
-rw-r--r--app/controllers/concerns/uploads_actions.rb4
-rw-r--r--app/controllers/dashboard/todos_controller.rb4
-rw-r--r--app/controllers/graphql_controller.rb5
-rw-r--r--app/controllers/groups/runners_controller.rb10
-rw-r--r--app/controllers/groups/settings/ci_cd_controller.rb2
-rw-r--r--app/controllers/import/bitbucket_controller.rb2
-rw-r--r--app/controllers/import/bitbucket_server_controller.rb12
-rw-r--r--app/controllers/import/fogbugz_controller.rb6
-rw-r--r--app/controllers/import/gitea_controller.rb2
-rw-r--r--app/controllers/import/gitlab_controller.rb2
-rw-r--r--app/controllers/import/gitlab_projects_controller.rb4
-rw-r--r--app/controllers/import/google_code_controller.rb12
-rw-r--r--app/controllers/projects/blob_controller.rb4
-rw-r--r--app/controllers/projects/branches_controller.rb4
-rw-r--r--app/controllers/projects/deploy_keys_controller.rb2
-rw-r--r--app/controllers/projects/git_http_client_controller.rb14
-rw-r--r--app/controllers/projects/git_http_controller.rb4
-rw-r--r--app/controllers/projects/group_links_controller.rb2
-rw-r--r--app/controllers/projects/hooks_controller.rb2
-rw-r--r--app/controllers/projects/imports_controller.rb4
-rw-r--r--app/controllers/projects/issues_controller.rb4
-rw-r--r--app/controllers/projects/jobs_controller.rb2
-rw-r--r--app/controllers/projects/labels_controller.rb2
-rw-r--r--app/controllers/projects/lfs_api_controller.rb4
-rw-r--r--app/controllers/projects/merge_requests/conflicts_controller.rb8
-rw-r--r--app/controllers/projects/merge_requests_controller.rb4
-rw-r--r--app/controllers/projects/mirrors_controller.rb4
-rw-r--r--app/controllers/projects/pipeline_schedules_controller.rb8
-rw-r--r--app/controllers/projects/runners_controller.rb10
-rw-r--r--app/controllers/projects/services_controller.rb10
-rw-r--r--app/controllers/projects/settings/ci_cd_controller.rb6
-rw-r--r--app/controllers/projects/tree_controller.rb2
-rw-r--r--app/controllers/projects/triggers_controller.rb14
-rw-r--r--app/controllers/projects/wikis_controller.rb12
-rw-r--r--app/finders/projects_finder.rb2
-rw-r--r--app/helpers/search_helper.rb7
-rw-r--r--app/models/project.rb53
-rw-r--r--app/models/project_wiki.rb4
-rw-r--r--app/models/repository.rb8
-rw-r--r--app/serializers/diff_file_entity.rb2
-rw-r--r--app/services/merge_requests/merge_service.rb4
-rw-r--r--app/views/layouts/nav/sidebar/_group.html.haml2
-rw-r--r--app/views/layouts/nav/sidebar/_project.html.haml2
-rw-r--r--app/views/projects/artifacts/browse.html.haml2
-rw-r--r--app/views/search/_results.html.haml2
-rw-r--r--app/views/search/results/_blob.html.haml2
-rw-r--r--app/views/search/results/_wiki_blob.html.haml2
-rw-r--r--app/views/shared/milestones/_milestone.html.haml2
-rw-r--r--app/workers/post_receive.rb4
-rw-r--r--changelogs/unreleased/48132-display-output-from-pre-receive-scripts.yml5
-rw-r--r--changelogs/unreleased/49910-reopening-a-closed-milestone-from-the-closed-milestones-page-fails2.yml5
-rw-r--r--changelogs/unreleased/59296-add-filter-by-title-milestones-api.yml5
-rw-r--r--changelogs/unreleased/59502-fix-breadcrumb-artifacts.yml5
-rw-r--r--changelogs/unreleased/issue_58547.yml5
-rw-r--r--changelogs/unreleased/sh-optimize-projects-api.yml5
-rw-r--r--db/fixtures/development/25_api_personal_access_token.rb15
-rw-r--r--doc/README.md2
-rw-r--r--doc/administration/custom_hooks.md20
-rw-r--r--doc/administration/img/custom_hooks_error_msg.pngbin44892 -> 80442 bytes
-rw-r--r--doc/administration/repository_storage_types.md3
-rw-r--r--doc/api/group_milestones.md2
-rw-r--r--doc/api/milestones.md2
-rw-r--r--doc/ci/pipelines.md4
-rw-r--r--doc/ci/variables/README.md2
-rw-r--r--doc/development/go_guide/index.md4
-rw-r--r--doc/install/aws/index.md8
-rw-r--r--doc/topics/autodevops/index.md2
-rw-r--r--doc/user/group/clusters/index.md2
-rw-r--r--doc/user/project/index.md4
-rw-r--r--doc/user/project/merge_requests/index.md2
-rw-r--r--jest.config.js1
-rw-r--r--lib/api/helpers.rb6
-rw-r--r--lib/api/helpers/internal_helpers.rb16
-rw-r--r--lib/api/internal.rb2
-rw-r--r--lib/api/milestone_responses.rb2
-rw-r--r--lib/gitlab/git/pre_receive_error.rb31
-rw-r--r--lib/gitlab/gl_repository.rb35
-rw-r--r--lib/gitlab/gl_repository/repo_type.rb42
-rw-r--r--lib/gitlab/repo_path.rb25
-rw-r--r--lib/gitlab/workhorse.rb4
-rw-r--r--locale/gitlab.pot240
-rw-r--r--package.json2
-rw-r--r--qa/qa/page/project/job/show.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb3
-rw-r--r--spec/controllers/graphql_controller_spec.rb45
-rw-r--r--spec/features/milestone_spec.rb28
-rw-r--r--spec/features/projects/artifacts/user_browses_artifacts_spec.rb6
-rw-r--r--spec/features/tags/master_deletes_tag_spec.rb2
-rw-r--r--spec/frontend/environment.js27
-rw-r--r--spec/frontend/helpers/fixtures.js2
-rw-r--r--spec/javascripts/diffs/components/diff_file_header_spec.js3
-rw-r--r--spec/javascripts/notes/components/note_form_spec.js18
-rw-r--r--spec/javascripts/pipelines/graph/stage_column_component_spec.js2
-rw-r--r--spec/javascripts/sidebar/assignees_spec.js13
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js2
-rw-r--r--spec/lib/gitlab/git/pre_receive_error_spec.rb16
-rw-r--r--spec/lib/gitlab/gitaly_client/operation_service_spec.rb10
-rw-r--r--spec/lib/gitlab/gl_repository/repo_type_spec.rb64
-rw-r--r--spec/lib/gitlab/gl_repository_spec.rb4
-rw-r--r--spec/lib/gitlab/repo_path_spec.rb20
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb10
-rw-r--r--spec/models/project_spec.rb63
-rw-r--r--spec/requests/api/internal_spec.rb6
-rw-r--r--spec/services/merge_requests/ff_merge_service_spec.rb2
-rw-r--r--spec/services/merge_requests/merge_service_spec.rb2
-rw-r--r--spec/services/tags/create_service_spec.rb2
-rw-r--r--spec/support/api/milestones_shared_examples.rb9
123 files changed, 1097 insertions, 285 deletions
diff --git a/.gitlab/merge_request_templates/Security Release.md b/.gitlab/merge_request_templates/Security Release.md
index 246f2dae009..42314f9b2dd 100644
--- a/.gitlab/merge_request_templates/Security Release.md
+++ b/.gitlab/merge_request_templates/Security Release.md
@@ -7,6 +7,10 @@ See [the general developer security release guidelines](https://gitlab.com/gitla
This merge request _must not_ close the corresponding security issue _unless_ it
targets master.
+When submitting a merge request for CE, a corresponding EE merge request is
+always required. This makes it easier to merge security merge requests, as
+manually merging CE into EE is no longer required.
+
-->
## Related issues
@@ -20,8 +24,8 @@ targets master.
- [ ] Title of this MR is the same as for all backports
- [ ] A [CHANGELOG entry](https://docs.gitlab.com/ee/development/changelog.html) is added without a `merge_request` value, with `type` set to `security`
- [ ] Add a link to this MR in the `links` section of related issue
-- [ ] Add a link to an EE MR if required
-- [ ] Assign to a reviewer
+- [ ] Set up an EE MR (always required for CE merge requests): EE_MR_LINK_HERE
+- [ ] Assign to a reviewer (that is not a release manager)
## Reviewer checklist
diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue
index a5125c3d077..d41d1464166 100644
--- a/app/assets/javascripts/diffs/components/diff_file_header.vue
+++ b/app/assets/javascripts/diffs/components/diff_file_header.vue
@@ -128,9 +128,6 @@ export default {
isModeChanged() {
return this.diffFile.viewer.name === diffViewerModes.mode_changed;
},
- showExpandDiffToFullFileEnabled() {
- return gon.features.expandDiffFullFile && !this.diffFile.is_fully_expanded;
- },
},
mounted() {
polyfillSticky(this.$refs.header);
@@ -258,7 +255,7 @@ export default {
<icon name="external-link" />
</gl-button>
<gl-button
- v-if="showExpandDiffToFullFileEnabled"
+ v-if="!diffFile.is_fully_expanded"
class="expand-file js-expand-file"
@click="toggleFullDiff(diffFile.file_path)"
>
diff --git a/app/assets/javascripts/environments/components/environments_table.vue b/app/assets/javascripts/environments/components/environments_table.vue
index ff4e16178e8..55613d815ce 100644
--- a/app/assets/javascripts/environments/components/environments_table.vue
+++ b/app/assets/javascripts/environments/components/environments_table.vue
@@ -99,7 +99,7 @@ export default {
/>
<div
- v-if="shouldRenderDeployBoard"
+ v-if="shouldRenderDeployBoard(model)"
:key="`deploy-board-row-${i}`"
class="js-deploy-board-row"
>
diff --git a/app/assets/javascripts/pipelines/mixins/graph_pipeline_bundle_mixin.js b/app/assets/javascripts/pipelines/mixins/graph_pipeline_bundle_mixin.js
index 9177943f88a..dd79ade5bc9 100644
--- a/app/assets/javascripts/pipelines/mixins/graph_pipeline_bundle_mixin.js
+++ b/app/assets/javascripts/pipelines/mixins/graph_pipeline_bundle_mixin.js
@@ -1,6 +1,16 @@
+import Flash from '~/flash';
+import { __ } from '~/locale';
+
export default {
methods: {
clickTriggeredByPipeline() {},
clickTriggeredPipeline() {},
+ requestRefreshPipelineGraph() {
+ // When an action is clicked
+ // (wether in the dropdown or in the main nodes, we refresh the big graph)
+ this.mediator
+ .refreshPipeline()
+ .catch(() => Flash(__('An error occurred while making the request.')));
+ },
},
};
diff --git a/app/assets/javascripts/pipelines/pipeline_details_bundle.js b/app/assets/javascripts/pipelines/pipeline_details_bundle.js
index 8adbd39edd4..6660f8120f8 100644
--- a/app/assets/javascripts/pipelines/pipeline_details_bundle.js
+++ b/app/assets/javascripts/pipelines/pipeline_details_bundle.js
@@ -29,15 +29,6 @@ export default () => {
mediator,
};
},
- methods: {
- requestRefreshPipelineGraph() {
- // When an action is clicked
- // (wether in the dropdown or in the main nodes, we refresh the big graph)
- this.mediator
- .refreshPipeline()
- .catch(() => Flash(__('An error occurred while making the request.')));
- },
- },
render(createElement) {
return createElement('pipeline-graph', {
props: {
diff --git a/app/assets/javascripts/pipelines/stores/pipeline_store.js b/app/assets/javascripts/pipelines/stores/pipeline_store.js
index 052e34a8aef..259278b6410 100644
--- a/app/assets/javascripts/pipelines/stores/pipeline_store.js
+++ b/app/assets/javascripts/pipelines/stores/pipeline_store.js
@@ -1,7 +1,6 @@
export default class PipelineStore {
constructor() {
this.state = {};
-
this.state.pipeline = {};
}
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue
index 2a4dff71d9b..11bc8c73ee9 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue
@@ -80,7 +80,7 @@ export default {
<status-icon :show-disabled-button="true" status="warning" />
<div class="media-body space-children">
<span class="bold">
- <span v-if="mr.mergeError" class="has-error-message"> {{ mergeError }}. </span>
+ <span v-if="mr.mergeError" class="has-error-message"> {{ mergeError }} </span>
<span v-else> {{ s__('mrWidget|Merge failed.') }} </span>
<span :class="{ 'has-custom-error': mr.mergeError }"> {{ timerText }} </span>
</span>
diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss
index 216877a4461..ab9047c54e4 100644
--- a/app/assets/stylesheets/framework.scss
+++ b/app/assets/stylesheets/framework.scss
@@ -60,6 +60,7 @@
@import 'framework/memory_graph';
@import 'framework/responsive_tables';
@import 'framework/stacked_progress_bar';
+@import 'framework/sortable';
@import 'framework/ci_variable_list';
@import 'framework/feature_highlight';
@import 'framework/terms';
diff --git a/app/assets/stylesheets/framework/sortable.scss b/app/assets/stylesheets/framework/sortable.scss
new file mode 100644
index 00000000000..8c070200135
--- /dev/null
+++ b/app/assets/stylesheets/framework/sortable.scss
@@ -0,0 +1,92 @@
+.sortable-container {
+ background-color: $gray-light;
+
+ .flex-list {
+ padding: 5px;
+ margin-bottom: 0;
+ }
+}
+
+.sortable-row {
+ .flex-row {
+ display: flex;
+
+ &.issuable-info-container {
+ padding-right: 0;
+ }
+ }
+
+ .sortable-link {
+ color: $black;
+ }
+}
+
+.gl-sortable {
+ .header {
+ user-select: none;
+
+ &:hover {
+ cursor: pointer;
+ background-color: $gray-100;
+ }
+
+ &:focus {
+ outline: 1px solid $blue-300;
+ }
+ }
+}
+
+.related-issues-list-item {
+ .card-body,
+ .issuable-info-container {
+ padding: $gl-padding-4 $gl-padding-4 $gl-padding-4 $gl-padding;
+
+ .block-truncated {
+ padding: $gl-padding-8 0;
+ line-height: $gl-btn-line-height;
+ }
+
+ @include media-breakpoint-down(md) {
+ padding-left: $gl-padding;
+
+ .block-truncated {
+ flex-direction: column-reverse;
+ padding: $gl-padding-4 0;
+
+ .text-secondary {
+ margin-top: $gl-padding-4;
+ }
+
+ .issue-token-title-text {
+ display: block;
+ }
+ }
+
+ .issue-item-remove-button {
+ align-self: baseline;
+ }
+ }
+
+ @include media-breakpoint-only(md) {
+ .block-truncated .issue-token-title-text {
+ white-space: nowrap;
+ }
+
+ .issue-item-remove-button {
+ align-self: center;
+ }
+ }
+
+ @include media-breakpoint-down(sm) {
+ padding-left: $gl-padding-8;
+
+ .block-truncated .issue-token-title-text {
+ white-space: normal;
+ }
+ }
+ }
+
+ &.is-dragging {
+ padding: 0;
+ }
+}
diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss
index 61ecf133b02..0eb854ecf98 100644
--- a/app/assets/stylesheets/pages/environments.scss
+++ b/app/assets/stylesheets/pages/environments.scss
@@ -346,7 +346,9 @@
}
> .popover-title,
- > .popover-content {
+ > .popover-content,
+ > .popover-header,
+ > .popover-body {
padding: 8px;
font-size: 12px;
white-space: nowrap;
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 9e2375b84d0..6415d902ca6 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -256,6 +256,10 @@
.selectbox {
display: none;
+
+ &.show {
+ display: block;
+ }
}
.btn-clipboard:hover {
@@ -309,6 +313,7 @@
}
.no-value,
+ .btn-default-hover-link,
.btn-secondary-hover-link {
color: $gl-text-color-secondary;
}
@@ -592,7 +597,6 @@
margin: -7px;
}
-
.user-list {
display: flex;
flex-wrap: wrap;
@@ -716,6 +720,7 @@
.issuable-main-info {
flex: 1 auto;
margin-right: 10px;
+ min-width: 0;
.issue-weight-icon {
vertical-align: sub;
@@ -777,6 +782,7 @@
@media(max-width: map-get($grid-breakpoints, lg)-1) {
.task-status,
.issuable-due-date,
+ .issuable-weight,
.project-ref-path {
display: none;
}
diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb
index 5507328f8ae..d5c4712bd78 100644
--- a/app/controllers/concerns/authenticates_with_two_factor.rb
+++ b/app/controllers/concerns/authenticates_with_two_factor.rb
@@ -36,7 +36,7 @@ module AuthenticatesWithTwoFactor
end
def locked_user_redirect(user)
- flash.now[:alert] = 'Invalid Login or password'
+ flash.now[:alert] = _('Invalid Login or password')
render 'devise/sessions/new'
end
@@ -66,7 +66,7 @@ module AuthenticatesWithTwoFactor
else
user.increment_failed_attempts!
Gitlab::AppLogger.info("Failed Login: user=#{user.username} ip=#{request.remote_ip} method=OTP")
- flash.now[:alert] = 'Invalid two-factor code.'
+ flash.now[:alert] = _('Invalid two-factor code.')
prompt_for_two_factor(user)
end
end
@@ -83,7 +83,7 @@ module AuthenticatesWithTwoFactor
else
user.increment_failed_attempts!
Gitlab::AppLogger.info("Failed Login: user=#{user.username} ip=#{request.remote_ip} method=U2F")
- flash.now[:alert] = 'Authentication via U2F device failed.'
+ flash.now[:alert] = _('Authentication via U2F device failed.')
prompt_for_two_factor(user)
end
end
diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb
index b3777fd2b0f..e8e681ce649 100644
--- a/app/controllers/concerns/creates_commit.rb
+++ b/app/controllers/concerns/creates_commit.rb
@@ -31,7 +31,7 @@ module CreatesCommit
respond_to do |format|
format.html { redirect_to success_path }
- format.json { render json: { message: "success", filePath: success_path } }
+ format.json { render json: { message: _("success"), filePath: success_path } }
end
else
flash[:alert] = result[:message]
@@ -45,7 +45,7 @@ module CreatesCommit
redirect_to failure_path
end
end
- format.json { render json: { message: "failed", filePath: failure_path } }
+ format.json { render json: { message: _("failed"), filePath: failure_path } }
end
end
end
@@ -60,15 +60,22 @@ module CreatesCommit
private
def update_flash_notice(success_notice)
- flash[:notice] = success_notice || "Your changes have been successfully committed."
+ flash[:notice] = success_notice || _("Your changes have been successfully committed.")
if create_merge_request?
- if merge_request_exists?
- flash[:notice] = nil
- else
- target = different_project? ? "project" : "branch"
- flash[:notice] = flash[:notice] + " You can now submit a merge request to get this change into the original #{target}."
- end
+ flash[:notice] =
+ if merge_request_exists?
+ nil
+ else
+ mr_message =
+ if different_project?
+ _("You can now submit a merge request to get this change into the original project.")
+ else
+ _("You can now submit a merge request to get this change into the original branch.")
+ end
+
+ flash[:notice] += " " + mr_message
+ end
end
end
diff --git a/app/controllers/concerns/lfs_request.rb b/app/controllers/concerns/lfs_request.rb
index 57e444319e0..f7137a04437 100644
--- a/app/controllers/concerns/lfs_request.rb
+++ b/app/controllers/concerns/lfs_request.rb
@@ -26,7 +26,7 @@ module LfsRequest
render(
json: {
- message: 'Git LFS is not enabled on this GitLab server, contact your admin.',
+ message: _('Git LFS is not enabled on this GitLab server, contact your admin.'),
documentation_url: help_url
},
status: :not_implemented
@@ -51,7 +51,7 @@ module LfsRequest
def render_lfs_forbidden
render(
json: {
- message: 'Access forbidden. Check your access level.',
+ message: _('Access forbidden. Check your access level.'),
documentation_url: help_url
},
content_type: CONTENT_TYPE,
@@ -62,7 +62,7 @@ module LfsRequest
def render_lfs_not_found
render(
json: {
- message: 'Not found.',
+ message: _('Not found.'),
documentation_url: help_url
},
content_type: CONTENT_TYPE,
diff --git a/app/controllers/concerns/membership_actions.rb b/app/controllers/concerns/membership_actions.rb
index 6402e01ddc0..0b2756c0c6a 100644
--- a/app/controllers/concerns/membership_actions.rb
+++ b/app/controllers/concerns/membership_actions.rb
@@ -9,7 +9,7 @@ module MembershipActions
result = Members::CreateService.new(current_user, create_params).execute(membershipable)
if result[:status] == :success
- redirect_to members_page_url, notice: 'Users were successfully added.'
+ redirect_to members_page_url, notice: _('Users were successfully added.')
else
redirect_to members_page_url, alert: result[:message]
end
@@ -35,9 +35,16 @@ module MembershipActions
respond_to do |format|
format.html do
- source = source_type == 'group' ? 'group and any subresources' : source_type
+ message =
+ begin
+ case membershipable
+ when Namespace
+ _("User was successfully removed from group and any subresources.")
+ else
+ _("User was successfully removed from project.")
+ end
+ end
- message = "User was successfully removed from #{source}."
redirect_to members_page_url, notice: message
end
@@ -49,7 +56,7 @@ module MembershipActions
membershipable.request_access(current_user)
redirect_to polymorphic_path(membershipable),
- notice: 'Your request for access has been queued for review.'
+ notice: _('Your request for access has been queued for review.')
end
def approve_access_request
@@ -68,9 +75,9 @@ module MembershipActions
notice =
if member.request?
- "Your access request to the #{source_type} has been withdrawn."
+ _("Your access request to the %{source_type} has been withdrawn.") % { source_type: source_type }
else
- "You left the \"#{membershipable.human_name}\" #{source_type}."
+ _("You left the \"%{membershipable_human_name}\" %{source_type}.") % { membershipable_human_name: membershipable.human_name, source_type: source_type }
end
respond_to do |format|
@@ -90,9 +97,9 @@ module MembershipActions
if member.invite?
member.resend_invite
- redirect_to members_page_url, notice: 'The invitation was successfully resent.'
+ redirect_to members_page_url, notice: _('The invitation was successfully resent.')
else
- redirect_to members_page_url, alert: 'The invitation has already been accepted.'
+ redirect_to members_page_url, alert: _('The invitation has already been accepted.')
end
end
@@ -125,6 +132,16 @@ module MembershipActions
end
def source_type
- @source_type ||= membershipable.class.to_s.humanize(capitalize: false)
+ @source_type ||=
+ begin
+ case membershipable
+ when Namespace
+ _("group")
+ when Project
+ _("project")
+ else
+ raise "Unknown membershipable type: #{membershipable}!"
+ end
+ end
end
end
diff --git a/app/controllers/concerns/spammable_actions.rb b/app/controllers/concerns/spammable_actions.rb
index c3a1b12af84..a8ffa33f1c7 100644
--- a/app/controllers/concerns/spammable_actions.rb
+++ b/app/controllers/concerns/spammable_actions.rb
@@ -12,9 +12,9 @@ module SpammableActions
def mark_as_spam
if SpamService.new(spammable).mark_as_spam!
- redirect_to spammable_path, notice: "#{spammable.spammable_entity_type.titlecase} was submitted to Akismet successfully."
+ redirect_to spammable_path, notice: _("%{spammable_titlecase} was submitted to Akismet successfully.") % { spammable_titlecase: spammable.spammable_entity_type.titlecase }
else
- redirect_to spammable_path, alert: 'Error with Akismet. Please check the logs for more info.'
+ redirect_to spammable_path, alert: _('Error with Akismet. Please check the logs for more info.')
end
end
@@ -33,7 +33,7 @@ module SpammableActions
ensure_spam_config_loaded!
if params[:recaptcha_verification]
- flash[:alert] = 'There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.'
+ flash[:alert] = _('There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.')
end
respond_to do |format|
diff --git a/app/controllers/concerns/uploads_actions.rb b/app/controllers/concerns/uploads_actions.rb
index 4ec0e94df9a..59f6d3452a3 100644
--- a/app/controllers/concerns/uploads_actions.rb
+++ b/app/controllers/concerns/uploads_actions.rb
@@ -16,7 +16,7 @@ module UploadsActions
end
else
format.json do
- render json: 'Invalid file.', status: :unprocessable_entity
+ render json: _('Invalid file.'), status: :unprocessable_entity
end
end
end
@@ -57,7 +57,7 @@ module UploadsActions
render json: authorized
rescue SocketError
- render json: "Error uploading file", status: :internal_server_error
+ render json: _("Error uploading file"), status: :internal_server_error
end
private
diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb
index 3fa582cf25b..f173c263474 100644
--- a/app/controllers/dashboard/todos_controller.rb
+++ b/app/controllers/dashboard/todos_controller.rb
@@ -21,7 +21,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController
format.html do
redirect_to dashboard_todos_path,
status: 302,
- notice: 'Todo was successfully marked as done.'
+ notice: _('Todo was successfully marked as done.')
end
format.js { head :ok }
format.json { render json: todos_counts }
@@ -32,7 +32,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController
updated_ids = TodoService.new.mark_todos_as_done(@todos, current_user)
respond_to do |format|
- format.html { redirect_to dashboard_todos_path, status: 302, notice: 'All todos were marked as done.' }
+ format.html { redirect_to dashboard_todos_path, status: 302, notice: _('All todos were marked as done.') }
format.js { head :ok }
format.json { render json: todos_counts.merge(updated_ids: updated_ids) }
end
diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb
index e147d32be2e..7b5dc22815c 100644
--- a/app/controllers/graphql_controller.rb
+++ b/app/controllers/graphql_controller.rb
@@ -12,6 +12,7 @@ class GraphqlController < ApplicationController
protect_from_forgery with: :null_session, only: :execute
before_action :check_graphql_feature_flag!
+ before_action :authorize_access_api!
before_action(only: [:execute]) { authenticate_sessionless_user!(:api) }
def execute
@@ -37,6 +38,10 @@ class GraphqlController < ApplicationController
private
+ def authorize_access_api!
+ access_denied!("API not accessible for user.") unless can?(current_user, :access_api)
+ end
+
# Overridden from the ApplicationController to make the response look like
# a GraphQL response. That is nicely picked up in Graphiql.
def render_404
diff --git a/app/controllers/groups/runners_controller.rb b/app/controllers/groups/runners_controller.rb
index dd8fbf7a029..f8e32451b02 100644
--- a/app/controllers/groups/runners_controller.rb
+++ b/app/controllers/groups/runners_controller.rb
@@ -16,7 +16,7 @@ class Groups::RunnersController < Groups::ApplicationController
def update
if Ci::UpdateRunnerService.new(@runner).update(runner_params)
- redirect_to group_runner_path(@group, @runner), notice: 'Runner was successfully updated.'
+ redirect_to group_runner_path(@group, @runner), notice: _('Runner was successfully updated.')
else
render 'edit'
end
@@ -30,17 +30,17 @@ class Groups::RunnersController < Groups::ApplicationController
def resume
if Ci::UpdateRunnerService.new(@runner).update(active: true)
- redirect_to group_settings_ci_cd_path(@group, anchor: 'runners-settings'), notice: 'Runner was successfully updated.'
+ redirect_to group_settings_ci_cd_path(@group, anchor: 'runners-settings'), notice: _('Runner was successfully updated.')
else
- redirect_to group_settings_ci_cd_path(@group, anchor: 'runners-settings'), alert: 'Runner was not updated.'
+ redirect_to group_settings_ci_cd_path(@group, anchor: 'runners-settings'), alert: _('Runner was not updated.')
end
end
def pause
if Ci::UpdateRunnerService.new(@runner).update(active: false)
- redirect_to group_settings_ci_cd_path(@group, anchor: 'runners-settings'), notice: 'Runner was successfully updated.'
+ redirect_to group_settings_ci_cd_path(@group, anchor: 'runners-settings'), notice: _('Runner was successfully updated.')
else
- redirect_to group_settings_ci_cd_path(@group, anchor: 'runners-settings'), alert: 'Runner was not updated.'
+ redirect_to group_settings_ci_cd_path(@group, anchor: 'runners-settings'), alert: _('Runner was not updated.')
end
end
diff --git a/app/controllers/groups/settings/ci_cd_controller.rb b/app/controllers/groups/settings/ci_cd_controller.rb
index f378f7ac79a..c465e622de0 100644
--- a/app/controllers/groups/settings/ci_cd_controller.rb
+++ b/app/controllers/groups/settings/ci_cd_controller.rb
@@ -13,7 +13,7 @@ module Groups
def reset_registration_token
@group.reset_runners_token!
- flash[:notice] = 'New runners registration token has been generated!'
+ flash[:notice] = _('GroupSettings|New runners registration token has been generated!')
redirect_to group_settings_ci_cd_path
end
diff --git a/app/controllers/import/bitbucket_controller.rb b/app/controllers/import/bitbucket_controller.rb
index 2b1395f364f..293d76ea765 100644
--- a/app/controllers/import/bitbucket_controller.rb
+++ b/app/controllers/import/bitbucket_controller.rb
@@ -62,7 +62,7 @@ class Import::BitbucketController < Import::BaseController
render json: { errors: project_save_error(project) }, status: :unprocessable_entity
end
else
- render json: { errors: 'This namespace has already been taken! Please choose another one.' }, status: :unprocessable_entity
+ render json: { errors: _('This namespace has already been taken! Please choose another one.') }, status: :unprocessable_entity
end
end
diff --git a/app/controllers/import/bitbucket_server_controller.rb b/app/controllers/import/bitbucket_server_controller.rb
index f333e43b892..643a3bfed1f 100644
--- a/app/controllers/import/bitbucket_server_controller.rb
+++ b/app/controllers/import/bitbucket_server_controller.rb
@@ -25,7 +25,7 @@ class Import::BitbucketServerController < Import::BaseController
repo = bitbucket_client.repo(@project_key, @repo_slug)
unless repo
- return render json: { errors: "Project #{@project_key}/#{@repo_slug} could not be found" }, status: :unprocessable_entity
+ return render json: { errors: _("Project %{project_repo} could not be found") % { project_repo: "#{@project_key}/#{@repo_slug}" } }, status: :unprocessable_entity
end
project_name = params[:new_name].presence || repo.name
@@ -41,10 +41,10 @@ class Import::BitbucketServerController < Import::BaseController
render json: { errors: project_save_error(project) }, status: :unprocessable_entity
end
else
- render json: { errors: 'This namespace has already been taken! Please choose another one.' }, status: :unprocessable_entity
+ render json: { errors: _('This namespace has already been taken! Please choose another one.') }, status: :unprocessable_entity
end
- rescue BitbucketServer::Connection::ConnectionError => e
- render json: { errors: "Unable to connect to server: #{e}" }, status: :unprocessable_entity
+ rescue BitbucketServer::Connection::ConnectionError => error
+ render json: { errors: _("Unable to connect to server: %{error}") % { error: error } }, status: :unprocessable_entity
end
def configure
@@ -65,8 +65,8 @@ class Import::BitbucketServerController < Import::BaseController
already_added_projects_names = @already_added_projects.pluck(:import_source)
@repos.reject! { |repo| already_added_projects_names.include?(repo.browse_url) }
- rescue BitbucketServer::Connection::ConnectionError => e
- flash[:alert] = "Unable to connect to server: #{e}"
+ rescue BitbucketServer::Connection::ConnectionError => error
+ flash[:alert] = _("Unable to connect to server: %{error}") % { error: error }
clear_session_data
redirect_to new_import_bitbucket_server_path
end
diff --git a/app/controllers/import/fogbugz_controller.rb b/app/controllers/import/fogbugz_controller.rb
index 5a439e6de78..a37ba682b91 100644
--- a/app/controllers/import/fogbugz_controller.rb
+++ b/app/controllers/import/fogbugz_controller.rb
@@ -14,7 +14,7 @@ class Import::FogbugzController < Import::BaseController
res = Gitlab::FogbugzImport::Client.new(import_params.symbolize_keys)
rescue
# If the URI is invalid various errors can occur
- return redirect_to new_import_fogbugz_path, alert: 'Could not connect to FogBugz, check your URL'
+ return redirect_to new_import_fogbugz_path, alert: _('Could not connect to FogBugz, check your URL')
end
session[:fogbugz_token] = res.get_token
session[:fogbugz_uri] = params[:uri]
@@ -29,14 +29,14 @@ class Import::FogbugzController < Import::BaseController
user_map = params[:users]
unless user_map.is_a?(Hash) && user_map.all? { |k, v| !v[:name].blank? }
- flash.now[:alert] = 'All users must have a name.'
+ flash.now[:alert] = _('All users must have a name.')
return render 'new_user_map'
end
session[:fogbugz_user_map] = user_map
- flash[:notice] = 'The user map has been saved. Continue by selecting the projects you want to import.'
+ flash[:notice] = _('The user map has been saved. Continue by selecting the projects you want to import.')
redirect_to status_import_fogbugz_path
end
diff --git a/app/controllers/import/gitea_controller.rb b/app/controllers/import/gitea_controller.rb
index 68ad8650dba..a23b2f8139e 100644
--- a/app/controllers/import/gitea_controller.rb
+++ b/app/controllers/import/gitea_controller.rb
@@ -46,7 +46,7 @@ class Import::GiteaController < Import::GithubController
def provider_auth
if session[access_token_key].blank? || provider_url.blank?
redirect_to new_import_gitea_url,
- alert: 'You need to specify both an Access Token and a Host URL.'
+ alert: _('You need to specify both an Access Token and a Host URL.')
end
end
diff --git a/app/controllers/import/gitlab_controller.rb b/app/controllers/import/gitlab_controller.rb
index 498de0b07b8..5ec8e9e6fc5 100644
--- a/app/controllers/import/gitlab_controller.rb
+++ b/app/controllers/import/gitlab_controller.rb
@@ -42,7 +42,7 @@ class Import::GitlabController < Import::BaseController
render json: { errors: project_save_error(project) }, status: :unprocessable_entity
end
else
- render json: { errors: 'This namespace has already been taken! Please choose another one.' }, status: :unprocessable_entity
+ render json: { errors: _('This namespace has already been taken! Please choose another one.') }, status: :unprocessable_entity
end
end
diff --git a/app/controllers/import/gitlab_projects_controller.rb b/app/controllers/import/gitlab_projects_controller.rb
index 354fba5d204..89889141be6 100644
--- a/app/controllers/import/gitlab_projects_controller.rb
+++ b/app/controllers/import/gitlab_projects_controller.rb
@@ -13,7 +13,7 @@ class Import::GitlabProjectsController < Import::BaseController
def create
unless file_is_valid?
- return redirect_back_or_default(options: { alert: "You need to upload a GitLab project export archive (ending in .gz)." })
+ return redirect_back_or_default(options: { alert: _("You need to upload a GitLab project export archive (ending in .gz).") })
end
@project = ::Projects::GitlabProjectsImportService.new(current_user, project_params).execute
@@ -21,7 +21,7 @@ class Import::GitlabProjectsController < Import::BaseController
if @project.saved?
redirect_to(
project_path(@project),
- notice: "Project '#{@project.name}' is being imported."
+ notice: _("Project '%{project_name}' is being imported.") % { project_name: @project.name }
)
else
redirect_back_or_default(options: { alert: "Project could not be imported: #{@project.errors.full_messages.join(', ')}" })
diff --git a/app/controllers/import/google_code_controller.rb b/app/controllers/import/google_code_controller.rb
index 331f06c3dd6..4dddfbcd20d 100644
--- a/app/controllers/import/google_code_controller.rb
+++ b/app/controllers/import/google_code_controller.rb
@@ -11,18 +11,18 @@ class Import::GoogleCodeController < Import::BaseController
dump_file = params[:dump_file]
unless dump_file.respond_to?(:read)
- return redirect_back_or_default(options: { alert: "You need to upload a Google Takeout archive." })
+ return redirect_back_or_default(options: { alert: _("You need to upload a Google Takeout archive.") })
end
begin
dump = JSON.parse(dump_file.read)
rescue
- return redirect_back_or_default(options: { alert: "The uploaded file is not a valid Google Takeout archive." })
+ return redirect_back_or_default(options: { alert: _("The uploaded file is not a valid Google Takeout archive.") })
end
client = Gitlab::GoogleCodeImport::Client.new(dump)
unless client.valid?
- return redirect_back_or_default(options: { alert: "The uploaded file is not a valid Google Takeout archive." })
+ return redirect_back_or_default(options: { alert: _("The uploaded file is not a valid Google Takeout archive.") })
end
session[:google_code_dump] = dump
@@ -44,13 +44,13 @@ class Import::GoogleCodeController < Import::BaseController
begin
user_map = JSON.parse(user_map_json)
rescue
- flash.now[:alert] = "The entered user map is not a valid JSON user map."
+ flash.now[:alert] = _("The entered user map is not a valid JSON user map.")
return render "new_user_map"
end
unless user_map.is_a?(Hash) && user_map.all? { |k, v| k.is_a?(String) && v.is_a?(String) }
- flash.now[:alert] = "The entered user map is not a valid JSON user map."
+ flash.now[:alert] = _("The entered user map is not a valid JSON user map.")
return render "new_user_map"
end
@@ -62,7 +62,7 @@ class Import::GoogleCodeController < Import::BaseController
session[:google_code_user_map] = user_map
- flash[:notice] = "The user map has been saved. Continue by selecting the projects you want to import."
+ flash[:notice] = _("The user map has been saved. Continue by selecting the projects you want to import.")
redirect_to status_import_google_code_path
end
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 0a33856a8d3..909b17e9c8d 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -29,7 +29,7 @@ class Projects::BlobController < Projects::ApplicationController
end
def create
- create_commit(Files::CreateService, success_notice: "The file has been successfully created.",
+ create_commit(Files::CreateService, success_notice: _("The file has been successfully created."),
success_path: -> { project_blob_path(@project, File.join(@branch_name, @file_path)) },
failure_view: :new,
failure_path: project_new_blob_path(@project, @ref))
@@ -81,7 +81,7 @@ class Projects::BlobController < Projects::ApplicationController
end
def destroy
- create_commit(Files::DeleteService, success_notice: "The file has been successfully deleted.",
+ create_commit(Files::DeleteService, success_notice: _("The file has been successfully deleted."),
success_path: -> { after_delete_path },
failure_view: :show,
failure_path: project_blob_path(@project, @id))
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index 32b7f3207ef..6ff2e222489 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -115,7 +115,7 @@ class Projects::BranchesController < Projects::ApplicationController
DeleteMergedBranchesService.new(@project, current_user).async_execute
redirect_to project_branches_path(@project),
- notice: 'Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes.'
+ notice: _('Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes.')
end
private
@@ -143,7 +143,7 @@ class Projects::BranchesController < Projects::ApplicationController
def redirect_for_legacy_index_sort_or_search
# Normalize a legacy URL with redirect
if request.format != :json && !params[:state].presence && [:sort, :search, :page].any? { |key| params[key].presence }
- redirect_to project_branches_filtered_path(@project, state: 'all'), notice: 'Update your bookmarked URLs as filtered/sorted branches URL has been changed.'
+ redirect_to project_branches_filtered_path(@project, state: 'all'), notice: _('Update your bookmarked URLs as filtered/sorted branches URL has been changed.')
end
end
diff --git a/app/controllers/projects/deploy_keys_controller.rb b/app/controllers/projects/deploy_keys_controller.rb
index 6824a07dc76..514b03e23b5 100644
--- a/app/controllers/projects/deploy_keys_controller.rb
+++ b/app/controllers/projects/deploy_keys_controller.rb
@@ -38,7 +38,7 @@ class Projects::DeployKeysController < Projects::ApplicationController
def update
if deploy_key.update(update_params)
- flash[:notice] = 'Deploy key was successfully updated.'
+ flash[:notice] = _('Deploy key was successfully updated.')
redirect_to_repository_settings(@project, anchor: 'js-deploy-keys-settings')
else
render 'edit'
diff --git a/app/controllers/projects/git_http_client_controller.rb b/app/controllers/projects/git_http_client_controller.rb
index d439db97252..55d5fce9214 100644
--- a/app/controllers/projects/git_http_client_controller.rb
+++ b/app/controllers/projects/git_http_client_controller.rb
@@ -78,7 +78,7 @@ class Projects::GitHttpClientController < Projects::ApplicationController
end
def parse_repo_path
- @project, @wiki, @redirected_path = Gitlab::RepoPath.parse("#{params[:namespace_id]}/#{params[:project_id]}")
+ @project, @repo_type, @redirected_path = Gitlab::RepoPath.parse("#{params[:namespace_id]}/#{params[:project_id]}")
end
def render_missing_personal_access_token
@@ -89,13 +89,19 @@ class Projects::GitHttpClientController < Projects::ApplicationController
end
def repository
- wiki? ? project.wiki.repository : project.repository
+ repo_type.repository_for(project)
end
def wiki?
- parse_repo_path unless defined?(@wiki)
+ repo_type.wiki?
+ end
- @wiki
+ def repo_type
+ parse_repo_path unless defined?(@repo_type)
+ # When there a project did not exist, the parsed repo_type would be empty.
+ # In that case, we want to continue with a regular project repository. As we
+ # could create the project if the user pushing is allowed to do so.
+ @repo_type || Gitlab::GlRepository::PROJECT
end
def handle_basic_authentication(login, password)
diff --git a/app/controllers/projects/git_http_controller.rb b/app/controllers/projects/git_http_controller.rb
index f28af42d1b7..e519cc1f158 100644
--- a/app/controllers/projects/git_http_controller.rb
+++ b/app/controllers/projects/git_http_controller.rb
@@ -55,7 +55,7 @@ class Projects::GitHttpController < Projects::GitHttpClientController
def render_ok
set_workhorse_internal_api_content_type
- render json: Gitlab::Workhorse.git_http_ok(repository, wiki?, user, action_name)
+ render json: Gitlab::Workhorse.git_http_ok(repository, repo_type, user, action_name)
end
def render_403(exception)
@@ -99,7 +99,7 @@ class Projects::GitHttpController < Projects::GitHttpClientController
end
def access_klass
- @access_klass ||= wiki? ? Gitlab::GitAccessWiki : Gitlab::GitAccess
+ @access_klass ||= repo_type.access_checker_class
end
def project_path
diff --git a/app/controllers/projects/group_links_controller.rb b/app/controllers/projects/group_links_controller.rb
index bc942ba9288..dc65f9959db 100644
--- a/app/controllers/projects/group_links_controller.rb
+++ b/app/controllers/projects/group_links_controller.rb
@@ -18,7 +18,7 @@ class Projects::GroupLinksController < Projects::ApplicationController
flash[:alert] = result[:message] if result[:http_status] == 409
else
- flash[:alert] = 'Please select a group.'
+ flash[:alert] = _('Please select a group.')
end
redirect_to project_project_members_path(project)
diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb
index bc84418b79f..5fa0339f44d 100644
--- a/app/controllers/projects/hooks_controller.rb
+++ b/app/controllers/projects/hooks_controller.rb
@@ -32,7 +32,7 @@ class Projects::HooksController < Projects::ApplicationController
def update
if hook.update(hook_params)
- flash[:notice] = 'Hook was successfully updated.'
+ flash[:notice] = _('Hook was successfully updated.')
redirect_to project_settings_integrations_path(@project)
else
render 'edit'
diff --git a/app/controllers/projects/imports_controller.rb b/app/controllers/projects/imports_controller.rb
index 8b33fa85c1e..8ee0bd26daf 100644
--- a/app/controllers/projects/imports_controller.rb
+++ b/app/controllers/projects/imports_controller.rb
@@ -42,9 +42,9 @@ class Projects::ImportsController < Projects::ApplicationController
def finished_notice
if @project.forked?
- 'The project was successfully forked.'
+ _('The project was successfully forked.')
else
- 'The project was successfully imported.'
+ _('The project was successfully imported.')
end
end
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index b9d02a62fc3..e9ed5554ab4 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -95,9 +95,9 @@ class Projects::IssuesController < Projects::ApplicationController
if service.discussions_to_resolve.count(&:resolved?) > 0
flash[:notice] = if service.discussion_to_resolve_id
- "Resolved 1 discussion."
+ _("Resolved 1 discussion.")
else
- "Resolved all discussions."
+ _("Resolved all discussions.")
end
end
diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb
index d5ce790e2d9..35cc32d3e63 100644
--- a/app/controllers/projects/jobs_controller.rb
+++ b/app/controllers/projects/jobs_controller.rb
@@ -122,7 +122,7 @@ class Projects::JobsController < Projects::ApplicationController
def erase
if @build.erase(erased_by: current_user)
redirect_to project_job_path(project, @build),
- notice: "Job has been successfully erased!"
+ notice: _("Job has been successfully erased!")
else
respond_422
end
diff --git a/app/controllers/projects/labels_controller.rb b/app/controllers/projects/labels_controller.rb
index 640038818f2..386a1f00bd2 100644
--- a/app/controllers/projects/labels_controller.rb
+++ b/app/controllers/projects/labels_controller.rb
@@ -132,7 +132,7 @@ class Projects::LabelsController < Projects::ApplicationController
respond_to do |format|
format.html do
redirect_to(project_labels_path(@project),
- notice: 'Failed to promote label due to internal error. Please contact administrators.')
+ notice: _('Failed to promote label due to internal error. Please contact administrators.'))
end
format.js
end
diff --git a/app/controllers/projects/lfs_api_controller.rb b/app/controllers/projects/lfs_api_controller.rb
index be40077d389..42c415757f9 100644
--- a/app/controllers/projects/lfs_api_controller.rb
+++ b/app/controllers/projects/lfs_api_controller.rb
@@ -26,7 +26,7 @@ class Projects::LfsApiController < Projects::GitHttpClientController
def deprecated
render(
json: {
- message: 'Server supports batch API only, please update your Git LFS client to version 1.0.1 and up.',
+ message: _('Server supports batch API only, please update your Git LFS client to version 1.0.1 and up.'),
documentation_url: "#{Gitlab.config.gitlab.url}/help"
},
status: :not_implemented
@@ -62,7 +62,7 @@ class Projects::LfsApiController < Projects::GitHttpClientController
else
object[:error] = {
code: 404,
- message: "Object does not exist on the server or you don't have permissions to access it"
+ message: _("Object does not exist on the server or you don't have permissions to access it")
}
end
end
diff --git a/app/controllers/projects/merge_requests/conflicts_controller.rb b/app/controllers/projects/merge_requests/conflicts_controller.rb
index 045a4e974fe..011ac9a42f8 100644
--- a/app/controllers/projects/merge_requests/conflicts_controller.rb
+++ b/app/controllers/projects/merge_requests/conflicts_controller.rb
@@ -16,12 +16,12 @@ class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::Ap
render json: @conflicts_list
elsif @merge_request.can_be_merged?
render json: {
- message: 'The merge conflicts for this merge request have already been resolved. Please return to the merge request.',
+ message: _('The merge conflicts for this merge request have already been resolved. Please return to the merge request.'),
type: 'error'
}
else
render json: {
- message: 'The merge conflicts for this merge request cannot be resolved through GitLab. Please try to resolve them locally.',
+ message: _('The merge conflicts for this merge request cannot be resolved through GitLab. Please try to resolve them locally.'),
type: 'error'
}
end
@@ -43,7 +43,7 @@ class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::Ap
return render_404 unless @conflicts_list.can_be_resolved_in_ui?
if @merge_request.can_be_merged?
- render status: :bad_request, json: { message: 'The merge conflicts for this merge request have already been resolved.' }
+ render status: :bad_request, json: { message: _('The merge conflicts for this merge request have already been resolved.') }
return
end
@@ -52,7 +52,7 @@ class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::Ap
.new(merge_request)
.execute(current_user, params)
- flash[:notice] = 'All merge conflicts were resolved. The merge request can now be merged.'
+ flash[:notice] = _('All merge conflicts were resolved. The merge request can now be merged.')
render json: { redirect_to: project_merge_request_url(@project, @merge_request, resolved_conflicts: true) }
rescue Gitlab::Git::Conflict::Resolver::ResolutionError => e
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 2b78abc66df..5cf7fa3422d 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -16,10 +16,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
before_action :authenticate_user!, only: [:assign_related_issues]
before_action :check_user_can_push_to_source_branch!, only: [:rebase]
- before_action only: [:show] do
- push_frontend_feature_flag(:expand_diff_full_file)
- end
-
def index
@merge_requests = @issuables
diff --git a/app/controllers/projects/mirrors_controller.rb b/app/controllers/projects/mirrors_controller.rb
index ab7ab13657a..ef330ae00f4 100644
--- a/app/controllers/projects/mirrors_controller.rb
+++ b/app/controllers/projects/mirrors_controller.rb
@@ -18,7 +18,7 @@ class Projects::MirrorsController < Projects::ApplicationController
result = ::Projects::UpdateService.new(project, current_user, mirror_params).execute
if result[:status] == :success
- flash[:notice] = 'Mirroring settings were successfully updated.'
+ flash[:notice] = _('Mirroring settings were successfully updated.')
else
flash[:alert] = project.errors.full_messages.join(', ').html_safe
end
@@ -38,7 +38,7 @@ class Projects::MirrorsController < Projects::ApplicationController
def update_now
if params[:sync_remote]
project.update_remote_mirrors
- flash[:notice] = "The remote repository is being updated..."
+ flash[:notice] = _("The remote repository is being updated...")
end
redirect_to_repository_settings(project, anchor: 'js-push-remote-settings')
diff --git a/app/controllers/projects/pipeline_schedules_controller.rb b/app/controllers/projects/pipeline_schedules_controller.rb
index acf56f0eb6a..fd5b89298a7 100644
--- a/app/controllers/projects/pipeline_schedules_controller.rb
+++ b/app/controllers/projects/pipeline_schedules_controller.rb
@@ -50,9 +50,11 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
job_id = RunPipelineScheduleWorker.perform_async(schedule.id, current_user.id)
if job_id
- flash[:notice] = "Successfully scheduled a pipeline to run. Go to the <a href=\"#{project_pipelines_path(@project)}\">Pipelines page</a> for details.".html_safe
+ link_to_pipelines = view_context.link_to(_('Pipelines page'), project_pipelines_path(@project))
+ message = _("Successfully scheduled a pipeline to run. Go to the %{link_to_pipelines} for details.").html_safe % { link_to_pipelines: link_to_pipelines }
+ flash[:notice] = message.html_safe
else
- flash[:alert] = 'Unable to schedule a pipeline to run immediately'
+ flash[:alert] = _('Unable to schedule a pipeline to run immediately')
end
redirect_to pipeline_schedules_path(@project)
@@ -85,7 +87,7 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
return unless limiter.throttled?([current_user, schedule], 1)
- flash[:alert] = 'You cannot play this scheduled pipeline at the moment. Please wait a minute.'
+ flash[:alert] = _('You cannot play this scheduled pipeline at the moment. Please wait a minute.')
redirect_to pipeline_schedules_path(@project)
end
diff --git a/app/controllers/projects/runners_controller.rb b/app/controllers/projects/runners_controller.rb
index 91f40b90aa8..ca62f54813b 100644
--- a/app/controllers/projects/runners_controller.rb
+++ b/app/controllers/projects/runners_controller.rb
@@ -15,7 +15,7 @@ class Projects::RunnersController < Projects::ApplicationController
def update
if Ci::UpdateRunnerService.new(@runner).update(runner_params)
- redirect_to project_runner_path(@project, @runner), notice: 'Runner was successfully updated.'
+ redirect_to project_runner_path(@project, @runner), notice: _('Runner was successfully updated.')
else
render 'edit'
end
@@ -31,17 +31,17 @@ class Projects::RunnersController < Projects::ApplicationController
def resume
if Ci::UpdateRunnerService.new(@runner).update(active: true)
- redirect_to project_runners_path(@project), notice: 'Runner was successfully updated.'
+ redirect_to project_runners_path(@project), notice: _('Runner was successfully updated.')
else
- redirect_to project_runners_path(@project), alert: 'Runner was not updated.'
+ redirect_to project_runners_path(@project), alert: _('Runner was not updated.')
end
end
def pause
if Ci::UpdateRunnerService.new(@runner).update(active: false)
- redirect_to project_runners_path(@project), notice: 'Runner was successfully updated.'
+ redirect_to project_runners_path(@project), notice: _('Runner was successfully updated.')
else
- redirect_to project_runners_path(@project), alert: 'Runner was not updated.'
+ redirect_to project_runners_path(@project), alert: _('Runner was not updated.')
end
end
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index f1c9d0d0f77..e0df51590ae 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -43,20 +43,20 @@ class Projects::ServicesController < Projects::ApplicationController
if outcome[:success]
{}
else
- { error: true, message: 'Test failed.', service_response: outcome[:result].to_s, test_failed: true }
+ { error: true, message: _('Test failed.'), service_response: outcome[:result].to_s, test_failed: true }
end
else
- { error: true, message: 'Validations failed.', service_response: @service.errors.full_messages.join(','), test_failed: false }
+ { error: true, message: _('Validations failed.'), service_response: @service.errors.full_messages.join(','), test_failed: false }
end
rescue Gitlab::HTTP::BlockedUrlError => e
- { error: true, message: 'Test failed.', service_response: e.message, test_failed: true }
+ { error: true, message: _('Test failed.'), service_response: e.message, test_failed: true }
end
def success_message
if @service.active?
- "#{@service.title} activated."
+ _("%{service_title} activated.") % { service_title: @service.title }
else
- "#{@service.title} settings saved, but not activated."
+ _("%{service_title} settings saved, but not activated.") % { service_title: @service.title }
end
end
diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb
index f2f63e986bb..d1c5cef76fa 100644
--- a/app/controllers/projects/settings/ci_cd_controller.rb
+++ b/app/controllers/projects/settings/ci_cd_controller.rb
@@ -13,7 +13,7 @@ module Projects
Projects::UpdateService.new(project, current_user, update_params).tap do |service|
result = service.execute
if result[:status] == :success
- flash[:notice] = "Pipelines settings for '#{@project.name}' were successfully updated."
+ flash[:notice] = _("Pipelines settings for '%{project_name}' were successfully updated.") % { project_name: @project.name }
run_autodevops_pipeline(service)
@@ -39,7 +39,7 @@ module Projects
def reset_registration_token
@project.reset_runners_token!
- flash[:notice] = 'New runners registration token has been generated!'
+ flash[:notice] = _('New runners registration token has been generated!')
redirect_to namespace_project_settings_ci_cd_path
end
@@ -58,7 +58,7 @@ module Projects
return unless service.run_auto_devops_pipeline?
if @project.empty_repo?
- flash[:warning] = "This repository is currently empty. A new Auto DevOps pipeline will be created after a new file has been pushed to a branch."
+ flash[:warning] = _("This repository is currently empty. A new Auto DevOps pipeline will be created after a new file has been pushed to a branch.")
return
end
diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb
index edebfc55c17..90d53aa08ea 100644
--- a/app/controllers/projects/tree_controller.rb
+++ b/app/controllers/projects/tree_controller.rb
@@ -37,7 +37,7 @@ class Projects::TreeController < Projects::ApplicationController
def create_dir
return render_404 unless @commit_params.values.all?
- create_commit(Files::CreateDirService, success_notice: "The directory has been successfully created.",
+ create_commit(Files::CreateDirService, success_notice: _("The directory has been successfully created."),
success_path: project_tree_path(@project, File.join(@branch_name, @dir_name)),
failure_path: project_tree_path(@project, @ref))
end
diff --git a/app/controllers/projects/triggers_controller.rb b/app/controllers/projects/triggers_controller.rb
index c7b4ebb2b24..284e119ca06 100644
--- a/app/controllers/projects/triggers_controller.rb
+++ b/app/controllers/projects/triggers_controller.rb
@@ -16,9 +16,9 @@ class Projects::TriggersController < Projects::ApplicationController
@trigger = project.triggers.create(trigger_params.merge(owner: current_user))
if @trigger.valid?
- flash[:notice] = 'Trigger was created successfully.'
+ flash[:notice] = _('Trigger was created successfully.')
else
- flash[:alert] = 'You could not create a new trigger.'
+ flash[:alert] = _('You could not create a new trigger.')
end
redirect_to project_settings_ci_cd_path(@project, anchor: 'js-pipeline-triggers')
@@ -26,9 +26,9 @@ class Projects::TriggersController < Projects::ApplicationController
def take_ownership
if trigger.update(owner: current_user)
- flash[:notice] = 'Trigger was re-assigned.'
+ flash[:notice] = _('Trigger was re-assigned.')
else
- flash[:alert] = 'You could not take ownership of trigger.'
+ flash[:alert] = _('You could not take ownership of trigger.')
end
redirect_to project_settings_ci_cd_path(@project, anchor: 'js-pipeline-triggers')
@@ -39,7 +39,7 @@ class Projects::TriggersController < Projects::ApplicationController
def update
if trigger.update(trigger_params)
- redirect_to project_settings_ci_cd_path(@project, anchor: 'js-pipeline-triggers'), notice: 'Trigger was successfully updated.'
+ redirect_to project_settings_ci_cd_path(@project, anchor: 'js-pipeline-triggers'), notice: _('Trigger was successfully updated.')
else
render action: "edit"
end
@@ -47,9 +47,9 @@ class Projects::TriggersController < Projects::ApplicationController
def destroy
if trigger.destroy
- flash[:notice] = "Trigger removed."
+ flash[:notice] = _("Trigger removed.")
else
- flash[:alert] = "Could not remove the trigger."
+ flash[:alert] = _("Could not remove the trigger.")
end
redirect_to project_settings_ci_cd_path(@project, anchor: 'js-pipeline-triggers'), status: :found
diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb
index 88dd111132b..da2420633ef 100644
--- a/app/controllers/projects/wikis_controller.rb
+++ b/app/controllers/projects/wikis_controller.rb
@@ -49,7 +49,7 @@ class Projects::WikisController < Projects::ApplicationController
if @page.valid?
redirect_to(
project_wiki_path(@project, @page),
- notice: 'Wiki was successfully updated.'
+ notice: _('Wiki was successfully updated.')
)
else
render 'edit'
@@ -65,7 +65,7 @@ class Projects::WikisController < Projects::ApplicationController
if @page.persisted?
redirect_to(
project_wiki_path(@project, @page),
- notice: 'Wiki was successfully updated.'
+ notice: _('Wiki was successfully updated.')
)
else
render action: "edit"
@@ -85,7 +85,7 @@ class Projects::WikisController < Projects::ApplicationController
else
redirect_to(
project_wiki_path(@project, :home),
- notice: "Page not found"
+ notice: _("Page not found")
)
end
end
@@ -95,7 +95,7 @@ class Projects::WikisController < Projects::ApplicationController
redirect_to project_wiki_path(@project, :home),
status: 302,
- notice: "Page was successfully deleted"
+ notice: _("Page was successfully deleted")
rescue Gitlab::Git::Wiki::OperationError => e
@error = e
render 'edit'
@@ -118,7 +118,7 @@ class Projects::WikisController < Projects::ApplicationController
@sidebar_wiki_entries = WikiPage.group_by_directory(@project_wiki.pages(limit: 15))
end
rescue ProjectWiki::CouldNotCreateWikiError
- flash[:notice] = "Could not create Wiki Repository at this time. Please try again later."
+ flash[:notice] = _("Could not create Wiki Repository at this time. Please try again later.")
redirect_to project_path(@project)
false
end
@@ -155,7 +155,7 @@ class Projects::WikisController < Projects::ApplicationController
end
def set_encoding_error
- flash.now[:notice] = "The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository."
+ flash.now[:notice] = _("The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository.")
end
def file_blob
diff --git a/app/finders/projects_finder.rb b/app/finders/projects_finder.rb
index 93d3c991846..0319e95d439 100644
--- a/app/finders/projects_finder.rb
+++ b/app/finders/projects_finder.rb
@@ -81,7 +81,7 @@ class ProjectsFinder < UnionFinder
if private_only?
current_user.authorized_projects
else
- Project.public_or_visible_to_user(current_user)
+ Project.public_or_visible_to_user(current_user, params[:visibility_level])
end
end
end
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index 8110377850b..09165979b26 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -33,10 +33,15 @@ module SearchHelper
"Showing #{from} - #{to} of #{count} #{scope.humanize(capitalize: false)} for \"#{term}\""
end
- def find_project_for_result_blob(result)
+ def find_project_for_result_blob(projects, result)
@project
end
+ # Used in EE
+ def blob_projects(results)
+ nil
+ end
+
def parse_search_result(result)
result
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 611c64c8f49..06010409574 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -459,14 +459,41 @@ class Project < ActiveRecord::Base
# Returns a collection of projects that is either public or visible to the
# logged in user.
- def self.public_or_visible_to_user(user = nil)
- if user
- where('EXISTS (?) OR projects.visibility_level IN (?)',
- user.authorizations_for_projects,
- Gitlab::VisibilityLevel.levels_for_user(user))
- else
- public_to_user
- end
+ #
+ # requested_visiblity_levels: Normally all projects that are visible
+ # to the user (e.g. internal and public) are queried, but this
+ # parameter allows the caller to narrow the search space to optimize
+ # database queries. For instance, a caller may only want to see
+ # internal projects. Instead of querying for internal and public
+ # projects and throwing away public projects, this parameter allows
+ # the query to be targeted for only internal projects.
+ def self.public_or_visible_to_user(user = nil, requested_visibility_levels = [])
+ return public_to_user unless user
+
+ visible_levels = Gitlab::VisibilityLevel.levels_for_user(user)
+ include_private = true
+ requested_visibility_levels = Array(requested_visibility_levels)
+
+ if requested_visibility_levels.present?
+ visible_levels &= requested_visibility_levels
+ include_private = requested_visibility_levels.include?(Gitlab::VisibilityLevel::PRIVATE)
+ end
+
+ public_or_internal_rel =
+ if visible_levels.present?
+ where('projects.visibility_level IN (?)', visible_levels)
+ else
+ Project.none
+ end
+
+ private_rel =
+ if include_private
+ where('EXISTS (?)', user.authorizations_for_projects)
+ else
+ Project.none
+ end
+
+ public_or_internal_rel.or(private_rel)
end
# project features may be "disabled", "internal", "enabled" or "public". If "internal",
@@ -2003,12 +2030,8 @@ class Project < ActiveRecord::Base
@storage = nil if storage_version_changed?
end
- def gl_repository(is_wiki:)
- Gitlab::GlRepository.gl_repository(self, is_wiki)
- end
-
- def reference_counter(wiki: false)
- Gitlab::ReferenceCounter.new(gl_repository(is_wiki: wiki))
+ def reference_counter(type: Gitlab::GlRepository::PROJECT)
+ Gitlab::ReferenceCounter.new(type.identifier_for_subject(self))
end
def badges
@@ -2152,7 +2175,7 @@ class Project < ActiveRecord::Base
end
def wiki_reference_count
- reference_counter(wiki: true).value
+ reference_counter(type: Gitlab::GlRepository::WIKI).value
end
def check_repository_absence!
diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb
index 6ea0716c192..268706a6aea 100644
--- a/app/models/project_wiki.rb
+++ b/app/models/project_wiki.rb
@@ -59,7 +59,7 @@ class ProjectWiki
# Returns the Gitlab::Git::Wiki object.
def wiki
@wiki ||= begin
- gl_repository = Gitlab::GlRepository.gl_repository(project, true)
+ gl_repository = Gitlab::GlRepository::WIKI.identifier_for_subject(project)
raw_repository = Gitlab::Git::Repository.new(project.repository_storage, disk_path + '.git', gl_repository, full_path)
create_repo!(raw_repository) unless raw_repository.exists?
@@ -151,7 +151,7 @@ class ProjectWiki
end
def repository
- @repository ||= Repository.new(full_path, @project, disk_path: disk_path, is_wiki: true)
+ @repository ||= Repository.new(full_path, @project, disk_path: disk_path, repo_type: Gitlab::GlRepository::WIKI)
end
def default_branch
diff --git a/app/models/repository.rb b/app/models/repository.rb
index ff355295862..574ce12b309 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -19,7 +19,7 @@ class Repository
include Gitlab::RepositoryCacheAdapter
- attr_accessor :full_path, :disk_path, :project, :is_wiki
+ attr_accessor :full_path, :disk_path, :project, :repo_type
delegate :ref_name_for_sha, to: :raw_repository
delegate :bundle_to_disk, to: :raw_repository
@@ -60,12 +60,12 @@ class Repository
xcode_config: :xcode_project?
}.freeze
- def initialize(full_path, project, disk_path: nil, is_wiki: false)
+ def initialize(full_path, project, disk_path: nil, repo_type: Gitlab::GlRepository::PROJECT)
@full_path = full_path
@disk_path = disk_path || full_path
@project = project
@commit_cache = {}
- @is_wiki = is_wiki
+ @repo_type = repo_type
end
def ==(other)
@@ -1112,7 +1112,7 @@ class Repository
def initialize_raw_repository
Gitlab::Git::Repository.new(project.repository_storage,
disk_path + '.git',
- Gitlab::GlRepository.gl_repository(project, is_wiki),
+ repo_type.identifier_for_subject(project),
project.full_path)
end
end
diff --git a/app/serializers/diff_file_entity.rb b/app/serializers/diff_file_entity.rb
index 066e30cd3bb..d3d5883e46b 100644
--- a/app/serializers/diff_file_entity.rb
+++ b/app/serializers/diff_file_entity.rb
@@ -57,7 +57,7 @@ class DiffFileEntity < DiffFileBaseEntity
diff_file.diff_lines_for_serializer
end
- expose :is_fully_expanded, if: -> (diff_file, _) { Feature.enabled?(:expand_diff_full_file, default_enabled: true) && diff_file.text? } do |diff_file|
+ expose :is_fully_expanded, if: -> (diff_file, _) { diff_file.text? } do |diff_file|
diff_file.fully_expanded?
end
diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb
index 8241e408ce5..d8a78001b79 100644
--- a/app/services/merge_requests/merge_service.rb
+++ b/app/services/merge_requests/merge_service.rb
@@ -76,8 +76,8 @@ module MergeRequests
def try_merge
repository.merge(current_user, source, merge_request, commit_message)
rescue Gitlab::Git::PreReceiveError => e
- handle_merge_error(log_message: e.message)
- raise_error('Something went wrong during merge pre-receive hook')
+ raise MergeError,
+ "Something went wrong during merge pre-receive hook. #{e.message}".strip
rescue => e
handle_merge_error(log_message: e.message)
raise_error('Something went wrong during merge')
diff --git a/app/views/layouts/nav/sidebar/_group.html.haml b/app/views/layouts/nav/sidebar/_group.html.haml
index eefe86eb6b4..b950e53639a 100644
--- a/app/views/layouts/nav/sidebar/_group.html.haml
+++ b/app/views/layouts/nav/sidebar/_group.html.haml
@@ -45,6 +45,8 @@
%span
= _('Contribution Analytics')
+ = render_if_exists 'layouts/nav/group_insights_link'
+
= render_if_exists "layouts/nav/ee/epic_link", group: @group
- if group_sidebar_link?(:issues)
diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml
index 7b492efeb09..6b33189d1cf 100644
--- a/app/views/layouts/nav/sidebar/_project.html.haml
+++ b/app/views/layouts/nav/sidebar/_project.html.haml
@@ -41,6 +41,8 @@
= link_to project_cycle_analytics_path(@project), title: _('Cycle Analytics'), class: 'shortcuts-project-cycle-analytics' do
%span= _('Cycle Analytics')
+ = render_if_exists 'layouts/nav/project_insights_link'
+
- if project_nav_tab? :files
= nav_link(controller: sidebar_repository_paths) do
= link_to project_tree_path(@project), class: 'shortcuts-tree qa-project-menu-repo' do
diff --git a/app/views/projects/artifacts/browse.html.haml b/app/views/projects/artifacts/browse.html.haml
index 09295940529..6a7cb1499c5 100644
--- a/app/views/projects/artifacts/browse.html.haml
+++ b/app/views/projects/artifacts/browse.html.haml
@@ -4,7 +4,7 @@
= render "projects/jobs/header"
- add_to_breadcrumbs(s_('CICD|Jobs'), project_jobs_path(@project))
-- add_to_breadcrumbs("##{@build.id}", project_jobs_path(@project))
+- add_to_breadcrumbs("##{@build.id}", project_job_path(@project, @build))
.tree-holder
.nav-block
diff --git a/app/views/search/_results.html.haml b/app/views/search/_results.html.haml
index 2e62039b90a..5b25a67bc87 100644
--- a/app/views/search/_results.html.haml
+++ b/app/views/search/_results.html.haml
@@ -21,6 +21,8 @@
- if @scope == 'projects'
.term
= render 'shared/projects/list', projects: @search_objects, pipeline_status: false
+ - elsif %w[blobs wiki_blobs].include?(@scope)
+ = render partial: 'search/results/blob', collection: @search_objects, locals: { projects: blob_projects(@search_objects) }
- else
= render partial: "search/results/#{@scope.singularize}", collection: @search_objects
diff --git a/app/views/search/results/_blob.html.haml b/app/views/search/results/_blob.html.haml
index 2a602095845..bdad07f36d1 100644
--- a/app/views/search/results/_blob.html.haml
+++ b/app/views/search/results/_blob.html.haml
@@ -1,4 +1,4 @@
-- project = find_project_for_result_blob(blob)
+- project = find_project_for_result_blob(projects, blob)
- return unless project
- blob = parse_search_result(blob)
diff --git a/app/views/search/results/_wiki_blob.html.haml b/app/views/search/results/_wiki_blob.html.haml
index 389e4cc75b9..b351ecd4edf 100644
--- a/app/views/search/results/_wiki_blob.html.haml
+++ b/app/views/search/results/_wiki_blob.html.haml
@@ -1,4 +1,4 @@
-- project = find_project_for_result_blob(wiki_blob)
+- project = find_project_for_result_blob(projects, wiki_blob)
- wiki_blob = parse_search_result(wiki_blob)
- wiki_blob_link = project_wiki_path(project, wiki_blob.basename)
diff --git a/app/views/shared/milestones/_milestone.html.haml b/app/views/shared/milestones/_milestone.html.haml
index e75f0a184ea..e99aa3f1ee4 100644
--- a/app/views/shared/milestones/_milestone.html.haml
+++ b/app/views/shared/milestones/_milestone.html.haml
@@ -52,7 +52,7 @@
= link_to 'Close Milestone', project_milestone_path(@project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-sm btn-close btn-grouped"
- unless milestone.active?
- = link_to 'Reopen Milestone', project_milestone_path(@project, milestone, {state_event: :activate }), method: :put, class: "btn btn-grouped btn-reopen"
+ = link_to 'Reopen Milestone', project_milestone_path(@project, milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-grouped btn-reopen"
- if @group
- if can?(current_user, :admin_milestone, @group)
- if milestone.closed?
diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb
index a40c865a5e5..396f44396a3 100644
--- a/app/workers/post_receive.rb
+++ b/app/workers/post_receive.rb
@@ -4,7 +4,7 @@ class PostReceive
include ApplicationWorker
def perform(gl_repository, identifier, changes, push_options = [])
- project, is_wiki = Gitlab::GlRepository.parse(gl_repository)
+ project, repo_type = Gitlab::GlRepository.parse(gl_repository)
if project.nil?
log("Triggered hook for non-existing project with gl_repository \"#{gl_repository}\"")
@@ -17,7 +17,7 @@ class PostReceive
Sidekiq.logger.info "changes: #{changes.inspect}" if ENV['SIDEKIQ_LOG_ARGUMENTS']
post_received = Gitlab::GitPostReceive.new(project, identifier, changes, push_options)
- if is_wiki
+ if repo_type.wiki?
process_wiki_changes(post_received)
else
process_project_changes(post_received)
diff --git a/changelogs/unreleased/48132-display-output-from-pre-receive-scripts.yml b/changelogs/unreleased/48132-display-output-from-pre-receive-scripts.yml
new file mode 100644
index 00000000000..e06a4d5ee75
--- /dev/null
+++ b/changelogs/unreleased/48132-display-output-from-pre-receive-scripts.yml
@@ -0,0 +1,5 @@
+---
+title: "Allow failed custom hook script errors to safely appear in GitLab UI by filtering error messages by the prefix GL-HOOK-ERR:"
+merge_request: 25625
+author:
+type: changed
diff --git a/changelogs/unreleased/49910-reopening-a-closed-milestone-from-the-closed-milestones-page-fails2.yml b/changelogs/unreleased/49910-reopening-a-closed-milestone-from-the-closed-milestones-page-fails2.yml
new file mode 100644
index 00000000000..68d38cd56c5
--- /dev/null
+++ b/changelogs/unreleased/49910-reopening-a-closed-milestone-from-the-closed-milestones-page-fails2.yml
@@ -0,0 +1,5 @@
+---
+title: Fix bug when reopening milestone from index page
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/59296-add-filter-by-title-milestones-api.yml b/changelogs/unreleased/59296-add-filter-by-title-milestones-api.yml
new file mode 100644
index 00000000000..440b24a548c
--- /dev/null
+++ b/changelogs/unreleased/59296-add-filter-by-title-milestones-api.yml
@@ -0,0 +1,5 @@
+---
+title: Add select by title to milestones API
+merge_request: 26573
+author:
+type: added
diff --git a/changelogs/unreleased/59502-fix-breadcrumb-artifacts.yml b/changelogs/unreleased/59502-fix-breadcrumb-artifacts.yml
new file mode 100644
index 00000000000..da65c3bc870
--- /dev/null
+++ b/changelogs/unreleased/59502-fix-breadcrumb-artifacts.yml
@@ -0,0 +1,5 @@
+---
+title: Fixes job link in artifacts page breadcrumb
+merge_request: 26592
+author:
+type: fixed
diff --git a/changelogs/unreleased/issue_58547.yml b/changelogs/unreleased/issue_58547.yml
new file mode 100644
index 00000000000..553c752e72d
--- /dev/null
+++ b/changelogs/unreleased/issue_58547.yml
@@ -0,0 +1,5 @@
+---
+title: Add API access check to Graphql
+merge_request: 26570
+author:
+type: other
diff --git a/changelogs/unreleased/sh-optimize-projects-api.yml b/changelogs/unreleased/sh-optimize-projects-api.yml
new file mode 100644
index 00000000000..2f2459be77f
--- /dev/null
+++ b/changelogs/unreleased/sh-optimize-projects-api.yml
@@ -0,0 +1,5 @@
+---
+title: Optimize /api/v4/projects endpoint for visibility level
+merge_request: 26481
+author:
+type: performance
diff --git a/db/fixtures/development/25_api_personal_access_token.rb b/db/fixtures/development/25_api_personal_access_token.rb
new file mode 100644
index 00000000000..a2e6c674c1f
--- /dev/null
+++ b/db/fixtures/development/25_api_personal_access_token.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require './spec/support/sidekiq'
+
+# Create an api access token for root user with the value: ypCa3Dzb23o5nvsixwPA
+Gitlab::Seeder.quiet do
+ PersonalAccessToken.create!(
+ user_id: User.find_by(username: 'root').id,
+ name: "seeded-api-token",
+ scopes: ["api"],
+ token_digest: "/O0jfLERYT/L5gG8nfByQxqTj43TeLlRzOtJGTzRsbQ="
+ )
+
+ print '.'
+end
diff --git a/doc/README.md b/doc/README.md
index ecc214d97c8..aead50ea97e 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -222,7 +222,7 @@ The following documentation relates to the DevOps **Verify** stage:
|:---------------------------------------------------|:-----------------------------------------------------------------------------|
| [GitLab CI/CD](ci/README.md) | Explore the features and capabilities of Continuous Integration with GitLab. |
| [JUnit test reports](ci/junit_test_reports.md) | Display JUnit test reports on merge requests. |
-| [Pipeline Graphs](ci/pipelines.md#pipeline-graphs) | Visualize builds. |
+| [Pipeline Graphs](ci/pipelines.md#visualizing-pipelines) | Visualize builds. |
| [Review Apps](ci/review_apps/index.md) | Preview changes to your application right from a merge request. |
<div align="right">
diff --git a/doc/administration/custom_hooks.md b/doc/administration/custom_hooks.md
index 60ad4bf4e8f..28afaf84f5a 100644
--- a/doc/administration/custom_hooks.md
+++ b/doc/administration/custom_hooks.md
@@ -51,7 +51,7 @@ Hooks can be also placed in `hooks/<hook_name>.d` (global) or
execution of the hooks.
NOTE: **Note:** `<hook_name>.d` would need to be either `pre-receive.d`,
-`post-receive.d`, or `update.d` to work properly. Any other names will be ignored.
+`post-receive.d`, or `update.d` to work properly. Any other names will be ignored.
To look in a different directory for the global custom hooks (those in
`hooks/<hook_name.d>`), set `custom_hooks_dir` in gitlab-shell config. For
@@ -76,9 +76,21 @@ first script exiting with a non-zero value.
> [Introduced][5073] in GitLab 8.10.
-If the commit is declined or an error occurs during the Git hook check,
-the STDERR or STDOUT message of the hook will be present in GitLab's UI.
-STDERR takes precedence over STDOUT.
+To have custom error messages appear in GitLab's UI when the commit is
+declined or an error occurs during the Git hook, your script should:
+
+- Send the custom error messages to either the script's `stdout` or `stderr`.
+- Prefix each message with `GL-HOOK-ERR:` with no characters appearing before the prefix.
+
+### Example custom error message
+
+This hook script written in bash will generate the following message in GitLab's UI:
+
+```bash
+#!/bin/sh
+echo "GL-HOOK-ERR: My custom error message.";
+exit 1
+```
![Custom message from custom Git hook](img/custom_hooks_error_msg.png)
diff --git a/doc/administration/img/custom_hooks_error_msg.png b/doc/administration/img/custom_hooks_error_msg.png
index 845f0de19ce..4f25c471908 100644
--- a/doc/administration/img/custom_hooks_error_msg.png
+++ b/doc/administration/img/custom_hooks_error_msg.png
Binary files differ
diff --git a/doc/administration/repository_storage_types.md b/doc/administration/repository_storage_types.md
index 25c3d564560..4e1e363888d 100644
--- a/doc/administration/repository_storage_types.md
+++ b/doc/administration/repository_storage_types.md
@@ -142,7 +142,7 @@ projects:
2. Uncheck the **Use hashed storage paths for newly created and renamed projects** checkbox.
To schedule a complete rollback, see the
-[rake task documentation for storage rollback][rake/rollback-to-legacy] for instructions.
+[rake task documentation for storage rollback](raketasks/storage.md#rollback-from-hashed-storage-to-legacy-storage) for instructions.
The rollback task also supports specifying a range of Project IDs. Here is an example
of limiting the rollout to Project IDs 50 to 100, in an Omnibus Gitlab installation:
@@ -205,6 +205,5 @@ They are also S3 compatible since **10.0** (GitLab Premium), and available in Gi
[ce-2821]: https://gitlab.com/gitlab-com/infrastructure/issues/2821
[ce-28283]: https://gitlab.com/gitlab-org/gitlab-ce/issues/28283
[rake/migrate-to-hashed]: raketasks/storage.md#migrate-existing-projects-to-hashed-storage
-[rake/rollback-to-legacy]: raketasks/storage.md#rollback
[storage-paths]: repository_storage_types.md
[gitaly]: gitaly/index.md
diff --git a/doc/api/group_milestones.md b/doc/api/group_milestones.md
index 1c2f56581eb..260eb09cc38 100644
--- a/doc/api/group_milestones.md
+++ b/doc/api/group_milestones.md
@@ -12,6 +12,7 @@ GET /groups/:id/milestones?iids[]=42
GET /groups/:id/milestones?iids[]=42&iids[]=43
GET /groups/:id/milestones?state=active
GET /groups/:id/milestones?state=closed
+GET /groups/:id/milestones?title=1.0
GET /groups/:id/milestones?search=version
```
@@ -22,6 +23,7 @@ Parameters:
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
| `iids[]` | Array[integer] | optional | Return only the milestones having the given `iid` |
| `state` | string | optional | Return only `active` or `closed` milestones |
+| `title` | string | optional | Return only the milestones having the given `title` |
| `search` | string | optional | Return only milestones with a title or description matching the provided string |
```bash
diff --git a/doc/api/milestones.md b/doc/api/milestones.md
index 897184d51af..3b76c19dc07 100644
--- a/doc/api/milestones.md
+++ b/doc/api/milestones.md
@@ -10,6 +10,7 @@ GET /projects/:id/milestones?iids[]=42
GET /projects/:id/milestones?iids[]=42&iids[]=43
GET /projects/:id/milestones?state=active
GET /projects/:id/milestones?state=closed
+GET /projects/:id/milestones?title=1.0
GET /projects/:id/milestones?search=version
```
@@ -20,6 +21,7 @@ Parameters:
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `iids[]` | Array[integer] | optional | Return only the milestones having the given `iid` |
| `state` | string | optional | Return only `active` or `closed` milestones |
+| `title` | string | optional | Return only the milestones having the given `title` |
| `search` | string | optional | Return only milestones with a title or description matching the provided string |
```bash
diff --git a/doc/ci/pipelines.md b/doc/ci/pipelines.md
index c509c341d1e..38cd58f11ac 100644
--- a/doc/ci/pipelines.md
+++ b/doc/ci/pipelines.md
@@ -45,12 +45,12 @@ Pipeline graphs can be displayed in two different ways, depending on the page yo
access the graph from.
NOTE: **Note:**
-GitLab capitalizes the stages' names when shown in the [pipeline graphs](#pipeline-graphs).
+GitLab capitalizes the stages' names when shown in the pipeline graphs (below).
### Regular pipeline graphs
Regular pipeline graphs show the names of the jobs of each stage. Regular pipeline graphs can
-be found when you are on a [single pipeline page](#seeing-pipeline-status). For example:
+be found when you are on a [single pipeline page](#accessing-pipelines). For example:
![Pipelines example](img/pipelines.png)
diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md
index 4d15d58cb40..814185f7732 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -311,7 +311,7 @@ variables that were set, etc.
Before enabling this, you should ensure jobs are visible to
[team members only](../../user/permissions.md#project-features). You should
-also [erase](../pipelines.md#seeing-job-status) all generated job traces
+also [erase](../pipelines.md#accessing-individual-jobs) all generated job traces
before making them visible again.
To enable debug traces, set the `CI_DEBUG_TRACE` variable to `true`:
diff --git a/doc/development/go_guide/index.md b/doc/development/go_guide/index.md
index 7fd41c5e01f..6dcade3bb51 100644
--- a/doc/development/go_guide/index.md
+++ b/doc/development/go_guide/index.md
@@ -26,7 +26,7 @@ Reviewers and maintainers should pay attention to:
- `defer` functions: ensure the presence when needed, and after `err` check.
- Inject dependencies as parameters.
-- Void structs when marshalling to JSON (generates `null` instead of `[]`).
+- Void structs when marshaling to JSON (generates `null` instead of `[]`).
### Security
@@ -185,7 +185,7 @@ There are a few guidelines one should follow when using the
- When printing an error use
[WithError](https://godoc.org/github.com/sirupsen/logrus#WithError). For
- exmaple, `logrus.WithError(err).Error("Failed to do something")`.
+ example, `logrus.WithError(err).Error("Failed to do something")`.
- Since we use [structured logging](#structured-json-logging) we can log
fields in the context of that code path, such as the URI of the request using
[`WithField`](https://godoc.org/github.com/sirupsen/logrus#WithField) or
diff --git a/doc/install/aws/index.md b/doc/install/aws/index.md
index d02aa24cd85..0000e03f1d7 100644
--- a/doc/install/aws/index.md
+++ b/doc/install/aws/index.md
@@ -1,11 +1,11 @@
-# Installing GitLab on Amazon Web Services (AWS)
-
-To install GitLab on AWS, you can use the Amazon Machine Images (AMIs) that GitLab
-provides with [each release](https://about.gitlab.com/releases/).
+# Installing GitLab HA on Amazon Web Services (AWS)
This page offers a walkthrough of a common HA (Highly Available) configuration
for GitLab on AWS. You should customize it to accommodate your needs.
+NOTE: **Note**
+For organizations with 300 users or less, the recommended AWS installation method is to launch an EC2 single box [Omnibus Installation](https://about.gitlab.com/install/) and implement a snapshot strategy for backing up the data.
+
## Introduction
GitLab on AWS can leverage many of the services that are already
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index fb3f9711711..11f24b4b701 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -901,7 +901,7 @@ increasing the rollout up to 100%.
If `INCREMENTAL_ROLLOUT_MODE` is set to `manual` in your project, then instead
of the standard `production` job, 4 different
-[manual jobs](../../ci/pipelines.md#manual-actions-from-the-pipeline-graph)
+[manual jobs](../../ci/pipelines.md#manual-actions-from-pipeline-graphs)
will be created:
1. `rollout 10%`
diff --git a/doc/user/group/clusters/index.md b/doc/user/group/clusters/index.md
index f6bb342de43..984881ef26c 100644
--- a/doc/user/group/clusters/index.md
+++ b/doc/user/group/clusters/index.md
@@ -28,7 +28,7 @@ deployments.
| [Helm Tiller](https://docs.helm.sh) | 11.6+ | Helm is a package manager for Kubernetes and is required to install all the other applications. It is installed in its own pod inside the cluster which can run the `helm` CLI in a safe environment. | n/a |
| [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress) | 11.6+ | Ingress can provide load balancing, SSL termination, and name-based virtual hosting. It acts as a web proxy for your applications and is useful if you want to use [Auto DevOps](../../../topics/autodevops/index.md) or deploy your own web apps. | [stable/nginx-ingress](https://github.com/helm/charts/tree/master/stable/nginx-ingress) |
| [Cert-Manager](https://docs.cert-manager.io/en/latest/) | 11.6+ | Cert-Manager is a native Kubernetes certificate management controller that helps with issuing certificates. Installing Cert-Manager on your cluster will issue a certificate by [Let's Encrypt](https://letsencrypt.org/) and ensure that certificates are valid and up-to-date. | [stable/cert-manager](https://github.com/helm/charts/tree/master/stable/cert-manager) |
-| [GitLab Runner](https://docs.gitlab.com/runner/) | 11.10+ | GitLab Runner is the open source project that is used to run your jobs and send the results back to GitLab. It is used in conjunction with [GitLab CI/CD](../../../ci/README.md), the open-source continuous integration service included with GitLab that coordinates the jobs. When installing the GitLab Runner via the applications, it will run in **privileged mode** by default. Make sure you read the [security implications](#security-implications) before doing so. | [runner/gitlab-runner](https://gitlab.com/charts/gitlab-runner) |
+| [GitLab Runner](https://docs.gitlab.com/runner/) | 11.10+ | GitLab Runner is the open source project that is used to run your jobs and send the results back to GitLab. It is used in conjunction with [GitLab CI/CD](../../../ci/README.md), the open-source continuous integration service included with GitLab that coordinates the jobs. When installing the GitLab Runner via the applications, it will run in **privileged mode** by default. Make sure you read the [security implications](../../project/clusters/index.md#security-implications) before doing so. | [runner/gitlab-runner](https://gitlab.com/charts/gitlab-runner) |
NOTE: **Note:**
Some [cluster
diff --git a/doc/user/project/index.md b/doc/user/project/index.md
index 4d19464cb7a..64139f9dbe9 100644
--- a/doc/user/project/index.md
+++ b/doc/user/project/index.md
@@ -55,11 +55,11 @@ When you create a project in GitLab, you'll have access to a large number of
- [Auto Deploy](../../ci/autodeploy/index.md): Configure GitLab CI/CD
to automatically set up your app's deployment
- [Enable and disable GitLab CI](../../ci/enable_or_disable_ci.md)
- - [Pipelines](../../ci/pipelines.md#pipelines): Configure and visualize
+ - [Pipelines](../../ci/pipelines.md): Configure and visualize
your GitLab CI/CD pipelines from the UI
- [Scheduled Pipelines](pipelines/schedules.md): Schedule a pipeline
to start at a chosen time
- - [Pipeline Graphs](../../ci/pipelines.md#pipeline-graphs): View your
+ - [Pipeline Graphs](../../ci/pipelines.md#visualizing-pipelines): View your
entire pipeline from the UI
- [Job artifacts](pipelines/job_artifacts.md): Define,
browse, and download job artifacts
diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md
index 593eb80e044..01a3a5bbbe1 100644
--- a/doc/user/project/merge_requests/index.md
+++ b/doc/user/project/merge_requests/index.md
@@ -18,7 +18,7 @@ With GitLab merge requests, you can:
- Live preview the changes when [Review Apps](../../../ci/review_apps/index.md) is configured for your project
- Build, test, and deploy your code in a per-branch basis with built-in [GitLab CI/CD](../../../ci/README.md)
- Prevent the merge request from being merged before it's ready with [WIP MRs](#work-in-progress-merge-requests)
-- View the deployment process through [Pipeline Graphs](../../../ci/pipelines.md#pipeline-graphs)
+- View the deployment process through [Pipeline Graphs](../../../ci/pipelines.md#visualizing-pipelines)
- [Automatically close the issue(s)](../../project/issues/closing_issues.md#via-merge-request) that originated the implementation proposed in the merge request
- Assign it to any registered user, and change the assignee how many times you need
- Assign a [milestone](../../project/milestones/index.md) and track the development of a broader implementation
diff --git a/jest.config.js b/jest.config.js
index 1f6e04390ae..cd0d311779d 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -37,4 +37,5 @@ module.exports = {
},
transformIgnorePatterns: ['node_modules/(?!(@gitlab/ui)/)'],
timers: 'fake',
+ testEnvironment: '<rootDir>/spec/frontend/environment.js',
};
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index b8bd180bdc1..8a21d44b4bf 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -302,6 +302,12 @@ module API
end
# rubocop: enable CodeReuse/ActiveRecord
+ # rubocop: disable CodeReuse/ActiveRecord
+ def filter_by_title(items, title)
+ items.where(title: title)
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
def filter_by_search(items, text)
items.search(text)
end
diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb
index fe78049af87..3fd824877ae 100644
--- a/lib/api/helpers/internal_helpers.rb
+++ b/lib/api/helpers/internal_helpers.rb
@@ -5,9 +5,11 @@ module API
module InternalHelpers
attr_reader :redirected_path
- def wiki?
- set_project unless defined?(@wiki) # rubocop:disable Gitlab/ModuleWithInstanceVariables
- @wiki # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ delegate :wiki?, to: :repo_type
+
+ def repo_type
+ set_project unless defined?(@repo_type) # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ @repo_type # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def project
@@ -67,10 +69,10 @@ module API
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def set_project
if params[:gl_repository]
- @project, @wiki = Gitlab::GlRepository.parse(params[:gl_repository])
+ @project, @repo_type = Gitlab::GlRepository.parse(params[:gl_repository])
@redirected_path = nil
else
- @project, @wiki, @redirected_path = Gitlab::RepoPath.parse(params[:project])
+ @project, @repo_type, @redirected_path = Gitlab::RepoPath.parse(params[:project])
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
@@ -78,7 +80,7 @@ module API
# Project id to pass between components that don't share/don't have
# access to the same filesystem mounts
def gl_repository
- Gitlab::GlRepository.gl_repository(project, wiki?)
+ repo_type.identifier_for_subject(project)
end
def gl_project_path
@@ -92,7 +94,7 @@ module API
# Return the repository depending on whether we want the wiki or the
# regular repository
def repository
- if wiki?
+ if repo_type.wiki?
project.wiki.repository
else
project.repository
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index 7f4a00f1389..cb9aa849eeb 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -59,7 +59,7 @@ module API
actor
end
- access_checker_klass = wiki? ? Gitlab::GitAccessWiki : Gitlab::GitAccess
+ access_checker_klass = repo_type.access_checker_class
access_checker = access_checker_klass.new(actor, project,
protocol, authentication_abilities: ssh_authentication_abilities,
namespace_path: namespace_path, project_path: project_path,
diff --git a/lib/api/milestone_responses.rb b/lib/api/milestone_responses.rb
index a0ca39b69d4..62e159ab003 100644
--- a/lib/api/milestone_responses.rb
+++ b/lib/api/milestone_responses.rb
@@ -16,6 +16,7 @@ module API
optional :state, type: String, values: %w[active closed all], default: 'all',
desc: 'Return "active", "closed", or "all" milestones'
optional :iids, type: Array[Integer], desc: 'The IIDs of the milestones'
+ optional :title, type: String, desc: 'The title of the milestones'
optional :search, type: String, desc: 'The search criteria for the title or description of the milestone'
use :pagination
end
@@ -33,6 +34,7 @@ module API
milestones = parent.milestones.order_id_desc
milestones = Milestone.filter_by_state(milestones, params[:state])
milestones = filter_by_iid(milestones, params[:iids]) if params[:iids].present?
+ milestones = filter_by_title(milestones, params[:title]) if params[:title]
milestones = filter_by_search(milestones, params[:search]) if params[:search]
present paginate(milestones), with: Entities::Milestone
diff --git a/lib/gitlab/git/pre_receive_error.rb b/lib/gitlab/git/pre_receive_error.rb
index 03caace6fce..b46d4ba0b02 100644
--- a/lib/gitlab/git/pre_receive_error.rb
+++ b/lib/gitlab/git/pre_receive_error.rb
@@ -4,19 +4,38 @@ module Gitlab
module Git
#
# PreReceiveError is special because its message gets displayed to users
- # in the web UI. To prevent XSS we sanitize the message on
- # initialization.
+ # in the web UI. Because of this, we:
+ # - Only display errors that have been marked as safe with a prefix.
+ # This is to prevent leaking of stacktraces, or other sensitive info.
+ # - Sanitize the string of any XSS
class PreReceiveError < StandardError
- def initialize(msg = '')
- super(nlbr(msg))
+ SAFE_MESSAGE_PREFIXES = [
+ 'GitLab:', # Messages from gitlab-shell
+ 'GL-HOOK-ERR:' # Messages marked as safe by user
+ ].freeze
+
+ SAFE_MESSAGE_REGEX = /^(#{SAFE_MESSAGE_PREFIXES.join('|')})\s*(?<safe_message>.+)/
+
+ def initialize(message = '')
+ super(sanitize(message))
end
private
# In gitaly-ruby we override this method to do nothing, so that
# sanitization happens in gitlab-rails only.
- def nlbr(str)
- Gitlab::Utils.nlbr(str)
+ def sanitize(message)
+ return message if message.blank?
+
+ safe_messages = message.split("\n").map do |msg|
+ if (match = msg.match(SAFE_MESSAGE_REGEX))
+ match[:safe_message].presence
+ end
+ end
+
+ safe_messages = safe_messages.compact.join("\n")
+
+ Gitlab::Utils.nlbr(safe_messages)
end
end
end
diff --git a/lib/gitlab/gl_repository.rb b/lib/gitlab/gl_repository.rb
index 435b74806e7..c2be7f3d63a 100644
--- a/lib/gitlab/gl_repository.rb
+++ b/lib/gitlab/gl_repository.rb
@@ -2,23 +2,38 @@
module Gitlab
module GlRepository
- def self.gl_repository(project, is_wiki)
- "#{is_wiki ? 'wiki' : 'project'}-#{project.id}"
+ PROJECT = RepoType.new(
+ name: :project,
+ access_checker_class: Gitlab::GitAccess,
+ repository_accessor: -> (project) { project.repository }
+ ).freeze
+ WIKI = RepoType.new(
+ name: :wiki,
+ access_checker_class: Gitlab::GitAccessWiki,
+ repository_accessor: -> (project) { project.wiki.repository }
+ ).freeze
+
+ TYPES = {
+ PROJECT.name.to_s => PROJECT,
+ WIKI.name.to_s => WIKI
+ }.freeze
+
+ def self.types
+ TYPES
end
- # rubocop: disable CodeReuse/ActiveRecord
def self.parse(gl_repository)
- match_data = /\A(project|wiki)-([1-9][0-9]*)\z/.match(gl_repository)
- unless match_data
+ type_name, _id = gl_repository.split('-').first
+ type = types[type_name]
+ subject_id = type&.fetch_id(gl_repository)
+
+ unless subject_id
raise ArgumentError, "Invalid GL Repository \"#{gl_repository}\""
end
- type, id = match_data.captures
- project = Project.find_by(id: id)
- wiki = type == 'wiki'
+ project = Project.find_by_id(subject_id)
- [project, wiki]
+ [project, type]
end
- # rubocop: enable CodeReuse/ActiveRecord
end
end
diff --git a/lib/gitlab/gl_repository/repo_type.rb b/lib/gitlab/gl_repository/repo_type.rb
new file mode 100644
index 00000000000..7abe6c29a25
--- /dev/null
+++ b/lib/gitlab/gl_repository/repo_type.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module GlRepository
+ class RepoType
+ attr_reader :name,
+ :access_checker_class,
+ :repository_accessor
+
+ def initialize(name:, access_checker_class:, repository_accessor:)
+ @name = name
+ @access_checker_class = access_checker_class
+ @repository_accessor = repository_accessor
+ end
+
+ def identifier_for_subject(subject)
+ "#{name}-#{subject.id}"
+ end
+
+ def fetch_id(identifier)
+ match = /\A#{name}-(?<id>\d+)\z/.match(identifier)
+ match[:id] if match
+ end
+
+ def wiki?
+ self == WIKI
+ end
+
+ def project?
+ self == PROJECT
+ end
+
+ def path_suffix
+ project? ? "" : ".#{name}"
+ end
+
+ def repository_for(subject)
+ repository_accessor.call(subject)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/repo_path.rb b/lib/gitlab/repo_path.rb
index 202d310e237..207a80b7db2 100644
--- a/lib/gitlab/repo_path.rb
+++ b/lib/gitlab/repo_path.rb
@@ -5,19 +5,26 @@ module Gitlab
NotFoundError = Class.new(StandardError)
def self.parse(repo_path)
- wiki = false
project_path = repo_path.sub(/\.git\z/, '').sub(%r{\A/}, '')
- project, was_redirected = find_project(project_path)
-
- if project_path.end_with?('.wiki') && project.nil?
- project, was_redirected = find_project(project_path.chomp('.wiki'))
- wiki = true
+ # Detect the repo type based on the path, the first one tried is the project
+ # type, which does not have a suffix.
+ Gitlab::GlRepository.types.each do |_name, type|
+ # If the project path does not end with the defined suffix, try the next
+ # type.
+ # We'll always try to find a project with an empty suffix (for the
+ # `Gitlab::GlRepository::PROJECT` type.
+ next unless project_path.end_with?(type.path_suffix)
+
+ project, was_redirected = find_project(project_path.chomp(type.path_suffix))
+ redirected_path = project_path if was_redirected
+
+ # If we found a matching project, then the type was matched, no need to
+ # continue looking.
+ return [project, type, redirected_path] if project
end
- redirected_path = project_path if was_redirected
-
- [project, wiki, redirected_path]
+ nil
end
def self.find_project(project_path)
diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb
index 265f6213a99..5d5a867c9ab 100644
--- a/lib/gitlab/workhorse.rb
+++ b/lib/gitlab/workhorse.rb
@@ -20,14 +20,14 @@ module Gitlab
SECRET_LENGTH = 32
class << self
- def git_http_ok(repository, is_wiki, user, action, show_all_refs: false)
+ def git_http_ok(repository, repo_type, user, action, show_all_refs: false)
raise "Unsupported action: #{action}" unless ALLOWED_GIT_HTTP_ACTIONS.include?(action.to_s)
project = repository.project
attrs = {
GL_ID: Gitlab::GlId.gl_id(user),
- GL_REPOSITORY: Gitlab::GlRepository.gl_repository(project, is_wiki),
+ GL_REPOSITORY: repo_type.identifier_for_subject(project),
GL_USERNAME: user&.username,
ShowAllRefs: show_all_refs,
Repository: repository.gitaly_repository.to_h,
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 1a0224a44e6..c7755c5c7e2 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -144,6 +144,15 @@ msgstr ""
msgid "%{percent}%% complete"
msgstr ""
+msgid "%{service_title} activated."
+msgstr ""
+
+msgid "%{service_title} settings saved, but not activated."
+msgstr ""
+
+msgid "%{spammable_titlecase} was submitted to Akismet successfully."
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -372,6 +381,9 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access forbidden. Check your access level."
+msgstr ""
+
msgid "Account"
msgstr ""
@@ -609,9 +621,18 @@ msgstr ""
msgid "All issues for this milestone are closed. You may close this milestone now."
msgstr ""
+msgid "All merge conflicts were resolved. The merge request can now be merged."
+msgstr ""
+
+msgid "All todos were marked as done."
+msgstr ""
+
msgid "All users"
msgstr ""
+msgid "All users must have a name."
+msgstr ""
+
msgid "Allow commits from members who can merge to the target branch."
msgstr ""
@@ -954,6 +975,9 @@ msgstr ""
msgid "Authentication method"
msgstr ""
+msgid "Authentication via U2F device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -2447,6 +2471,15 @@ msgstr ""
msgid "Copy token to clipboard"
msgstr ""
+msgid "Could not connect to FogBugz, check your URL"
+msgstr ""
+
+msgid "Could not create Wiki Repository at this time. Please try again later."
+msgstr ""
+
+msgid "Could not remove the trigger."
+msgstr ""
+
msgid "Could not retrieve the pipeline status. For troubleshooting steps, read the %{linkStart}documentation.%{linkEnd}"
msgstr ""
@@ -3370,6 +3403,9 @@ msgstr ""
msgid "Error updating todo status."
msgstr ""
+msgid "Error uploading file"
+msgstr ""
+
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -3541,6 +3577,9 @@ msgstr ""
msgid "Failed to load errors from Sentry. Error message: %{errorMessage}"
msgstr ""
+msgid "Failed to promote label due to internal error. Please contact administrators."
+msgstr ""
+
msgid "Failed to remove issue from board, please try again."
msgstr ""
@@ -3786,6 +3825,9 @@ msgstr ""
msgid "Git"
msgstr ""
+msgid "Git LFS is not enabled on this GitLab server, contact your admin."
+msgstr ""
+
msgid "Git global setup"
msgstr ""
@@ -3966,6 +4008,9 @@ msgstr ""
msgid "GroupSettings|Learn more about badges."
msgstr ""
+msgid "GroupSettings|New runners registration token has been generated!"
+msgstr ""
+
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
msgstr ""
@@ -4130,6 +4175,9 @@ msgstr ""
msgid "Hook was successfully created."
msgstr ""
+msgid "Hook was successfully updated."
+msgstr ""
+
msgid "Housekeeping successfully started"
msgstr ""
@@ -4409,12 +4457,21 @@ msgstr ""
msgid "Introducing Your Conversational Development Index"
msgstr ""
+msgid "Invalid Login or password"
+msgstr ""
+
+msgid "Invalid file."
+msgstr ""
+
msgid "Invalid input, please avoid emojis"
msgstr ""
msgid "Invalid pin code"
msgstr ""
+msgid "Invalid two-factor code."
+msgstr ""
+
msgid "Invitation"
msgstr ""
@@ -4478,6 +4535,9 @@ msgstr ""
msgid "Job has been erased"
msgstr ""
+msgid "Job has been successfully erased!"
+msgstr ""
+
msgid "Job is stuck. Check runners."
msgstr ""
@@ -4986,6 +5046,9 @@ msgstr ""
msgid "Merged"
msgstr ""
+msgid "Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes."
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -5079,6 +5142,9 @@ msgstr ""
msgid "Mirroring repositories"
msgstr ""
+msgid "Mirroring settings were successfully updated."
+msgstr ""
+
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr ""
@@ -5384,6 +5450,9 @@ msgstr ""
msgid "Not enough data"
msgstr ""
+msgid "Not found."
+msgstr ""
+
msgid "Not now"
msgstr ""
@@ -5489,6 +5558,9 @@ msgstr ""
msgid "November"
msgstr ""
+msgid "Object does not exist on the server or you don't have permissions to access it"
+msgstr ""
+
msgid "Oct"
msgstr ""
@@ -5590,6 +5662,12 @@ msgstr ""
msgid "Owner"
msgstr ""
+msgid "Page not found"
+msgstr ""
+
+msgid "Page was successfully deleted"
+msgstr ""
+
msgid "Pages"
msgstr ""
@@ -5752,6 +5830,12 @@ msgstr ""
msgid "Pipelines for last year"
msgstr ""
+msgid "Pipelines page"
+msgstr ""
+
+msgid "Pipelines settings for '%{project_name}' were successfully updated."
+msgstr ""
+
msgid "Pipelines|Build with confidence"
msgstr ""
@@ -5896,6 +5980,9 @@ msgstr ""
msgid "Please note that this application is not provided by GitLab and you should verify its authenticity before allowing access."
msgstr ""
+msgid "Please select a group."
+msgstr ""
+
msgid "Please select at least one filter to see results"
msgstr ""
@@ -6217,6 +6304,12 @@ msgstr ""
msgid "Project \"%{name}\" is no longer available. Select another project to continue."
msgstr ""
+msgid "Project %{project_repo} could not be found"
+msgstr ""
+
+msgid "Project '%{project_name}' is being imported."
+msgstr ""
+
msgid "Project '%{project_name}' is in the process of being deleted."
msgstr ""
@@ -6696,6 +6789,12 @@ msgstr ""
msgid "Resolved"
msgstr ""
+msgid "Resolved 1 discussion."
+msgstr ""
+
+msgid "Resolved all discussions."
+msgstr ""
+
msgid "Response metrics (AWS ELB)"
msgstr ""
@@ -7019,6 +7118,9 @@ msgstr ""
msgid "September"
msgstr ""
+msgid "Server supports batch API only, please update your Git LFS client to version 1.0.1 and up."
+msgstr ""
+
msgid "Server version"
msgstr ""
@@ -7603,6 +7705,9 @@ msgstr ""
msgid "Successfully removed email."
msgstr ""
+msgid "Successfully scheduled a pipeline to run. Go to the %{link_to_pipelines} for details."
+msgstr ""
+
msgid "Successfully unblocked"
msgstr ""
@@ -7756,6 +7861,9 @@ msgstr ""
msgid "Test coverage parsing"
msgstr ""
+msgid "Test failed."
+msgstr ""
+
msgid "The Git LFS objects will <strong>not</strong> be synced."
msgstr ""
@@ -7774,9 +7882,24 @@ msgstr ""
msgid "The collection of events added to the data gathered for that stage."
msgstr ""
+msgid "The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository."
+msgstr ""
+
msgid "The deployment of this job to %{environmentLink} did not succeed."
msgstr ""
+msgid "The directory has been successfully created."
+msgstr ""
+
+msgid "The entered user map is not a valid JSON user map."
+msgstr ""
+
+msgid "The file has been successfully created."
+msgstr ""
+
+msgid "The file has been successfully deleted."
+msgstr ""
+
msgid "The fork relationship has been removed."
msgstr ""
@@ -7789,6 +7912,12 @@ msgstr ""
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
+msgid "The invitation has already been accepted."
+msgstr ""
+
+msgid "The invitation was successfully resent."
+msgstr ""
+
msgid "The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage."
msgstr ""
@@ -7798,6 +7927,15 @@ msgstr ""
msgid "The maximum file size allowed is 200KB."
msgstr ""
+msgid "The merge conflicts for this merge request cannot be resolved through GitLab. Please try to resolve them locally."
+msgstr ""
+
+msgid "The merge conflicts for this merge request have already been resolved."
+msgstr ""
+
+msgid "The merge conflicts for this merge request have already been resolved. Please return to the merge request."
+msgstr ""
+
msgid "The name %{entryName} is already taken in this directory."
msgstr ""
@@ -7822,6 +7960,15 @@ msgstr ""
msgid "The project can be accessed without any authentication."
msgstr ""
+msgid "The project was successfully forked."
+msgstr ""
+
+msgid "The project was successfully imported."
+msgstr ""
+
+msgid "The remote repository is being updated..."
+msgstr ""
+
msgid "The repository for this project does not exist."
msgstr ""
@@ -7852,12 +7999,18 @@ msgstr ""
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
+msgid "The uploaded file is not a valid Google Takeout archive."
+msgstr ""
+
msgid "The usage ping is disabled, and cannot be configured through this form."
msgstr ""
msgid "The user is being deleted."
msgstr ""
+msgid "The user map has been saved. Continue by selecting the projects you want to import."
+msgstr ""
+
msgid "The user map is a JSON document mapping the Google Code users that participated on your projects to the way their email addresses and usernames will be imported into GitLab. You can change this by changing the value on the right hand side of <code>:</code>. Be sure to preserve the surrounding double quotes, other punctuation and the email address or username on the left hand side."
msgstr ""
@@ -7921,6 +8074,9 @@ msgstr ""
msgid "There was an error when unsubscribing from this label."
msgstr ""
+msgid "There was an error with the reCAPTCHA. Please solve the reCAPTCHA again."
+msgstr ""
+
msgid "These existing issues have a similar title. It might be better to comment there instead of creating another similar issue."
msgstr ""
@@ -8071,6 +8227,9 @@ msgstr ""
msgid "This merge request is locked."
msgstr ""
+msgid "This namespace has already been taken! Please choose another one."
+msgstr ""
+
msgid "This option is disabled as you don't have write permissions for the current branch"
msgstr ""
@@ -8107,6 +8266,9 @@ msgstr ""
msgid "This repository"
msgstr ""
+msgid "This repository is currently empty. A new Auto DevOps pipeline will be created after a new file has been pushed to a branch."
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -8393,6 +8555,9 @@ msgstr ""
msgid "Todo"
msgstr ""
+msgid "Todo was successfully marked as done."
+msgstr ""
+
msgid "Todos"
msgstr ""
@@ -8450,6 +8615,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trigger removed."
+msgstr ""
+
msgid "Trigger this manual action"
msgstr ""
@@ -8459,6 +8627,15 @@ msgstr ""
msgid "Trigger variables:"
msgstr ""
+msgid "Trigger was created successfully."
+msgstr ""
+
+msgid "Trigger was re-assigned."
+msgstr ""
+
+msgid "Trigger was successfully updated."
+msgstr ""
+
msgid "Triggers can force a specific branch or tag to get rebuilt with an API call. These tokens will impersonate their associated user including their access to projects and their project permissions."
msgstr ""
@@ -8483,9 +8660,15 @@ msgstr ""
msgid "Type"
msgstr ""
+msgid "Unable to connect to server: %{error}"
+msgstr ""
+
msgid "Unable to load the diff. %{button_try_again}"
msgstr ""
+msgid "Unable to schedule a pipeline to run immediately"
+msgstr ""
+
msgid "Unblock"
msgstr ""
@@ -8561,6 +8744,9 @@ msgstr ""
msgid "Update now"
msgstr ""
+msgid "Update your bookmarked URLs as filtered/sorted branches URL has been changed."
+msgstr ""
+
msgid "Update your group name, description, avatar, and visibility."
msgstr ""
@@ -8657,6 +8843,12 @@ msgstr ""
msgid "User was successfully created."
msgstr ""
+msgid "User was successfully removed from group and any subresources."
+msgstr ""
+
+msgid "User was successfully removed from project."
+msgstr ""
+
msgid "User was successfully updated."
msgstr ""
@@ -8750,6 +8942,9 @@ msgstr ""
msgid "Validate your GitLab CI configuration file"
msgstr ""
+msgid "Validations failed."
+msgstr ""
+
msgid "Value"
msgstr ""
@@ -8888,6 +9083,9 @@ msgstr ""
msgid "Wiki"
msgstr ""
+msgid "Wiki was successfully updated."
+msgstr ""
+
msgid "WikiClone|Clone your wiki"
msgstr ""
@@ -9107,6 +9305,12 @@ msgstr ""
msgid "You can move around the graph by using the arrow keys."
msgstr ""
+msgid "You can now submit a merge request to get this change into the original branch."
+msgstr ""
+
+msgid "You can now submit a merge request to get this change into the original project."
+msgstr ""
+
msgid "You can only add files when you are on a branch"
msgstr ""
@@ -9134,9 +9338,18 @@ msgstr ""
msgid "You cannot impersonate an internal user"
msgstr ""
+msgid "You cannot play this scheduled pipeline at the moment. Please wait a minute."
+msgstr ""
+
msgid "You cannot write to this read-only GitLab instance."
msgstr ""
+msgid "You could not create a new trigger."
+msgstr ""
+
+msgid "You could not take ownership of trigger."
+msgstr ""
+
msgid "You do not have any subscriptions yet"
msgstr ""
@@ -9155,6 +9368,9 @@ msgstr ""
msgid "You have reached your project limit"
msgstr ""
+msgid "You left the \"%{membershipable_human_name}\" %{source_type}."
+msgstr ""
+
msgid "You may also add variables that are made available to the running application by prepending the variable key with <code>K8S_SECRET_</code>."
msgstr ""
@@ -9170,6 +9386,15 @@ msgstr ""
msgid "You need to register a two-factor authentication app before you can set up a U2F device."
msgstr ""
+msgid "You need to specify both an Access Token and a Host URL."
+msgstr ""
+
+msgid "You need to upload a GitLab project export archive (ending in .gz)."
+msgstr ""
+
+msgid "You need to upload a Google Takeout archive."
+msgstr ""
+
msgid "You will lose all changes you've made to this file. This action cannot be undone."
msgstr ""
@@ -9242,6 +9467,9 @@ msgstr ""
msgid "Your U2F device was registered!"
msgstr ""
+msgid "Your access request to the %{source_type} has been withdrawn."
+msgstr ""
+
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
@@ -9263,6 +9491,9 @@ msgstr ""
msgid "Your changes have been saved"
msgstr ""
+msgid "Your changes have been successfully committed."
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -9287,6 +9518,9 @@ msgstr ""
msgid "Your projects"
msgstr ""
+msgid "Your request for access has been queued for review."
+msgstr ""
+
msgid "a deleted user"
msgstr ""
@@ -9366,6 +9600,9 @@ msgstr ""
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
+msgid "failed"
+msgstr ""
+
msgid "for %{link_to_merge_request} with %{link_to_merge_request_source_branch}"
msgstr ""
@@ -9743,6 +9980,9 @@ msgstr ""
msgid "stuck"
msgstr ""
+msgid "success"
+msgstr ""
+
msgid "syntax is correct"
msgstr ""
diff --git a/package.json b/package.json
index b40436d057e..f0f819fdb74 100644
--- a/package.json
+++ b/package.json
@@ -160,7 +160,9 @@
"jasmine-diff": "^0.1.3",
"jasmine-jquery": "^2.1.1",
"jest": "^24.1.0",
+ "jest-environment-jsdom": "^24.0.0",
"jest-junit": "^6.3.0",
+ "jest-util": "^24.0.0",
"jsdoc": "^3.5.5",
"jsdoc-vue": "^1.0.0",
"karma": "^3.0.0",
diff --git a/qa/qa/page/project/job/show.rb b/qa/qa/page/project/job/show.rb
index 9c218f4ed8b..5853f487f0b 100644
--- a/qa/qa/page/project/job/show.rb
+++ b/qa/qa/page/project/job/show.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module QA::Page
module Project::Job
class Show < QA::Page::Base
@@ -31,7 +33,9 @@ module QA::Page
private
def loaded?(wait: 60)
- has_element?(:build_trace, wait: wait)
+ wait(reload: true, max: wait, interval: 1) do
+ has_element?(:build_trace, wait: 1)
+ end
end
def completed?(timeout: 60)
diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
index 0b92ea29ca4..ceb888bb4ef 100644
--- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
+++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
@@ -106,8 +106,7 @@ module QA
end
end
- # Failure issue: https://gitlab.com/gitlab-org/quality/nightly/issues/87
- describe 'Auto DevOps', :smoke, :quarantine do
+ describe 'Auto DevOps', :smoke do
it 'enables AutoDevOps by default' do
login
diff --git a/spec/controllers/graphql_controller_spec.rb b/spec/controllers/graphql_controller_spec.rb
new file mode 100644
index 00000000000..c19a752b07b
--- /dev/null
+++ b/spec/controllers/graphql_controller_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe GraphqlController do
+ before do
+ stub_feature_flags(graphql: true)
+ end
+
+ describe 'POST #execute' do
+ context 'when user is logged in' do
+ let(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ end
+
+ it 'returns 200 when user can access API' do
+ post :execute
+
+ expect(response).to have_gitlab_http_status(200)
+ end
+
+ it 'returns access denied template when user cannot access API' do
+ # User cannot access API in a couple of cases
+ # * When user is internal(like ghost users)
+ # * When user is blocked
+ expect(Ability).to receive(:allowed?).with(user, :access_api, :global).and_return(false)
+
+ post :execute
+
+ expect(response.status).to eq(403)
+ expect(response).to render_template('errors/access_denied')
+ end
+ end
+
+ context 'when user is not logged in' do
+ it 'returns 200' do
+ post :execute
+
+ expect(response).to have_gitlab_http_status(200)
+ end
+ end
+ end
+end
diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb
index 6e349395017..adac59b89ef 100644
--- a/spec/features/milestone_spec.rb
+++ b/spec/features/milestone_spec.rb
@@ -122,4 +122,32 @@ describe 'Milestone' do
expect(page).to have_selector('.popover')
end
end
+
+ describe 'reopen closed milestones' do
+ before do
+ create(:milestone, :closed, project: project)
+ end
+
+ describe 'group milestones page' do
+ it 'reopens the milestone' do
+ visit group_milestones_path(group, { state: 'closed' })
+
+ click_link 'Reopen Milestone'
+
+ expect(page).not_to have_selector('.status-box-closed')
+ expect(page).to have_selector('.status-box-open')
+ end
+ end
+
+ describe 'project milestones page' do
+ it 'reopens the milestone' do
+ visit project_milestones_path(project, { state: 'closed' })
+
+ click_link 'Reopen Milestone'
+
+ expect(page).not_to have_selector('.status-box-closed')
+ expect(page).to have_selector('.status-box-open')
+ end
+ end
+ end
end
diff --git a/spec/features/projects/artifacts/user_browses_artifacts_spec.rb b/spec/features/projects/artifacts/user_browses_artifacts_spec.rb
index 5f630c9ffa4..a1fcd4024c0 100644
--- a/spec/features/projects/artifacts/user_browses_artifacts_spec.rb
+++ b/spec/features/projects/artifacts/user_browses_artifacts_spec.rb
@@ -19,6 +19,12 @@ describe "User browses artifacts" do
visit(browse_project_job_artifacts_path(project, job))
end
+ it "renders a link to the job in the breadcrumbs" do
+ page.within('.js-breadcrumbs-list') do
+ expect(page).to have_link("##{job.id}", href: project_job_path(project, job))
+ end
+ end
+
it "shows artifacts" do
expect(page).not_to have_selector(".build-sidebar")
diff --git a/spec/features/tags/master_deletes_tag_spec.rb b/spec/features/tags/master_deletes_tag_spec.rb
index 8d567e925ef..bdbbe645779 100644
--- a/spec/features/tags/master_deletes_tag_spec.rb
+++ b/spec/features/tags/master_deletes_tag_spec.rb
@@ -37,7 +37,7 @@ describe 'Maintainer deletes tag' do
context 'when pre-receive hook fails', :js do
before do
allow_any_instance_of(Gitlab::GitalyClient::OperationService).to receive(:rm_tag)
- .and_raise(Gitlab::Git::PreReceiveError, 'Do not delete tags')
+ .and_raise(Gitlab::Git::PreReceiveError, 'GitLab: Do not delete tags')
end
it 'shows the error message' do
diff --git a/spec/frontend/environment.js b/spec/frontend/environment.js
new file mode 100644
index 00000000000..cb128c7d880
--- /dev/null
+++ b/spec/frontend/environment.js
@@ -0,0 +1,27 @@
+/* eslint-disable import/no-commonjs */
+
+const { ErrorWithStack } = require('jest-util');
+const JSDOMEnvironment = require('jest-environment-jsdom');
+
+class CustomEnvironment extends JSDOMEnvironment {
+ constructor(config, context) {
+ super(config, context);
+ Object.assign(context.console, {
+ error(...args) {
+ throw new ErrorWithStack(
+ `Unexpected call of console.error() with:\n\n${args.join(', ')}`,
+ this.error,
+ );
+ },
+
+ warn(...args) {
+ throw new ErrorWithStack(
+ `Unexpected call of console.warn() with:\n\n${args.join(', ')}`,
+ this.warn,
+ );
+ },
+ });
+ }
+}
+
+module.exports = CustomEnvironment;
diff --git a/spec/frontend/helpers/fixtures.js b/spec/frontend/helpers/fixtures.js
index f96f27c4d80..de9058d7832 100644
--- a/spec/frontend/helpers/fixtures.js
+++ b/spec/frontend/helpers/fixtures.js
@@ -3,8 +3,6 @@
import fs from 'fs';
import path from 'path';
-// jest-util is part of Jest
-// eslint-disable-next-line import/no-extraneous-dependencies
import { ErrorWithStack } from 'jest-util';
const fixturesBasePath = path.join(process.cwd(), 'spec', 'javascripts', 'fixtures');
diff --git a/spec/javascripts/diffs/components/diff_file_header_spec.js b/spec/javascripts/diffs/components/diff_file_header_spec.js
index 66c5b17b825..e10193c25b7 100644
--- a/spec/javascripts/diffs/components/diff_file_header_spec.js
+++ b/spec/javascripts/diffs/components/diff_file_header_spec.js
@@ -23,9 +23,6 @@ describe('diff_file_header', () => {
});
beforeEach(() => {
- gon.features = {
- expandDiffFullFile: true,
- };
const diffFile = diffDiscussionMock.diff_file;
diffFile.added_lines = 2;
diff --git a/spec/javascripts/notes/components/note_form_spec.js b/spec/javascripts/notes/components/note_form_spec.js
index c48f8188105..b632ee6736d 100644
--- a/spec/javascripts/notes/components/note_form_spec.js
+++ b/spec/javascripts/notes/components/note_form_spec.js
@@ -41,8 +41,6 @@ describe('issue_note_form component', () => {
noteBody: 'Magni suscipit eius consectetur enim et ex et commodi.',
noteId: '545',
};
-
- wrapper = createComponentWrapper();
});
afterEach(() => {
@@ -50,6 +48,10 @@ describe('issue_note_form component', () => {
});
describe('noteHash', () => {
+ beforeEach(() => {
+ wrapper = createComponentWrapper();
+ });
+
it('returns note hash string based on `noteId`', () => {
expect(wrapper.vm.noteHash).toBe(`#note_${props.noteId}`);
});
@@ -71,6 +73,10 @@ describe('issue_note_form component', () => {
});
describe('conflicts editing', () => {
+ beforeEach(() => {
+ wrapper = createComponentWrapper();
+ });
+
it('should show conflict message if note changes outside the component', done => {
wrapper.setProps({
...props,
@@ -100,6 +106,10 @@ describe('issue_note_form component', () => {
});
describe('form', () => {
+ beforeEach(() => {
+ wrapper = createComponentWrapper();
+ });
+
it('should render text area with placeholder', () => {
const textarea = wrapper.find('textarea');
@@ -198,10 +208,6 @@ describe('issue_note_form component', () => {
});
describe('with autosaveKey', () => {
- beforeEach(() => {
- wrapper.destroy();
- });
-
describe('with draft', () => {
beforeEach(done => {
Object.assign(props, {
diff --git a/spec/javascripts/pipelines/graph/stage_column_component_spec.js b/spec/javascripts/pipelines/graph/stage_column_component_spec.js
index dafb892da43..3240e8e4c1b 100644
--- a/spec/javascripts/pipelines/graph/stage_column_component_spec.js
+++ b/spec/javascripts/pipelines/graph/stage_column_component_spec.js
@@ -55,7 +55,7 @@ describe('stage column component', () => {
id: 4259,
name: '<img src=x onerror=alert(document.domain)>',
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
label: 'success',
tooltip: '<img src=x onerror=alert(document.domain)>',
},
diff --git a/spec/javascripts/sidebar/assignees_spec.js b/spec/javascripts/sidebar/assignees_spec.js
index eced4925489..57b16b12cb0 100644
--- a/spec/javascripts/sidebar/assignees_spec.js
+++ b/spec/javascripts/sidebar/assignees_spec.js
@@ -210,6 +210,19 @@ describe('Assignee component', () => {
expect(component.$el.querySelector('.user-list-more')).toBe(null);
});
+ it('sets tooltip container to body', () => {
+ const users = UsersMockHelper.createNumberRandomUsers(2);
+ component = new AssigneeComponent({
+ propsData: {
+ rootPath: 'http://localhost:3000',
+ users,
+ editable: true,
+ },
+ }).$mount();
+
+ expect(component.$el.querySelector('.user-link').getAttribute('data-container')).toBe('body');
+ });
+
it('Shows the "show-less" assignees label', done => {
const users = UsersMockHelper.createNumberRandomUsers(6);
component = new AssigneeComponent({
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js
index 3229ddd5e27..780bed1bf69 100644
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js
@@ -120,7 +120,7 @@ describe('MRWidgetFailedToMerge', () => {
it('renders given error', () => {
expect(vm.$el.querySelector('.has-error-message').textContent.trim()).toEqual(
- 'Merge error happened.',
+ 'Merge error happened',
);
});
diff --git a/spec/lib/gitlab/git/pre_receive_error_spec.rb b/spec/lib/gitlab/git/pre_receive_error_spec.rb
index 1b8be62dec6..cb030e38032 100644
--- a/spec/lib/gitlab/git/pre_receive_error_spec.rb
+++ b/spec/lib/gitlab/git/pre_receive_error_spec.rb
@@ -1,9 +1,19 @@
require 'spec_helper'
describe Gitlab::Git::PreReceiveError do
- it 'makes its message HTML-friendly' do
- ex = described_class.new("hello\nworld\n")
+ Gitlab::Git::PreReceiveError::SAFE_MESSAGE_PREFIXES.each do |prefix|
+ context "error messages prefixed with #{prefix}" do
+ it 'accepts only errors lines with the prefix' do
+ ex = described_class.new("#{prefix} Hello,\nworld!")
- expect(ex.message).to eq('hello<br>world<br>')
+ expect(ex.message).to eq('Hello,')
+ end
+
+ it 'makes its message HTML-friendly' do
+ ex = described_class.new("#{prefix} Hello,\n#{prefix} world!\n")
+
+ expect(ex.message).to eq('Hello,<br>world!')
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
index b37fe2686b6..7579a6577b9 100644
--- a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
@@ -39,7 +39,7 @@ describe Gitlab::GitalyClient::OperationService do
context "when pre_receive_error is present" do
let(:response) do
- Gitaly::UserCreateBranchResponse.new(pre_receive_error: "something failed")
+ Gitaly::UserCreateBranchResponse.new(pre_receive_error: "GitLab: something failed")
end
it "throws a PreReceive exception" do
@@ -80,7 +80,7 @@ describe Gitlab::GitalyClient::OperationService do
context "when pre_receive_error is present" do
let(:response) do
- Gitaly::UserUpdateBranchResponse.new(pre_receive_error: "something failed")
+ Gitaly::UserUpdateBranchResponse.new(pre_receive_error: "GitLab: something failed")
end
it "throws a PreReceive exception" do
@@ -117,7 +117,7 @@ describe Gitlab::GitalyClient::OperationService do
context "when pre_receive_error is present" do
let(:response) do
- Gitaly::UserDeleteBranchResponse.new(pre_receive_error: "something failed")
+ Gitaly::UserDeleteBranchResponse.new(pre_receive_error: "GitLab: something failed")
end
it "throws a PreReceive exception" do
@@ -175,7 +175,7 @@ describe Gitlab::GitalyClient::OperationService do
shared_examples 'cherry pick and revert errors' do
context 'when a pre_receive_error is present' do
- let(:response) { response_class.new(pre_receive_error: "something failed") }
+ let(:response) { response_class.new(pre_receive_error: "GitLab: something failed") }
it 'raises a PreReceiveError' do
expect { subject }.to raise_error(Gitlab::Git::PreReceiveError, "something failed")
@@ -313,7 +313,7 @@ describe Gitlab::GitalyClient::OperationService do
end
context 'when a pre_receive_error is present' do
- let(:response) { Gitaly::UserCommitFilesResponse.new(pre_receive_error: "something failed") }
+ let(:response) { Gitaly::UserCommitFilesResponse.new(pre_receive_error: "GitLab: something failed") }
it 'raises a PreReceiveError' do
expect { subject }.to raise_error(Gitlab::Git::PreReceiveError, "something failed")
diff --git a/spec/lib/gitlab/gl_repository/repo_type_spec.rb b/spec/lib/gitlab/gl_repository/repo_type_spec.rb
new file mode 100644
index 00000000000..f06a2448ff7
--- /dev/null
+++ b/spec/lib/gitlab/gl_repository/repo_type_spec.rb
@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+describe Gitlab::GlRepository::RepoType do
+ set(:project) { create(:project) }
+
+ shared_examples 'a repo type' do
+ describe "#identifier_for_subject" do
+ subject { described_class.identifier_for_subject(project) }
+
+ it { is_expected.to eq(expected_identifier) }
+ end
+
+ describe "#fetch_id" do
+ it "finds an id match in the identifier" do
+ expect(described_class.fetch_id(expected_identifier)).to eq(expected_id)
+ end
+
+ it 'does not break on other identifiers' do
+ expect(described_class.fetch_id("wiki-noid")).to eq(nil)
+ end
+ end
+
+ describe "#path_suffix" do
+ subject { described_class.path_suffix }
+
+ it { is_expected.to eq(expected_suffix) }
+ end
+
+ describe "#repository_for" do
+ it "finds the repository for the repo type" do
+ expect(described_class.repository_for(project)).to eq(expected_repository)
+ end
+ end
+ end
+
+ describe Gitlab::GlRepository::PROJECT do
+ it_behaves_like 'a repo type' do
+ let(:expected_identifier) { "project-#{project.id}" }
+ let(:expected_id) { project.id.to_s }
+ let(:expected_suffix) { "" }
+ let(:expected_repository) { project.repository }
+ end
+
+ it "knows its type" do
+ expect(described_class).not_to be_wiki
+ expect(described_class).to be_project
+ end
+ end
+
+ describe Gitlab::GlRepository::WIKI do
+ it_behaves_like 'a repo type' do
+ let(:expected_identifier) { "wiki-#{project.id}" }
+ let(:expected_id) { project.id.to_s }
+ let(:expected_suffix) { ".wiki" }
+ let(:expected_repository) { project.wiki.repository }
+ end
+
+ it "knows its type" do
+ expect(described_class).to be_wiki
+ expect(described_class).not_to be_project
+ end
+ end
+end
diff --git a/spec/lib/gitlab/gl_repository_spec.rb b/spec/lib/gitlab/gl_repository_spec.rb
index 4e09020471b..d4b6c629659 100644
--- a/spec/lib/gitlab/gl_repository_spec.rb
+++ b/spec/lib/gitlab/gl_repository_spec.rb
@@ -5,11 +5,11 @@ describe ::Gitlab::GlRepository do
set(:project) { create(:project, :repository) }
it 'parses a project gl_repository' do
- expect(described_class.parse("project-#{project.id}")).to eq([project, false])
+ expect(described_class.parse("project-#{project.id}")).to eq([project, Gitlab::GlRepository::PROJECT])
end
it 'parses a wiki gl_repository' do
- expect(described_class.parse("wiki-#{project.id}")).to eq([project, true])
+ expect(described_class.parse("wiki-#{project.id}")).to eq([project, Gitlab::GlRepository::WIKI])
end
it 'throws an argument error on an invalid gl_repository' do
diff --git a/spec/lib/gitlab/repo_path_spec.rb b/spec/lib/gitlab/repo_path_spec.rb
index 13940713dfc..4c7ca4e2b57 100644
--- a/spec/lib/gitlab/repo_path_spec.rb
+++ b/spec/lib/gitlab/repo_path_spec.rb
@@ -6,43 +6,47 @@ describe ::Gitlab::RepoPath do
context 'a repository storage path' do
it 'parses a full repository path' do
- expect(described_class.parse(project.repository.full_path)).to eq([project, false, nil])
+ expect(described_class.parse(project.repository.full_path)).to eq([project, Gitlab::GlRepository::PROJECT, nil])
end
it 'parses a full wiki path' do
- expect(described_class.parse(project.wiki.repository.full_path)).to eq([project, true, nil])
+ expect(described_class.parse(project.wiki.repository.full_path)).to eq([project, Gitlab::GlRepository::WIKI, nil])
end
end
context 'a relative path' do
it 'parses a relative repository path' do
- expect(described_class.parse(project.full_path + '.git')).to eq([project, false, nil])
+ expect(described_class.parse(project.full_path + '.git')).to eq([project, Gitlab::GlRepository::PROJECT, nil])
end
it 'parses a relative wiki path' do
- expect(described_class.parse(project.full_path + '.wiki.git')).to eq([project, true, nil])
+ expect(described_class.parse(project.full_path + '.wiki.git')).to eq([project, Gitlab::GlRepository::WIKI, nil])
end
it 'parses a relative path starting with /' do
- expect(described_class.parse('/' + project.full_path + '.git')).to eq([project, false, nil])
+ expect(described_class.parse('/' + project.full_path + '.git')).to eq([project, Gitlab::GlRepository::PROJECT, nil])
end
context 'of a redirected project' do
let(:redirect) { project.route.create_redirect('foo/bar') }
it 'parses a relative repository path' do
- expect(described_class.parse(redirect.path + '.git')).to eq([project, false, 'foo/bar'])
+ expect(described_class.parse(redirect.path + '.git')).to eq([project, Gitlab::GlRepository::PROJECT, 'foo/bar'])
end
it 'parses a relative wiki path' do
- expect(described_class.parse(redirect.path + '.wiki.git')).to eq([project, true, 'foo/bar.wiki'])
+ expect(described_class.parse(redirect.path + '.wiki.git')).to eq([project, Gitlab::GlRepository::WIKI, 'foo/bar.wiki'])
end
it 'parses a relative path starting with /' do
- expect(described_class.parse('/' + redirect.path + '.git')).to eq([project, false, 'foo/bar'])
+ expect(described_class.parse('/' + redirect.path + '.git')).to eq([project, Gitlab::GlRepository::PROJECT, 'foo/bar'])
end
end
end
+
+ it "returns nil for non existent paths" do
+ expect(described_class.parse("path/non-existent.git")).to eq(nil)
+ end
end
describe '.find_project' do
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
index 7213eee5675..d88086b01b1 100644
--- a/spec/lib/gitlab/workhorse_spec.rb
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -250,11 +250,11 @@ describe Gitlab::Workhorse do
}
end
- subject { described_class.git_http_ok(repository, false, user, action) }
+ subject { described_class.git_http_ok(repository, Gitlab::GlRepository::PROJECT, user, action) }
it { expect(subject).to include(params) }
- context 'when is_wiki' do
+ context 'when the repo_type is a wiki' do
let(:params) do
{
GL_ID: "user-#{user.id}",
@@ -264,7 +264,7 @@ describe Gitlab::Workhorse do
}
end
- subject { described_class.git_http_ok(repository, true, user, action) }
+ subject { described_class.git_http_ok(repository, Gitlab::GlRepository::WIKI, user, action) }
it { expect(subject).to include(params) }
end
@@ -304,7 +304,7 @@ describe Gitlab::Workhorse do
end
context 'show_all_refs enabled' do
- subject { described_class.git_http_ok(repository, false, user, action, show_all_refs: true) }
+ subject { described_class.git_http_ok(repository, Gitlab::GlRepository::PROJECT, user, action, show_all_refs: true) }
it { is_expected.to include(ShowAllRefs: true) }
end
@@ -322,7 +322,7 @@ describe Gitlab::Workhorse do
it { expect(subject).to include(gitaly_params) }
context 'show_all_refs enabled' do
- subject { described_class.git_http_ok(repository, false, user, action, show_all_refs: true) }
+ subject { described_class.git_http_ok(repository, Gitlab::GlRepository::PROJECT, user, action, show_all_refs: true) }
it { is_expected.to include(ShowAllRefs: true) }
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 1ea54eeb4f7..90dcf861849 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -2710,7 +2710,7 @@ describe Project do
end
describe '#any_lfs_file_locks?', :request_store do
- set(:project) { create(:project) }
+ let!(:project) { create(:project) }
it 'returns false when there are no LFS file locks' do
expect(project.any_lfs_file_locks?).to be_falsey
@@ -3148,6 +3148,53 @@ describe Project do
expect(projects).to eq([public_project])
end
end
+
+ context 'with requested visibility levels' do
+ set(:internal_project) { create(:project, :internal, :repository) }
+ set(:private_project_2) { create(:project, :private) }
+
+ context 'with admin user' do
+ set(:admin) { create(:admin) }
+
+ it 'returns all projects' do
+ projects = described_class.all.public_or_visible_to_user(admin, [])
+
+ expect(projects).to match_array([public_project, private_project, private_project_2, internal_project])
+ end
+
+ it 'returns all public and private projects' do
+ projects = described_class.all.public_or_visible_to_user(admin, [Gitlab::VisibilityLevel::PUBLIC, Gitlab::VisibilityLevel::PRIVATE])
+
+ expect(projects).to match_array([public_project, private_project, private_project_2])
+ end
+
+ it 'returns all private projects' do
+ projects = described_class.all.public_or_visible_to_user(admin, [Gitlab::VisibilityLevel::PRIVATE])
+
+ expect(projects).to match_array([private_project, private_project_2])
+ end
+ end
+
+ context 'with regular user' do
+ it 'returns authorized projects' do
+ projects = described_class.all.public_or_visible_to_user(user, [])
+
+ expect(projects).to match_array([public_project, private_project, internal_project])
+ end
+
+ it "returns user's public and private projects" do
+ projects = described_class.all.public_or_visible_to_user(user, [Gitlab::VisibilityLevel::PUBLIC, Gitlab::VisibilityLevel::PRIVATE])
+
+ expect(projects).to match_array([public_project, private_project])
+ end
+
+ it 'returns one private project' do
+ projects = described_class.all.public_or_visible_to_user(user, [Gitlab::VisibilityLevel::PRIVATE])
+
+ expect(projects).to eq([private_project])
+ end
+ end
+ end
end
describe '.with_feature_available_for_user' do
@@ -3428,7 +3475,7 @@ describe Project do
end
it 'schedules HashedStorage::ProjectMigrateWorker with delayed start when the project repo is in use' do
- Gitlab::ReferenceCounter.new(project.gl_repository(is_wiki: false)).increase
+ Gitlab::ReferenceCounter.new(Gitlab::GlRepository::PROJECT.identifier_for_subject(project)).increase
expect(HashedStorage::ProjectMigrateWorker).to receive(:perform_in)
@@ -3436,7 +3483,7 @@ describe Project do
end
it 'schedules HashedStorage::ProjectMigrateWorker with delayed start when the wiki repo is in use' do
- Gitlab::ReferenceCounter.new(project.gl_repository(is_wiki: true)).increase
+ Gitlab::ReferenceCounter.new(Gitlab::GlRepository::WIKI.identifier_for_subject(project)).increase
expect(HashedStorage::ProjectMigrateWorker).to receive(:perform_in)
@@ -3569,16 +3616,6 @@ describe Project do
end
end
- describe '#gl_repository' do
- let(:project) { create(:project) }
-
- it 'delegates to Gitlab::GlRepository.gl_repository' do
- expect(Gitlab::GlRepository).to receive(:gl_repository).with(project, true)
-
- project.gl_repository(is_wiki: true)
- end
- end
-
describe '#has_ci?' do
set(:project) { create(:project) }
let(:repository) { double }
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index b184c92824a..537194b8e11 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -321,7 +321,7 @@ describe API::Internal do
end
context 'with env passed as a JSON' do
- let(:gl_repository) { project.gl_repository(is_wiki: true) }
+ let(:gl_repository) { Gitlab::GlRepository::WIKI.identifier_for_subject(project) }
it 'sets env in RequestStore' do
obj_dir_relative = './objects'
@@ -975,9 +975,9 @@ describe API::Internal do
def gl_repository_for(project_or_wiki)
case project_or_wiki
when ProjectWiki
- project_or_wiki.project.gl_repository(is_wiki: true)
+ Gitlab::GlRepository::WIKI.identifier_for_subject(project_or_wiki.project)
when Project
- project_or_wiki.gl_repository(is_wiki: false)
+ Gitlab::GlRepository::PROJECT.identifier_for_subject(project_or_wiki)
else
nil
end
diff --git a/spec/services/merge_requests/ff_merge_service_spec.rb b/spec/services/merge_requests/ff_merge_service_spec.rb
index fe673de46aa..1430e12a07e 100644
--- a/spec/services/merge_requests/ff_merge_service_spec.rb
+++ b/spec/services/merge_requests/ff_merge_service_spec.rb
@@ -72,7 +72,7 @@ describe MergeRequests::FfMergeService do
it 'logs and saves error if there is an PreReceiveError exception' do
error_message = 'error message'
- allow(service).to receive(:repository).and_raise(Gitlab::Git::PreReceiveError, error_message)
+ allow(service).to receive(:repository).and_raise(Gitlab::Git::PreReceiveError, "GitLab: #{error_message}")
allow(service).to receive(:execute_hooks)
service.execute(merge_request)
diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb
index ede79b87bcc..887ec17171e 100644
--- a/spec/services/merge_requests/merge_service_spec.rb
+++ b/spec/services/merge_requests/merge_service_spec.rb
@@ -239,7 +239,7 @@ describe MergeRequests::MergeService do
it 'logs and saves error if there is an PreReceiveError exception' do
error_message = 'error message'
- allow(service).to receive(:repository).and_raise(Gitlab::Git::PreReceiveError, error_message)
+ allow(service).to receive(:repository).and_raise(Gitlab::Git::PreReceiveError, "GitLab: #{error_message}")
allow(service).to receive(:execute_hooks)
service.execute(merge_request)
diff --git a/spec/services/tags/create_service_spec.rb b/spec/services/tags/create_service_spec.rb
index 0cbe57352be..e112cdc8881 100644
--- a/spec/services/tags/create_service_spec.rb
+++ b/spec/services/tags/create_service_spec.rb
@@ -41,7 +41,7 @@ describe Tags::CreateService do
it 'returns an error' do
expect(repository).to receive(:add_tag)
.with(user, 'v1.1.0', 'master', 'Foo')
- .and_raise(Gitlab::Git::PreReceiveError, 'something went wrong')
+ .and_raise(Gitlab::Git::PreReceiveError, 'GitLab: something went wrong')
response = service.execute('v1.1.0', 'master', 'Foo')
diff --git a/spec/support/api/milestones_shared_examples.rb b/spec/support/api/milestones_shared_examples.rb
index 5f709831ce1..63b719be03e 100644
--- a/spec/support/api/milestones_shared_examples.rb
+++ b/spec/support/api/milestones_shared_examples.rb
@@ -72,6 +72,15 @@ shared_examples_for 'group and project milestones' do |route_definition|
expect(json_response.first['id']).to eq closed_milestone.id
end
+ it 'returns a milestone by title' do
+ get api(route, user), params: { title: 'version2' }
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response.size).to eq(1)
+ expect(json_response.first['title']).to eq milestone.title
+ expect(json_response.first['id']).to eq milestone.id
+ end
+
it 'returns a milestone by searching for title' do
get api(route, user), params: { search: 'version2' }