summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md7
-rw-r--r--CONTRIBUTING.md45
-rw-r--r--app/assets/javascripts/boards/models/list.js1
-rw-r--r--app/assets/javascripts/clusters/clusters_bundle.js3
-rw-r--r--app/assets/javascripts/clusters/components/applications.vue19
-rw-r--r--app/assets/javascripts/clusters/stores/clusters_store.js6
-rw-r--r--app/assets/javascripts/diffs/components/commit_item.vue33
-rw-r--r--app/assets/javascripts/gl_form.js2
-rw-r--r--app/assets/javascripts/monitoring/components/charts/area.vue12
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue5
-rw-r--r--app/assets/javascripts/notes.js18
-rw-r--r--app/assets/javascripts/notes/components/comment_form.vue9
-rw-r--r--app/assets/javascripts/notes/components/note_form.vue7
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue4
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_url.vue34
-rw-r--r--app/assets/javascripts/releases/components/release_block.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/field.vue3
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/suggestions.vue3
-rw-r--r--app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_list.vue83
-rw-r--r--app/assets/stylesheets/framework/common.scss9
-rw-r--r--app/assets/stylesheets/framework/forms.scss9
-rw-r--r--app/assets/stylesheets/framework/modal.scss38
-rw-r--r--app/assets/stylesheets/framework/selects.scss18
-rw-r--r--app/assets/stylesheets/framework/tables.scss9
-rw-r--r--app/assets/stylesheets/framework/variables.scss1
-rw-r--r--app/assets/stylesheets/pages/issues.scss8
-rw-r--r--app/controllers/concerns/uploads_actions.rb6
-rw-r--r--app/controllers/projects/ci/lints_controller.rb8
-rw-r--r--app/controllers/projects/issues_controller.rb18
-rw-r--r--app/controllers/projects/settings/operations_controller.rb46
-rw-r--r--app/helpers/commits_helper.rb2
-rw-r--r--app/helpers/projects_helper.rb23
-rw-r--r--app/helpers/user_callouts_helper.rb4
-rw-r--r--app/mailers/emails/issues.rb11
-rw-r--r--app/mailers/previews/notify_preview.rb4
-rw-r--r--app/models/blob_viewer/gitlab_ci_yml.rb8
-rw-r--r--app/models/ci/build.rb52
-rw-r--r--app/models/ci/build_metadata.rb12
-rw-r--r--app/models/ci/pipeline.rb15
-rw-r--r--app/models/clusters/applications/knative.rb11
-rw-r--r--app/models/error_tracking/project_error_tracking_setting.rb14
-rw-r--r--app/models/merge_request.rb20
-rw-r--r--app/models/note.rb4
-rw-r--r--app/models/project.rb3
-rw-r--r--app/policies/project_policy.rb2
-rw-r--r--app/services/ci/retry_build_service.rb2
-rw-r--r--app/services/issues/import_csv_service.rb53
-rw-r--r--app/services/merge_requests/create_service.rb16
-rw-r--r--app/services/notes/quick_actions_service.rb2
-rw-r--r--app/services/projects/operations/update_service.rb19
-rw-r--r--app/services/quick_actions/interpret_service.rb41
-rw-r--r--app/services/upload_service.rb2
-rw-r--r--app/validators/url_validator.rb4
-rw-r--r--app/views/admin/users/_user.html.haml2
-rw-r--r--app/views/clusters/clusters/show.html.haml1
-rw-r--r--app/views/layouts/nav/sidebar/_project.html.haml5
-rw-r--r--app/views/notify/import_issues_csv_email.html.haml18
-rw-r--r--app/views/notify/import_issues_csv_email.text.erb11
-rw-r--r--app/views/projects/_issuable_by_email.html.haml7
-rw-r--r--app/views/projects/blob/viewers/_gitlab_ci_yml.html.haml4
-rw-r--r--app/views/projects/ci/lints/_create.html.haml9
-rw-r--r--app/views/projects/cleanup/_show.html.haml2
-rw-r--r--app/views/projects/issues/_import_export.svg1
-rw-r--r--app/views/projects/issues/_nav_btns.html.haml41
-rw-r--r--app/views/projects/issues/import_csv/_button.html.haml9
-rw-r--r--app/views/projects/issues/import_csv/_modal.html.haml24
-rw-r--r--app/views/projects/issues/index.html.haml5
-rw-r--r--app/views/projects/releases/index.html.haml2
-rw-r--r--app/views/projects/settings/operations/_error_tracking.html.haml30
-rw-r--r--app/views/projects/settings/operations/show.html.haml5
-rw-r--r--app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml2
-rw-r--r--app/views/shared/_flash_user_callout.html.haml11
-rw-r--r--app/views/shared/empty_states/_issues.html.haml13
-rw-r--r--app/views/shared/issuable/_feed_buttons.html.haml4
-rw-r--r--app/views/shared/issuable/_filter.html.haml32
-rw-r--r--app/views/shared/issuable/form/_merge_params.html.haml2
-rw-r--r--app/views/shared/members/_member.html.haml2
-rw-r--r--app/views/shared/notes/_comment_button.html.haml19
-rw-r--r--app/views/shared/notes/_edit.html.haml2
-rw-r--r--app/views/shared/notes/_edit_form.html.haml8
-rw-r--r--app/views/shared/notes/_form.html.haml6
-rw-r--r--app/views/shared/notes/_hints.html.haml12
-rw-r--r--app/views/shared/notes/_note.html.haml4
-rw-r--r--app/views/shared/notes/_notes_with_form.html.haml14
-rw-r--r--app/views/shared/snippets/_snippet.html.haml2
-rw-r--r--app/workers/all_queues.yml1
-rw-r--r--app/workers/import_issues_csv_worker.rb20
-rw-r--r--app/workers/update_head_pipeline_for_merge_request_worker.rb21
-rw-r--r--changelogs/unreleased/40473-api-support-for-kubernetes-integration.yml5
-rw-r--r--changelogs/unreleased/49231-import-issues-csv.yml5
-rw-r--r--changelogs/unreleased/52446-hide-ado-project-banner-for-ci-file-or-ci-disabled.yml5
-rw-r--r--changelogs/unreleased/53796-discard-draft-comment-button-to-easy-to-accidentally-hit-on-mobile.yml5
-rw-r--r--changelogs/unreleased/54142-pages-in-project-s-permission-should-be-named-pages-access-control.yml5
-rw-r--r--changelogs/unreleased/54311-fix-board-add-label.yml5
-rw-r--r--changelogs/unreleased/54981-extended-user-centric-tooltips-add-missing-cases.yml5
-rw-r--r--changelogs/unreleased/55192-about-link-in-new-window.yml5
-rw-r--r--changelogs/unreleased/55670-remove-app-views-shared-issuable-_filter-html-haml.yml5
-rw-r--r--changelogs/unreleased/55721-externalization-for-pipeline-tags.yml5
-rw-r--r--changelogs/unreleased/deprecated-migration-inheritance-2.yml5
-rw-r--r--changelogs/unreleased/gt-externalize-app-views-shared-notes.yml5
-rw-r--r--changelogs/unreleased/include-project.yml5
-rw-r--r--changelogs/unreleased/knative-rbac-check.yml5
-rw-r--r--changelogs/unreleased/sh-fix-clone-url-for-https.yml5
-rw-r--r--changelogs/unreleased/sh-fix-issue-55914.yml5
-rw-r--r--changelogs/unreleased/suggestion-dashes.yml5
-rw-r--r--changelogs/unreleased/user-update-head-pipeline-worker.yml5
-rw-r--r--config/initializers/ar_mysql_jsonb_support.rb31
-rw-r--r--config/routes/project.rb5
-rw-r--r--config/sidekiq_queues.yml1
-rw-r--r--db/fixtures/development/14_pipelines.rb5
-rw-r--r--db/migrate/20181119132520_add_indexes_to_ci_builds_and_pipelines.rb2
-rw-r--r--db/migrate/20181212171634_create_error_tracking_settings.rb17
-rw-r--r--db/migrate/20181219145521_add_options_to_build_metadata.rb15
-rw-r--r--db/schema.rb10
-rw-r--r--doc/api/README.md20
-rw-r--r--doc/api/access_requests.md16
-rw-r--r--doc/api/applications.md6
-rw-r--r--doc/api/award_emoji.md16
-rw-r--r--doc/api/boards.md14
-rw-r--r--doc/api/branches.md14
-rw-r--r--doc/api/broadcast_messages.md10
-rw-r--r--doc/api/commits.md24
-rw-r--r--doc/api/custom_attributes.md8
-rw-r--r--doc/api/deploy_key_multiple_projects.md8
-rw-r--r--doc/api/deploy_keys.md14
-rw-r--r--doc/api/deployments.md4
-rw-r--r--doc/api/discussions.md54
-rw-r--r--doc/api/environments.md10
-rw-r--r--doc/api/events.md6
-rw-r--r--doc/api/features.md4
-rw-r--r--doc/api/graphql/index.md2
-rw-r--r--doc/api/group_badges.md12
-rw-r--r--doc/api/group_boards.md14
-rw-r--r--doc/api/group_level_variables.md10
-rw-r--r--doc/api/group_milestones.md2
-rw-r--r--doc/api/groups.md6
-rw-r--r--doc/api/issues.md40
-rw-r--r--doc/api/jobs.md26
-rw-r--r--doc/api/labels.md12
-rw-r--r--doc/api/members.md24
-rw-r--r--doc/api/merge_requests.md26
-rw-r--r--doc/api/milestones.md2
-rw-r--r--doc/api/namespaces.md8
-rw-r--r--doc/api/notes.md28
-rw-r--r--doc/api/notification_settings.md12
-rw-r--r--doc/api/pages_domains.md18
-rw-r--r--doc/api/pipeline_triggers.md12
-rw-r--r--doc/api/pipelines.md12
-rw-r--r--doc/api/project_badges.md12
-rw-r--r--doc/api/project_import_export.md12
-rw-r--r--doc/api/project_level_variables.md10
-rw-r--r--doc/api/project_snippets.md2
-rw-r--r--doc/api/projects.md18
-rw-r--r--doc/api/protected_branches.md8
-rw-r--r--doc/api/protected_tags.md8
-rw-r--r--doc/api/releases.md2
-rw-r--r--doc/api/repositories.md4
-rw-r--r--doc/api/repository_files.md12
-rw-r--r--doc/api/repository_submodules.md2
-rw-r--r--doc/api/resource_label_events.md8
-rw-r--r--doc/api/runners.md18
-rw-r--r--doc/api/search.md34
-rw-r--r--doc/api/services.md2
-rw-r--r--doc/api/settings.md4
-rw-r--r--doc/api/sidekiq_metrics.md8
-rw-r--r--doc/api/snippets.md10
-rw-r--r--doc/api/suggestions.md2
-rw-r--r--doc/api/system_hooks.md8
-rw-r--r--doc/api/tags.md2
-rw-r--r--doc/api/templates/licenses.md2
-rw-r--r--doc/api/todos.md7
-rw-r--r--doc/api/users.md30
-rw-r--r--doc/api/version.md2
-rw-r--r--doc/api/wikis.md12
-rw-r--r--doc/ci/variables/README.md17
-rw-r--r--doc/ci/yaml/README.md30
-rw-r--r--doc/development/documentation/styleguide.md155
-rw-r--r--doc/development/migration_style_guide.md25
-rw-r--r--doc/install/kubernetes/gitlab_omnibus.md2
-rw-r--r--doc/topics/autodevops/index.md95
-rw-r--r--doc/university/glossary/README.md12
-rw-r--r--doc/university/high-availability/aws/README.md16
-rw-r--r--doc/user/project/import/repo_by_url.md2
-rw-r--r--doc/user/project/index.md15
-rw-r--r--doc/user/project/issues/csv_import.md45
-rw-r--r--doc/user/project/issues/img/import_csv_button.pngbin0 -> 4342 bytes
-rw-r--r--doc/user/project/issues/index.md9
-rw-r--r--doc/user/project/releases.md60
-rw-r--r--doc/user/project/releases/img/releases.png (renamed from doc/user/project/img/releases.png)bin126093 -> 126093 bytes
-rw-r--r--doc/user/project/releases/index.md59
-rw-r--r--doc/workflow/releases.md15
-rw-r--r--lib/api/api.rb2
-rw-r--r--lib/api/entities.rb33
-rw-r--r--lib/api/lint.rb3
-rw-r--r--lib/api/project_clusters.rb142
-rw-r--r--lib/api/projects.rb2
-rw-r--r--lib/api/release/links.rb117
-rw-r--r--lib/bitbucket_server/paginator.rb12
-rw-r--r--lib/gitlab/ci/build/step.rb1
-rw-r--r--lib/gitlab/ci/config.rb17
-rw-r--r--lib/gitlab/ci/config/entry/job.rb7
-rw-r--r--lib/gitlab/ci/config/external/file/base.rb2
-rw-r--r--lib/gitlab/ci/config/external/file/project.rb72
-rw-r--r--lib/gitlab/ci/config/external/mapper.rb8
-rw-r--r--lib/gitlab/ci/config/external/processor.rb4
-rw-r--r--lib/gitlab/ci/yaml_processor.rb3
-rw-r--r--lib/gitlab/email/attachment_uploader.rb4
-rw-r--r--lib/gitlab/import_export/import_export.yml5
-rw-r--r--lib/gitlab/import_export/relation_factory.rb2
-rw-r--r--lib/gitlab/import_export/uploads_manager.rb2
-rw-r--r--lib/gitlab/middleware/multipart.rb2
-rw-r--r--lib/gitlab/url_blocker.rb18
-rw-r--r--lib/gitlab/utils.rb10
-rw-r--r--lib/serializers/json.rb34
-rw-r--r--locale/gitlab.pot149
-rw-r--r--package.json2
-rw-r--r--qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb50
-rwxr-xr-xscripts/review_apps/review-apps.sh1
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb66
-rw-r--r--spec/controllers/projects/settings/operations_controller_spec.rb181
-rw-r--r--spec/db/schema_spec.rb7
-rw-r--r--spec/factories/ci/builds.rb56
-rw-r--r--spec/factories/clusters/clusters.rb4
-rw-r--r--spec/factories/clusters/platforms/kubernetes.rb4
-rw-r--r--spec/factories/project_error_tracking_settings.rb10
-rw-r--r--spec/features/boards/new_issue_spec.rb21
-rw-r--r--spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb2
-rw-r--r--spec/features/projects/clusters/applications_spec.rb28
-rw-r--r--spec/features/projects/environments/environments_spec.rb6
-rw-r--r--spec/features/projects/pipelines/pipeline_spec.rb2
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb15
-rw-r--r--spec/features/projects/settings/operations_settings_spec.rb39
-rw-r--r--spec/fixtures/api/schemas/release.json10
-rw-r--r--spec/fixtures/api/schemas/release/link.json11
-rw-r--r--spec/fixtures/api/schemas/release/links.json4
-rw-r--r--spec/fixtures/csv_comma.csv4
-rw-r--r--spec/fixtures/csv_semicolon.csv5
-rw-r--r--spec/fixtures/csv_tab.csv4
-rw-r--r--spec/fixtures/security-reports/master/gl-container-scanning-report.json94
-rw-r--r--spec/helpers/commits_helper_spec.rb2
-rw-r--r--spec/helpers/projects_helper_spec.rb99
-rw-r--r--spec/helpers/user_callouts_helper_spec.rb9
-rw-r--r--spec/javascripts/clusters/stores/clusters_store_spec.js1
-rw-r--r--spec/javascripts/diffs/components/commit_item_spec.js2
-rw-r--r--spec/javascripts/fixtures/jobs.rb3
-rw-r--r--spec/javascripts/ide/components/file_finder/index_spec.js1
-rw-r--r--spec/javascripts/notes/components/comment_form_spec.js1
-rw-r--r--spec/javascripts/releases/components/release_block_spec.js4
-rw-r--r--spec/javascripts/vue_shared/components/markdown/suggestions_spec.js4
-rw-r--r--spec/javascripts/vue_shared/components/user_avatar/user_avatar_list_spec.js130
-rw-r--r--spec/lib/bitbucket_server/paginator_spec.rb11
-rw-r--r--spec/lib/gitlab/background_migration/populate_external_pipeline_source_spec.rb5
-rw-r--r--spec/lib/gitlab/ci/build/step_spec.rb9
-rw-r--r--spec/lib/gitlab/ci/config/entry/global_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/job_spec.rb11
-rw-r--r--spec/lib/gitlab/ci/config/entry/jobs_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/file/base_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/file/local_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/file/project_spec.rb151
-rw-r--r--spec/lib/gitlab/ci/config/external/file/remote_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/mapper_spec.rb3
-rw-r--r--spec/lib/gitlab/ci/config/external/processor_spec.rb7
-rw-r--r--spec/lib/gitlab/ci/config_spec.rb10
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/build_spec.rb5
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb26
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml3
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml5
-rw-r--r--spec/lib/gitlab/middleware/multipart_spec.rb24
-rw-r--r--spec/lib/gitlab/utils_spec.rb16
-rw-r--r--spec/lib/serializers/json_spec.rb102
-rw-r--r--spec/mailers/emails/issues_spec.rb33
-rw-r--r--spec/migrations/delete_inconsistent_internal_id_records_spec.rb7
-rw-r--r--spec/models/blob_viewer/gitlab_ci_yml_spec.rb10
-rw-r--r--spec/models/ci/build_metadata_spec.rb4
-rw-r--r--spec/models/ci/build_spec.rb333
-rw-r--r--spec/models/clusters/applications/knative_spec.rb7
-rw-r--r--spec/models/error_tracking/project_error_tracking_setting_spec.rb36
-rw-r--r--spec/models/merge_request_spec.rb28
-rw-r--r--spec/models/note_spec.rb15
-rw-r--r--spec/models/project_spec.rb5
-rw-r--r--spec/requests/api/project_clusters_spec.rb450
-rw-r--r--spec/requests/api/release/links_spec.rb417
-rw-r--r--spec/requests/api/runner_spec.rb8
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb3
-rw-r--r--spec/services/ci/process_pipeline_service_spec.rb6
-rw-r--r--spec/services/ci/register_job_service_spec.rb7
-rw-r--r--spec/services/issues/import_csv_service_spec.rb64
-rw-r--r--spec/services/merge_requests/create_service_spec.rb29
-rw-r--r--spec/services/projects/operations/update_service_spec.rb86
-rw-r--r--spec/services/upload_service_spec.rb4
-rw-r--r--spec/validators/url_validator_spec.rb51
-rw-r--r--spec/views/projects/settings/operations/show.html.haml_spec.rb39
-rw-r--r--spec/workers/import_issues_csv_worker_spec.rb21
-rw-r--r--spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb10
-rw-r--r--yarn.lock21
295 files changed, 5078 insertions, 1154 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 56ac809b548..e86c818298b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,13 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 11.6.3 (2019-01-04)
+
+### Fixed (1 change)
+
+- Fix clone URL not showing if protocol is HTTPS. !24131
+
+
## 11.6.2 (2019-01-02)
### Fixed (7 changes)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 4304f6c8744..97dbe2f512b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -15,48 +15,6 @@ repository is licensed under Creative Commons:
_This notice should stay as the first item in the CONTRIBUTING.md file._
----
-
-<!-- START doctoc generated TOC please keep comment here to allow auto update -->
-<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
-**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
-
-- [Contributing Documentation has been moved](#contributing-documentation-has-been-moved)
-- [Contribute to GitLab](#contribute-to-gitlab)
-- [Security vulnerability disclosure](#security-vulnerability-disclosure)
-- [Code of conduct](#code-of-conduct)
-- [Closing policy for issues and merge requests](#closing-policy-for-issues-and-merge-requests)
-- [Helping others](#helping-others)
-- [I want to contribute!](#i-want-to-contribute)
-- [Contribution Flow](#contribution-flow)
-- [Workflow labels](#workflow-labels)
- - [Type labels](#type-labels)
- - [Subject labels](#subject-labels)
- - [Team labels](#team-labels)
- - [Release Scoping labels](#release-scoping-labels)
- - [Priority labels](#priority-labels)
- - [Severity labels](#severity-labels)
- - [Severity impact guidance](#severity-impact-guidance)
- - [Label for community contributors](#label-for-community-contributors)
-- [Implement design & UI elements](#implement-design--ui-elements)
-- [Issue tracker](#issue-tracker)
- - [Issue triaging](#issue-triaging)
- - [Feature proposals](#feature-proposals)
- - [Issue tracker guidelines](#issue-tracker-guidelines)
- - [Issue weight](#issue-weight)
- - [Regression issues](#regression-issues)
- - [Technical and UX debt](#technical-and-ux-debt)
- - [Stewardship](#stewardship)
-- [Merge requests](#merge-requests)
- - [Merge request guidelines](#merge-request-guidelines)
- - [Contribution acceptance criteria](#contribution-acceptance-criteria)
-- [Definition of done](#definition-of-done)
-- [Style guides](#style-guides)
-
-<!-- END doctoc generated TOC please keep comment here to allow auto update -->
-
----
-
## Contributing Documentation has been moved
As of July 2018, all the documentation for contributing to the GitLab project has been moved to a new location.
@@ -92,7 +50,7 @@ This [documentation](doc/development/contributing/index.md) has been moved.
## Workflow labels
-This [documentation](doc/development/contributing/issue_workflow.md) has been moved.
+This [documentation](doc/development/contributing/issue_workflow.md) has been moved.
### Type labels
@@ -170,7 +128,6 @@ This [documentation](doc/development/contributing/merge_request_workflow.md) has
This [documentation](doc/development/contributing/merge_request_workflow.md) has been moved.
-
### Contribution acceptance criteria
This [documentation](doc/development/contributing/merge_request_workflow.md) has been moved.
diff --git a/app/assets/javascripts/boards/models/list.js b/app/assets/javascripts/boards/models/list.js
index dd3feedbc0e..9f6d9a853da 100644
--- a/app/assets/javascripts/boards/models/list.js
+++ b/app/assets/javascripts/boards/models/list.js
@@ -244,6 +244,7 @@ class List {
issue.project = data.project;
issue.path = data.real_path;
issue.referencePath = data.reference_path;
+ issue.assignableLabelsEndpoint = data.assignable_labels_endpoint;
if (this.issuesSize > 1) {
const moveBeforeId = this.issues[1].id;
diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js
index aff32d95db1..b1f992c03ff 100644
--- a/app/assets/javascripts/clusters/clusters_bundle.js
+++ b/app/assets/javascripts/clusters/clusters_bundle.js
@@ -32,6 +32,7 @@ export default class Clusters {
installKnativePath,
installPrometheusPath,
managePrometheusPath,
+ hasRbac,
clusterType,
clusterStatus,
clusterStatusReason,
@@ -45,6 +46,7 @@ export default class Clusters {
this.store.setManagePrometheusPath(managePrometheusPath);
this.store.updateStatus(clusterStatus);
this.store.updateStatusReason(clusterStatusReason);
+ this.store.updateRbac(hasRbac);
this.service = new ClustersService({
endpoint: statusPath,
installHelmEndpoint: installHelmPath,
@@ -102,6 +104,7 @@ export default class Clusters {
ingressHelpPath: this.state.ingressHelpPath,
managePrometheusPath: this.state.managePrometheusPath,
ingressDnsHelpPath: this.state.ingressDnsHelpPath,
+ rbac: this.state.rbac,
},
});
},
diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue
index 489615f1f78..5d19c79570a 100644
--- a/app/assets/javascripts/clusters/components/applications.vue
+++ b/app/assets/javascripts/clusters/components/applications.vue
@@ -52,6 +52,11 @@ export default {
required: false,
default: '',
},
+ rbac: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data: () => ({
elasticsearchLogo,
@@ -442,6 +447,18 @@ export default {
title-link="https://github.com/knative/docs"
>
<div slot="description">
+ <span v-if="!rbac">
+ <p v-if="!rbac" class="bs-callout bs-callout-info append-bottom-0">
+ {{
+ s__(`ClusterIntegration|You must have an RBAC-enabled cluster
+ to install Knative.`)
+ }}
+ <a :href="helpPath" target="_blank" rel="noopener noreferrer">
+ {{ __('More information') }}
+ </a>
+ </p>
+ <br />
+ </span>
<p>
{{
s__(`ClusterIntegration|Knative extends Kubernetes to provide
@@ -465,7 +482,7 @@ export default {
/>
</div>
</template>
- <template v-else-if="helmInstalled">
+ <template v-else-if="helmInstalled && rbac">
<div class="form-group">
<label for="knative-domainname">
{{ s__('ClusterIntegration|Knative Domain Name:') }}
diff --git a/app/assets/javascripts/clusters/stores/clusters_store.js b/app/assets/javascripts/clusters/stores/clusters_store.js
index c750daab112..8f74be4e0e6 100644
--- a/app/assets/javascripts/clusters/stores/clusters_store.js
+++ b/app/assets/javascripts/clusters/stores/clusters_store.js
@@ -1,4 +1,5 @@
import { s__ } from '../../locale';
+import { parseBoolean } from '../../lib/utils/common_utils';
import { INGRESS, JUPYTER, KNATIVE, CERT_MANAGER } from '../constants';
export default class ClusterStore {
@@ -7,6 +8,7 @@ export default class ClusterStore {
helpPath: null,
ingressHelpPath: null,
status: null,
+ rbac: false,
statusReason: null,
applications: {
helm: {
@@ -81,6 +83,10 @@ export default class ClusterStore {
this.state.status = status;
}
+ updateRbac(rbac) {
+ this.state.rbac = parseBoolean(rbac);
+ }
+
updateStatusReason(reason) {
this.state.statusReason = reason;
}
diff --git a/app/assets/javascripts/diffs/components/commit_item.vue b/app/assets/javascripts/diffs/components/commit_item.vue
index ebc4a83af4d..c02a8740a42 100644
--- a/app/assets/javascripts/diffs/components/commit_item.vue
+++ b/app/assets/javascripts/diffs/components/commit_item.vue
@@ -5,6 +5,7 @@ import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import CIIcon from '~/vue_shared/components/ci_icon.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import CommitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue';
+import initUserPopovers from '../../user_popovers';
/**
* CommitItem
@@ -35,20 +36,30 @@ export default {
},
},
computed: {
+ author() {
+ return this.commit.author || {};
+ },
authorName() {
- return (this.commit.author && this.commit.author.name) || this.commit.author_name;
+ return this.author.name || this.commit.author_name;
+ },
+ authorClass() {
+ return this.author.name ? 'js-user-link' : '';
+ },
+ authorId() {
+ return this.author.id ? this.author.id : '';
},
authorUrl() {
- return (
- (this.commit.author && this.commit.author.web_url) || `mailto:${this.commit.author_email}`
- );
+ return this.author.web_url || `mailto:${this.commit.author_email}`;
},
authorAvatar() {
- return (
- (this.commit.author && this.commit.author.avatar_url) || this.commit.author_gravatar_url
- );
+ return this.author.avatar_url || this.commit.author_gravatar_url;
},
},
+ created() {
+ this.$nextTick(() => {
+ initUserPopovers(this.$el.querySelectorAll('.js-user-link'));
+ });
+ },
};
</script>
@@ -81,7 +92,13 @@ export default {
</button>
<div class="commiter">
- <a :href="authorUrl" v-text="authorName"></a> {{ s__('CommitWidget|authored') }}
+ <a
+ :href="authorUrl"
+ :class="authorClass"
+ :data-user-id="authorId"
+ v-text="authorName"
+ ></a>
+ {{ s__('CommitWidget|authored') }}
<time-ago-tooltip :time="commit.authored_date" />
</div>
diff --git a/app/assets/javascripts/gl_form.js b/app/assets/javascripts/gl_form.js
index f842d2d74db..f5e2e46237f 100644
--- a/app/assets/javascripts/gl_form.js
+++ b/app/assets/javascripts/gl_form.js
@@ -51,8 +51,6 @@ export default class GLForm {
// form and textarea event listeners
this.addEventListeners();
addMarkdownListeners(this.form);
- // hide discard button
- this.form.find('.js-note-discard').hide();
this.form.show();
if (this.isAutosizeable) this.setupAutosize();
}
diff --git a/app/assets/javascripts/monitoring/components/charts/area.vue b/app/assets/javascripts/monitoring/components/charts/area.vue
index 12224e36ba2..e2cffe0b4b4 100644
--- a/app/assets/javascripts/monitoring/components/charts/area.vue
+++ b/app/assets/javascripts/monitoring/components/charts/area.vue
@@ -6,6 +6,7 @@ export default {
components: {
GlAreaChart,
},
+ inheritAttrs: false,
props: {
graphData: {
type: Object,
@@ -25,6 +26,11 @@ export default {
);
},
},
+ alertData: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
},
computed: {
chartData() {
@@ -74,9 +80,6 @@ export default {
const [date, value] = params;
return [dateFormat(date, 'dd mmm yyyy, h:MMtt'), value.toFixed(3)];
},
- onCreated(chart) {
- this.$emit('created', chart);
- },
},
};
</script>
@@ -88,10 +91,11 @@ export default {
<div class="prometheus-graph-widgets"><slot></slot></div>
</div>
<gl-area-chart
+ v-bind="$attrs"
:data="chartData"
:option="chartOptions"
:format-tooltip-text="formatTooltipText"
- @created="onCreated"
+ :thresholds="alertData"
/>
</div>
</template>
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index 2d9c5050c9b..cea5c1a56ca 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -144,6 +144,9 @@ export default {
}
},
methods: {
+ getGraphAlerts(graphId) {
+ return this.alertData ? this.alertData[graphId] || {} : {};
+ },
getGraphsData() {
this.state = 'loading';
Promise.all([
@@ -223,6 +226,8 @@ export default {
:tags-path="tagsPath"
:show-legend="showLegend"
:small-graph="forceSmallGraph"
+ :alert-data="getGraphAlerts(graphData.id)"
+ group-id="monitor-area-chart"
>
<!-- EE content -->
{{ null }}
diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js
index dfb53c986fc..c3443c300e3 100644
--- a/app/assets/javascripts/notes.js
+++ b/app/assets/javascripts/notes.js
@@ -138,8 +138,6 @@ export default class Notes {
this.$wrapperEl.on('click', '.js-note-delete', this.removeNote);
// delete note attachment
this.$wrapperEl.on('click', '.js-note-attachment-delete', this.removeAttachment);
- // reset main target form when clicking discard
- this.$wrapperEl.on('click', '.js-note-discard', this.resetMainTargetForm);
// update the file name when an attachment is selected
this.$wrapperEl.on('change', '.js-note-attachment-input', this.updateFormAttachment);
// reply to diff/discussion notes
@@ -191,7 +189,6 @@ export default class Notes {
this.$wrapperEl.off('keyup input', '.js-note-text');
this.$wrapperEl.off('click', '.js-note-target-reopen');
this.$wrapperEl.off('click', '.js-note-target-close');
- this.$wrapperEl.off('click', '.js-note-discard');
this.$wrapperEl.off('keydown', '.js-note-text');
this.$wrapperEl.off('click', '.js-comment-resolve-button');
this.$wrapperEl.off('click', '.system-note-commit-list-toggler');
@@ -986,11 +983,9 @@ export default class Notes {
form.find('#note_position').val(dataHolder.attr('data-position'));
form
- .find('.js-note-discard')
+ .find('.js-close-discussion-note-form')
.show()
- .removeClass('js-note-discard')
- .addClass('js-close-discussion-note-form')
- .text(form.find('.js-close-discussion-note-form').data('cancelText'));
+ .removeClass('hide');
form.find('.js-note-target-close').remove();
form.find('.js-note-new-discussion').remove();
this.setupNoteForm(form);
@@ -1194,12 +1189,11 @@ export default class Notes {
}
updateTargetButtons(e) {
- var closebtn, closetext, discardbtn, form, reopenbtn, reopentext, textarea;
+ var closebtn, closetext, form, reopenbtn, reopentext, textarea;
textarea = $(e.target);
form = textarea.parents('form');
reopenbtn = form.find('.js-note-target-reopen');
closebtn = form.find('.js-note-target-close');
- discardbtn = form.find('.js-note-discard');
if (textarea.val().trim().length > 0) {
reopentext = reopenbtn.attr('data-alternative-text');
@@ -1216,9 +1210,6 @@ export default class Notes {
if (closebtn.is(':not(.btn-comment-and-close)')) {
closebtn.addClass('btn-comment-and-close');
}
- if (discardbtn.is(':hidden')) {
- return discardbtn.show();
- }
} else {
reopentext = reopenbtn.data('originalText');
closetext = closebtn.data('originalText');
@@ -1234,9 +1225,6 @@ export default class Notes {
if (closebtn.is('.btn-comment-and-close')) {
closebtn.removeClass('btn-comment-and-close');
}
- if (discardbtn.is(':visible')) {
- return discardbtn.hide();
- }
}
}
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue
index ce56beb1e6b..8bf02327cd2 100644
--- a/app/assets/javascripts/notes/components/comment_form.vue
+++ b/app/assets/javascripts/notes/components/comment_form.vue
@@ -431,15 +431,6 @@ append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown"
:label="issueActionButtonTitle"
@click="handleSave(true);"
/>
-
- <button
- v-if="note.length"
- type="button"
- class="btn btn-cancel js-note-discard"
- @click="discard"
- >
- Discard draft
- </button>
</div>
</form>
</div>
diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue
index e78596f8b52..db62ddb3ecd 100644
--- a/app/assets/javascripts/notes/components/note_form.vue
+++ b/app/assets/javascripts/notes/components/note_form.vue
@@ -149,6 +149,9 @@ export default {
return shouldResolve || shouldToggleState;
},
+ handleKeySubmit() {
+ this.handleUpdate();
+ },
handleUpdate(shouldResolve) {
const beforeSubmitDiscussionState = this.discussionResolved;
this.isSubmitting = true;
@@ -216,8 +219,8 @@ export default {
class="note-textarea js-gfm-input js-note-text js-autosize markdown-area js-vue-issue-note-form js-vue-textarea qa-reply-input"
aria-label="Description"
placeholder="Write a comment or drag your files here…"
- @keydown.meta.enter="handleUpdate();"
- @keydown.ctrl.enter="handleUpdate();"
+ @keydown.meta.enter="handleKeySubmit();"
+ @keydown.ctrl.enter="handleKeySubmit();"
@keydown.up="editMyLastNote();"
@keydown.esc="cancelHandler(true);"
></textarea>
diff --git a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
index 08c7719dcf2..19d9903c988 100644
--- a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
+++ b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
@@ -325,8 +325,8 @@ export default {
<project-setting-row
v-if="pagesAvailable && pagesAccessControlEnabled"
:help-path="pagesHelpPath"
- label="Pages"
- help-text="Static website for the project."
+ label="Pages access control"
+ help-text="Access control for the project's static website"
>
<project-feature-setting
v-model="pagesAccessLevel"
diff --git a/app/assets/javascripts/pipelines/components/pipeline_url.vue b/app/assets/javascripts/pipelines/components/pipeline_url.vue
index 7d8863dff29..918622ef8dc 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_url.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_url.vue
@@ -1,8 +1,20 @@
<script>
import { GlLink, GlTooltipDirective } from '@gitlab/ui';
+import _ from 'underscore';
+import { __, sprintf } from '~/locale';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import popover from '~/vue_shared/directives/popover';
+const popoverTitle = sprintf(
+ _.escape(
+ __(
+ `This pipeline makes use of a predefined CI/CD configuration enabled by %{strongStart}Auto DevOps.%{strongEnd}`,
+ ),
+ ),
+ { strongStart: '<b>', strongEnd: '</b>' },
+ false,
+);
+
export default {
components: {
UserAvatarLink,
@@ -32,14 +44,14 @@ export default {
trigger: 'focus',
placement: 'top',
title: `<div class="autodevops-title">
- This pipeline makes use of a predefined CI/CD configuration enabled by <b>Auto DevOps.</b>
+ ${popoverTitle}
</div>`,
content: `<a
class="autodevops-link"
href="${this.autoDevopsHelpPath}"
target="_blank"
rel="noopener noreferrer nofollow">
- Learn more about Auto DevOps
+ ${_.escape(__('Learn more about Auto DevOps'))}
</a>`,
};
},
@@ -54,9 +66,9 @@ export default {
<span>by</span>
<user-avatar-link
v-if="user"
- :link-href="pipeline.user.path"
- :img-src="pipeline.user.avatar_url"
- :tooltip-text="pipeline.user.name"
+ :link-href="user.path"
+ :img-src="user.avatar_url"
+ :tooltip-text="user.name"
class="js-pipeline-url-user"
/>
<span v-if="!user" class="js-pipeline-url-api api"> API </span>
@@ -64,10 +76,10 @@ export default {
<span
v-if="pipeline.flags.latest"
v-gl-tooltip
- class="js-pipeline-url-latest badge badge-success"
:title="__('Latest pipeline for this branch')"
+ class="js-pipeline-url-latest badge badge-success"
>
- latest
+ {{ __('latest') }}
</span>
<span
v-if="pipeline.flags.yaml_errors"
@@ -75,7 +87,7 @@ export default {
:title="pipeline.yaml_errors"
class="js-pipeline-url-yaml badge badge-danger"
>
- yaml invalid
+ {{ __('yaml invalid') }}
</span>
<span
v-if="pipeline.flags.failure_reason"
@@ -83,7 +95,7 @@ export default {
:title="pipeline.failure_reason"
class="js-pipeline-url-failure badge badge-danger"
>
- error
+ {{ __('error') }}
</span>
<gl-link
v-if="pipeline.flags.auto_devops"
@@ -95,7 +107,7 @@ export default {
Auto DevOps
</gl-link>
<span v-if="pipeline.flags.stuck" class="js-pipeline-url-stuck badge badge-warning">
- stuck
+ {{ __('stuck') }}
</span>
<span
v-if="pipeline.flags.merge_request"
@@ -103,7 +115,7 @@ export default {
:title="__('This pipeline is run in a merge request context')"
class="js-pipeline-url-mergerequest badge badge-info"
>
- merge request
+ {{ __('merge request') }}
</span>
</div>
</div>
diff --git a/app/assets/javascripts/releases/components/release_block.vue b/app/assets/javascripts/releases/components/release_block.vue
index 34b97826cdb..4295fef8f0a 100644
--- a/app/assets/javascripts/releases/components/release_block.vue
+++ b/app/assets/javascripts/releases/components/release_block.vue
@@ -45,7 +45,7 @@ export default {
return this.release.author || {};
},
hasAuthor() {
- return _.isEmpty(this.author);
+ return !_.isEmpty(this.author);
},
},
};
diff --git a/app/assets/javascripts/vue_shared/components/markdown/field.vue b/app/assets/javascripts/vue_shared/components/markdown/field.vue
index 2f7ed4a982c..937a2847a58 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/field.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/field.vue
@@ -89,7 +89,6 @@ export default {
return this.referencedUsers.length >= referencedUsersThreshold;
},
lineContent() {
- const FIRST_CHAR_REGEX = /^(\+|-)/;
const [firstSuggestion] = this.suggestions;
if (firstSuggestion) {
return firstSuggestion.from_content;
@@ -99,7 +98,7 @@ export default {
const { rich_text: richText, text } = this.line;
if (text) {
- return text.replace(FIRST_CHAR_REGEX, '');
+ return text;
}
return _.unescape(stripHtml(richText).replace(/\n/g, ''));
diff --git a/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue b/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue
index 7c6dbee3e19..721f0276ac8 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue
@@ -82,13 +82,12 @@ export default {
// extracts the suggested lines from the markdown
// calculates a line number for each line
- const FIRST_CHAR_REGEX = /^(\+|-)/;
const newLines = suggestionEl.querySelectorAll('.line');
const fromLine = this.suggestions.length ? this.suggestions[0].from_line : this.fromLine;
const lines = [];
newLines.forEach((line, i) => {
- const content = `${line.innerText.replace(FIRST_CHAR_REGEX, '')}\n`;
+ const content = `${line.innerText}\n`;
const lineNumber = fromLine + i;
lines.push({ content, lineNumber });
});
diff --git a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_list.vue b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_list.vue
new file mode 100644
index 00000000000..7361867edc5
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_list.vue
@@ -0,0 +1,83 @@
+<script>
+import { GlButton } from '@gitlab/ui';
+import { sprintf, __ } from '~/locale';
+import UserAvatarLink from './user_avatar_link.vue';
+
+export default {
+ components: {
+ UserAvatarLink,
+ GlButton,
+ },
+ props: {
+ items: {
+ type: Array,
+ required: true,
+ },
+ breakpoint: {
+ type: Number,
+ required: false,
+ default: 10,
+ },
+ imgSize: {
+ type: Number,
+ required: false,
+ default: 20,
+ },
+ },
+ data() {
+ return {
+ isExpanded: false,
+ };
+ },
+ computed: {
+ visibleItems() {
+ if (!this.hasHiddenItems) {
+ return this.items;
+ }
+
+ return this.items.slice(0, this.breakpoint);
+ },
+ hasHiddenItems() {
+ return this.hasBreakpoint && !this.isExpanded && this.items.length > this.breakpoint;
+ },
+ hasBreakpoint() {
+ return this.breakpoint > 0 && this.items.length > this.breakpoint;
+ },
+ expandText() {
+ if (!this.hasHiddenItems) {
+ return '';
+ }
+
+ const count = this.items.length - this.breakpoint;
+
+ return sprintf(__('%{count} more'), { count });
+ },
+ },
+ methods: {
+ expand() {
+ this.isExpanded = true;
+ },
+ collapse() {
+ this.isExpanded = false;
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <user-avatar-link
+ v-for="item in visibleItems"
+ :key="item.id"
+ :link-href="item.web_url"
+ :img-src="item.avatar_url"
+ :img-alt="item.name"
+ :tooltip-text="item.name"
+ :img-size="imgSize"
+ />
+ <template v-if="hasBreakpoint">
+ <gl-button v-if="hasHiddenItems" variant="link" @click="expand"> {{ expandText }} </gl-button>
+ <gl-button v-else variant="link" @click="collapse"> {{ __('show less') }} </gl-button>
+ </template>
+ </div>
+</template>
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index e037b02a30c..a499a3a9f95 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -384,10 +384,17 @@ img.emoji {
.flex-align-self-center { align-self: center; }
.flex-grow { flex-grow: 1; }
.flex-no-shrink { flex-shrink: 0; }
-.mw-460 { max-width: 460px; }
.ws-initial { white-space: initial; }
+.overflow-auto { overflow: auto; }
+
+/** COMMON SIZING CLASSES **/
+.w-0 { width: 0; }
+.h-13em { height: 13em; }
+.mw-460 { max-width: 460px; }
+.mw-6em { max-width: 6em; }
.min-height-0 { min-height: 0; }
+/** COMMON SPACING CLASSES **/
.gl-pl-0 { padding-left: 0; }
.gl-pl-1 { padding-left: #{0.5 * $grid-size}; }
.gl-pl-2 { padding-left: $grid-size; }
diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss
index 4da2243981e..0a0ef2071e9 100644
--- a/app/assets/stylesheets/framework/forms.scss
+++ b/app/assets/stylesheets/framework/forms.scss
@@ -36,6 +36,15 @@ label {
}
}
+.label-wrapper {
+ display: block;
+ margin: 0;
+}
+
+.form-label {
+ @extend label;
+}
+
.form-control-label {
@extend .col-md-2;
}
diff --git a/app/assets/stylesheets/framework/modal.scss b/app/assets/stylesheets/framework/modal.scss
index 46d40ea7aa5..ace46e32b18 100644
--- a/app/assets/stylesheets/framework/modal.scss
+++ b/app/assets/stylesheets/framework/modal.scss
@@ -101,3 +101,41 @@ body.modal-open {
margin: 0;
}
}
+
+.issues-import-modal,
+.issues-export-modal {
+ .modal-header {
+ justify-content: flex-start;
+
+ .import-export-svg-container {
+ flex-grow: 1;
+ height: 56px;
+ padding: $gl-btn-padding $gl-btn-padding 0;
+
+ > svg {
+ float: right;
+ height: 100%;
+ }
+ }
+ }
+
+ .modal-body {
+ padding: 0;
+
+ .modal-subheader {
+ justify-content: flex-start;
+ align-items: center;
+ border-bottom: 1px solid $modal-border-color;
+ padding: 14px;
+ }
+
+ .modal-text {
+ padding: $gl-padding-24 $gl-padding;
+ min-height: $modal-body-height;
+ }
+ }
+
+ .checkmark {
+ color: $green-400;
+ }
+}
diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss
index a68f1e4e570..bcd601e198a 100644
--- a/app/assets/stylesheets/framework/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -57,6 +57,16 @@
color: $gl-text-color;
}
}
+
+ &.is-invalid {
+ ~ .invalid-feedback {
+ display: block;
+ }
+
+ .select2-choices {
+ border-color: $red-500;
+ }
+ }
}
.select2-drop,
@@ -67,10 +77,18 @@
min-width: 175px;
color: $gl-text-color;
z-index: 999;
+
+ .modal-open & {
+ z-index: $zindex-modal + 200;
+ }
}
.select2-drop-mask {
z-index: 998;
+
+ .modal-open & {
+ z-index: $zindex-modal + 100;
+ }
}
.select2-drop.select2-drop-above.select2-drop-active {
diff --git a/app/assets/stylesheets/framework/tables.scss b/app/assets/stylesheets/framework/tables.scss
index 6954e6599b1..295a5b5ee7a 100644
--- a/app/assets/stylesheets/framework/tables.scss
+++ b/app/assets/stylesheets/framework/tables.scss
@@ -50,6 +50,14 @@ table {
border-color: $white-normal;
}
}
+
+ .thead-white {
+ th {
+ background-color: $white-light;
+ color: $gl-text-color-secondary;
+ border-top: 0;
+ }
+ }
}
&.responsive-table {
@@ -153,3 +161,4 @@ table {
border-top: 0;
}
}
+
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index d92d81b2cb5..242977e8543 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -656,6 +656,7 @@ $border-color-settings: #e1e1e1;
Modals
*/
$modal-body-height: 134px;
+$modal-border-color: #e9ecef;
$priority-label-empty-state-width: 114px;
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index bb6b6f84849..6c847fc0d53 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -155,6 +155,14 @@ ul.related-merge-requests > li {
}
}
+.issues-nav-controls {
+ font-size: 0;
+
+ .btn-group:empty {
+ display: none;
+ }
+}
+
.issuable-email-modal-btn {
padding: 0;
color: $blue-600;
diff --git a/app/controllers/concerns/uploads_actions.rb b/app/controllers/concerns/uploads_actions.rb
index 0eea0cdd50f..c114e16edf8 100644
--- a/app/controllers/concerns/uploads_actions.rb
+++ b/app/controllers/concerns/uploads_actions.rb
@@ -7,12 +7,12 @@ module UploadsActions
UPLOAD_MOUNTS = %w(avatar attachment file logo header_logo favicon).freeze
def create
- link_to_file = UploadService.new(model, params[:file], uploader_class).execute
+ uploader = UploadService.new(model, params[:file], uploader_class).execute
respond_to do |format|
- if link_to_file
+ if uploader
format.json do
- render json: { link: link_to_file }
+ render json: { link: uploader.to_h }
end
else
format.json do
diff --git a/app/controllers/projects/ci/lints_controller.rb b/app/controllers/projects/ci/lints_controller.rb
index 2090af0a111..d7a0b7ece14 100644
--- a/app/controllers/projects/ci/lints_controller.rb
+++ b/app/controllers/projects/ci/lints_controller.rb
@@ -8,7 +8,7 @@ class Projects::Ci::LintsController < Projects::ApplicationController
def create
@content = params[:content]
- @error = Gitlab::Ci::YamlProcessor.validation_message(@content, yaml_processor_options)
+ @error = Gitlab::Ci::YamlProcessor.validation_message(@content, yaml_processor_options)
@status = @error.blank?
if @error.blank?
@@ -24,6 +24,10 @@ class Projects::Ci::LintsController < Projects::ApplicationController
private
def yaml_processor_options
- { project: @project, sha: project.repository.commit.sha }
+ {
+ project: @project,
+ user: current_user,
+ sha: project.repository.commit.sha
+ }
end
end
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 5ed46fc0545..21688e54481 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -10,7 +10,7 @@ class Projects::IssuesController < Projects::ApplicationController
include SpammableActions
def self.issue_except_actions
- %i[index calendar new create bulk_update]
+ %i[index calendar new create bulk_update import_csv]
end
def self.set_issuables_index_only_actions
@@ -37,6 +37,8 @@ class Projects::IssuesController < Projects::ApplicationController
# Allow create a new branch and empty WIP merge request from current issue
before_action :authorize_create_merge_request_from!, only: [:create_merge_request]
+ before_action :authorize_import_issues!, only: [:import_csv]
+
before_action :set_suggested_issues_feature_flags, only: [:new]
respond_to :html
@@ -175,6 +177,20 @@ class Projects::IssuesController < Projects::ApplicationController
end
end
+ def import_csv
+ return render_404 unless Feature.enabled?(:issues_import_csv)
+
+ if uploader = UploadService.new(project, params[:file]).execute
+ ImportIssuesCsvWorker.perform_async(current_user.id, project.id, uploader.upload.id)
+
+ flash[:notice] = _("Your issues are being imported. Once finished, you'll get a confirmation email.")
+ else
+ flash[:alert] = _("File upload error.")
+ end
+
+ redirect_to project_issues_path(project)
+ end
+
protected
# rubocop: disable CodeReuse/ActiveRecord
diff --git a/app/controllers/projects/settings/operations_controller.rb b/app/controllers/projects/settings/operations_controller.rb
new file mode 100644
index 00000000000..521ec2acebb
--- /dev/null
+++ b/app/controllers/projects/settings/operations_controller.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module Projects
+ module Settings
+ class OperationsController < Projects::ApplicationController
+ before_action :check_license
+ before_action :authorize_update_environment!
+
+ helper_method :error_tracking_setting
+
+ def show
+ end
+
+ def update
+ result = ::Projects::Operations::UpdateService.new(project, current_user, update_params).execute
+
+ if result[:status] == :success
+ flash[:notice] = _('Your changes have been saved')
+ redirect_to project_settings_operations_path(@project)
+ else
+ render 'show'
+ end
+ end
+
+ private
+
+ def error_tracking_setting
+ @error_tracking_setting ||= project.error_tracking_setting ||
+ project.build_error_tracking_setting
+ end
+
+ def update_params
+ params.require(:project).permit(permitted_project_params)
+ end
+
+ # overridden in EE
+ def permitted_project_params
+ { error_tracking_setting_attributes: [:enabled, :api_url, :token] }
+ end
+
+ def check_license
+ render_404 unless helpers.settings_operations_available?
+ end
+ end
+ end
+end
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index d52cfd6e37a..d58f634425b 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -154,7 +154,7 @@ module CommitsHelper
if user.nil?
mail_to(source_email, text, link_options)
else
- link_to(text, user_path(user), link_options)
+ link_to(text, user_path(user), { class: "commit-#{options[:source]}-link js-user-link", data: { user_id: user.id } })
end
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 0cfc2db3285..e67c327f7f8 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -204,12 +204,10 @@ module ProjectsHelper
current_user.require_extra_setup_for_git_auth?
end
- def show_auto_devops_implicitly_enabled_banner?(project)
- cookie_key = "hide_auto_devops_implicitly_enabled_banner_#{project.id}"
+ def show_auto_devops_implicitly_enabled_banner?(project, user)
+ return false unless user_can_see_auto_devops_implicitly_enabled_banner?(project, user)
- project.has_auto_devops_implicitly_enabled? &&
- cookies[cookie_key.to_sym].blank? &&
- (project.owner == current_user || project.team.maintainer?(current_user))
+ cookies["hide_auto_devops_implicitly_enabled_banner_#{project.id}".to_sym].blank?
end
def link_to_set_password
@@ -285,6 +283,11 @@ module ProjectsHelper
!disabled && !compact_mode && Feature.enabled?(:project_list_show_issue_count, default_enabled: true)
end
+ # overridden in EE
+ def settings_operations_available?
+ Feature.enabled?(:error_tracking, @project) && can?(current_user, :read_environment, @project)
+ end
+
private
def get_project_nav_tabs(project, current_user)
@@ -485,7 +488,7 @@ module ProjectsHelper
lfsHelpPath: help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs'),
pagesAvailable: Gitlab.config.pages.enabled,
pagesAccessControlEnabled: Gitlab.config.pages.access_control,
- pagesHelpPath: help_page_path('user/project/pages/index.md')
+ pagesHelpPath: help_page_path('user/project/pages/introduction', anchor: 'gitlab-pages-access-control-core-only')
}
end
@@ -546,6 +549,7 @@ module ProjectsHelper
services#edit
repository#show
ci_cd#show
+ operations#show
badges#index
pages#show
]
@@ -579,4 +583,11 @@ module ProjectsHelper
gcp
]
end
+
+ def user_can_see_auto_devops_implicitly_enabled_banner?(project, user)
+ Ability.allowed?(user, :admin_project, project) &&
+ project.has_auto_devops_implicitly_enabled? &&
+ project.builds_enabled? &&
+ !project.repository.gitlab_ci_yml
+ end
end
diff --git a/app/helpers/user_callouts_helper.rb b/app/helpers/user_callouts_helper.rb
index 4aba48061ba..1ad7bb81784 100644
--- a/app/helpers/user_callouts_helper.rb
+++ b/app/helpers/user_callouts_helper.rb
@@ -13,6 +13,10 @@ module UserCalloutsHelper
!user_dismissed?(GCP_SIGNUP_OFFER)
end
+ def render_flash_user_callout(flash_type, message, feature_name)
+ render 'shared/flash_user_callout', flash_type: flash_type, message: message, feature_name: feature_name
+ end
+
private
def user_dismissed?(feature_name)
diff --git a/app/mailers/emails/issues.rb b/app/mailers/emails/issues.rb
index 370e6d2f90b..654ae211310 100644
--- a/app/mailers/emails/issues.rb
+++ b/app/mailers/emails/issues.rb
@@ -77,6 +77,17 @@ module Emails
mail_answer_thread(issue, issue_thread_options(updated_by_user.id, recipient.id, reason))
end
+ def import_issues_csv_email(user_id, project_id, results)
+ @user = User.find(user_id)
+ @project = Project.find(project_id)
+ @results = results
+
+ mail(to: @user.notification_email, subject: subject('Imported issues')) do |format|
+ format.html { render layout: 'mailer' }
+ format.text { render layout: 'mailer' }
+ end
+ end
+
private
def setup_issue_mail(issue_id, recipient_id)
diff --git a/app/mailers/previews/notify_preview.rb b/app/mailers/previews/notify_preview.rb
index 2ac4610967d..80e0a17c312 100644
--- a/app/mailers/previews/notify_preview.rb
+++ b/app/mailers/previews/notify_preview.rb
@@ -76,6 +76,10 @@ class NotifyPreview < ActionMailer::Preview
Notify.changed_milestone_issue_email(user.id, issue.id, milestone, user.id)
end
+ def import_issues_csv_email
+ Notify.import_issues_csv_email(user, project, { success: 3, errors: [5, 6, 7], valid_file: true })
+ end
+
def closed_merge_request_email
Notify.closed_merge_request_email(user.id, issue.id, user.id).message
end
diff --git a/app/models/blob_viewer/gitlab_ci_yml.rb b/app/models/blob_viewer/gitlab_ci_yml.rb
index 655241c2808..11228e620c9 100644
--- a/app/models/blob_viewer/gitlab_ci_yml.rb
+++ b/app/models/blob_viewer/gitlab_ci_yml.rb
@@ -10,16 +10,16 @@ module BlobViewer
self.file_types = %i(gitlab_ci)
self.binary = false
- def validation_message(project, sha)
+ def validation_message(opts)
return @validation_message if defined?(@validation_message)
prepare!
- @validation_message = Gitlab::Ci::YamlProcessor.validation_message(blob.data, { project: project, sha: sha })
+ @validation_message = Gitlab::Ci::YamlProcessor.validation_message(blob.data, opts)
end
- def valid?(project, sha)
- validation_message(project, sha).blank?
+ def valid?(opts)
+ validation_message(opts).blank?
end
end
end
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index aeb35538d67..dc6f8ae1a7f 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -8,10 +8,15 @@ module Ci
include ObjectStorage::BackgroundMove
include Presentable
include Importable
+ include IgnorableColumn
include Gitlab::Utils::StrongMemoize
include Deployable
include HasRef
+ BuildArchivedError = Class.new(StandardError)
+
+ ignore_column :commands
+
belongs_to :project, inverse_of: :builds
belongs_to :runner
belongs_to :trigger_request
@@ -31,7 +36,7 @@ module Ci
has_one :"job_artifacts_#{key}", -> { where(file_type: value) }, class_name: 'Ci::JobArtifact', inverse_of: :job, foreign_key: :job_id
end
- has_one :metadata, class_name: 'Ci::BuildMetadata'
+ has_one :metadata, class_name: 'Ci::BuildMetadata', autosave: true
has_one :runner_session, class_name: 'Ci::BuildRunnerSession', validate: true, inverse_of: :build
accepts_nested_attributes_for :runner_session
@@ -273,11 +278,14 @@ module Ci
# degenerated build is one that cannot be run by Runner
def degenerated?
- self.options.nil?
+ self.options.blank?
end
def degenerate!
- self.update!(options: nil, yaml_variables: nil, commands: nil)
+ Build.transaction do
+ self.update!(options: nil, yaml_variables: nil)
+ self.metadata&.destroy
+ end
end
def archived?
@@ -624,11 +632,23 @@ module Ci
end
def when
- read_attribute(:when) || build_attributes_from_config[:when] || 'on_success'
+ read_attribute(:when) || 'on_success'
+ end
+
+ def options
+ read_metadata_attribute(:options, :config_options, {})
end
def yaml_variables
- read_attribute(:yaml_variables) || build_attributes_from_config[:yaml_variables] || []
+ read_metadata_attribute(:yaml_variables, :config_variables, [])
+ end
+
+ def options=(value)
+ write_metadata_attribute(:options, :config_options, value)
+ end
+
+ def yaml_variables=(value)
+ write_metadata_attribute(:yaml_variables, :config_variables, value)
end
def user_variables
@@ -904,8 +924,11 @@ module Ci
# have the old integer only format. This method returns the retry option
# normalized as a hash in 11.5+ format.
def normalized_retry
- value = options&.dig(:retry)
- value.is_a?(Integer) ? { max: value } : value.to_h
+ strong_memoize(:normalized_retry) do
+ value = options&.dig(:retry)
+ value = value.is_a?(Integer) ? { max: value } : value.to_h
+ value.with_indifferent_access
+ end
end
def build_attributes_from_config
@@ -929,5 +952,20 @@ module Ci
def project_destroyed?
project.pending_delete?
end
+
+ def read_metadata_attribute(legacy_key, metadata_key, default_value = nil)
+ read_attribute(legacy_key) || metadata&.read_attribute(metadata_key) || default_value
+ end
+
+ def write_metadata_attribute(legacy_key, metadata_key, value)
+ # save to metadata or this model depending on the state of feature flag
+ if Feature.enabled?(:ci_build_metadata_config)
+ ensure_metadata.write_attribute(metadata_key, value)
+ write_attribute(legacy_key, nil)
+ else
+ write_attribute(legacy_key, value)
+ metadata&.write_attribute(metadata_key, nil)
+ end
+ end
end
end
diff --git a/app/models/ci/build_metadata.rb b/app/models/ci/build_metadata.rb
index 9d588b862bd..38390f49217 100644
--- a/app/models/ci/build_metadata.rb
+++ b/app/models/ci/build_metadata.rb
@@ -13,8 +13,12 @@ module Ci
belongs_to :build, class_name: 'Ci::Build'
belongs_to :project
+ before_create :set_build_project
+
validates :build, presence: true
- validates :project, presence: true
+
+ serialize :config_options, Serializers::JSON # rubocop:disable Cop/ActiveRecordSerialize
+ serialize :config_variables, Serializers::JSON # rubocop:disable Cop/ActiveRecordSerialize
chronic_duration_attr_reader :timeout_human_readable, :timeout
@@ -33,5 +37,11 @@ module Ci
update(timeout: timeout, timeout_source: timeout_source)
end
+
+ private
+
+ def set_build_project
+ self.project_id ||= self.build.project_id
+ end
end
end
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 01134e133db..30a957b4117 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -178,6 +178,15 @@ module Ci
scope :for_user, -> (user) { where(user: user) }
+ scope :for_merge_request, -> (merge_request, ref, sha) do
+ ##
+ # We have to filter out unrelated MR pipelines.
+ # When merge request is empty, it selects general pipelines, such as push sourced pipelines.
+ # When merge request is matched, it selects MR pipelines.
+ where(merge_request: [nil, merge_request], ref: ref, sha: sha)
+ .sort_by_merge_request_pipelines
+ end
+
# Returns the pipelines in descending order (= newest first), optionally
# limited to a number of references.
#
@@ -265,6 +274,10 @@ module Ci
sources.reject { |source| source == "external" }.values
end
+ def self.latest_for_merge_request(merge_request, ref, sha)
+ for_merge_request(merge_request, ref, sha).first
+ end
+
def self.ci_sources_values
config_sources.values_at(:repository_source, :auto_devops_source, :unknown_source)
end
@@ -496,7 +509,7 @@ module Ci
return @config_processor if defined?(@config_processor)
@config_processor ||= begin
- ::Gitlab::Ci::YamlProcessor.new(ci_yaml_file, { project: project, sha: sha })
+ ::Gitlab::Ci::YamlProcessor.new(ci_yaml_file, { project: project, sha: sha, user: user })
rescue Gitlab::Ci::YamlProcessor::ValidationError => e
self.yaml_errors = e.message
nil
diff --git a/app/models/clusters/applications/knative.rb b/app/models/clusters/applications/knative.rb
index 0a3168afe68..c572c8bff44 100644
--- a/app/models/clusters/applications/knative.rb
+++ b/app/models/clusters/applications/knative.rb
@@ -19,6 +19,13 @@ module Clusters
self.reactive_cache_key = ->(knative) { [knative.class.model_name.singular, knative.id] }
+ def set_initial_status
+ return unless not_installable?
+ return unless verify_cluster?
+
+ self.status = 'installable'
+ end
+
state_machine :status do
after_transition any => [:installed] do |application|
application.run_after_commit do
@@ -99,6 +106,10 @@ module Clusters
def install_knative_metrics
["kubectl apply -f #{METRICS_CONFIG}"] if cluster.application_prometheus_available?
end
+
+ def verify_cluster?
+ cluster&.application_helm_available? && cluster&.platform_kubernetes_rbac?
+ end
end
end
end
diff --git a/app/models/error_tracking/project_error_tracking_setting.rb b/app/models/error_tracking/project_error_tracking_setting.rb
new file mode 100644
index 00000000000..632c64c2f1c
--- /dev/null
+++ b/app/models/error_tracking/project_error_tracking_setting.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module ErrorTracking
+ class ProjectErrorTrackingSetting < ActiveRecord::Base
+ belongs_to :project
+
+ validates :api_url, length: { maximum: 255 }, public_url: true, url: { enforce_sanitization: true }
+
+ attr_encrypted :token,
+ mode: :per_attribute_iv,
+ key: Settings.attr_encrypted_db_key_base_truncated,
+ algorithm: 'aes-256-gcm'
+ end
+end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 6092c56b925..613860ec31a 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -1092,10 +1092,15 @@ class MergeRequest < ActiveRecord::Base
def all_pipelines(shas: all_commit_shas)
return Ci::Pipeline.none unless source_project
- @all_pipelines ||= source_project.ci_pipelines
- .where(sha: shas, ref: source_branch)
- .where(merge_request: [nil, self])
- .sort_by_merge_request_pipelines
+ @all_pipelines ||=
+ source_project.ci_pipelines
+ .for_merge_request(self, source_branch, all_commit_shas)
+ end
+
+ def update_head_pipeline
+ self.head_pipeline = find_actual_head_pipeline
+
+ update_column(:head_pipeline_id, head_pipeline.id) if head_pipeline_id_changed?
end
def merge_request_pipeline_exists?
@@ -1338,4 +1343,11 @@ class MergeRequest < ActiveRecord::Base
source_project.repository.squash_in_progress?(id)
end
+
+ private
+
+ def find_actual_head_pipeline
+ source_project&.ci_pipelines
+ &.latest_for_merge_request(self, source_branch, diff_head_sha)
+ end
end
diff --git a/app/models/note.rb b/app/models/note.rb
index becf14e9785..1578ae9c4cc 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -456,6 +456,10 @@ class Note < ActiveRecord::Base
Upload.find_by(model: self, path: paths)
end
+ def parent
+ project
+ end
+
private
def keep_around_commit
diff --git a/app/models/project.rb b/app/models/project.rb
index 0187f2eb43f..cab173503ce 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -187,6 +187,7 @@ class Project < ActiveRecord::Base
has_one :import_state, autosave: true, class_name: 'ProjectImportState', inverse_of: :project
has_one :import_export_upload, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_one :project_repository, inverse_of: :project
+ has_one :error_tracking_setting, inverse_of: :project, class_name: 'ErrorTracking::ProjectErrorTrackingSetting'
# Merge Requests for target project should be removed with it
has_many :merge_requests, foreign_key: 'target_project_id', inverse_of: :target_project
@@ -295,6 +296,8 @@ class Project < ActiveRecord::Base
allow_destroy: true,
reject_if: ->(attrs) { attrs[:id].blank? && attrs[:url].blank? }
+ accepts_nested_attributes_for :error_tracking_setting, update_only: true
+
delegate :name, to: :owner, allow_nil: true, prefix: true
delegate :members, to: :team, prefix: true
delegate :add_user, :add_users, to: :team
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 3146f26bed5..d70417e710e 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -222,6 +222,8 @@ class ProjectPolicy < BasePolicy
rule { owner | admin | guest | group_member }.prevent :request_access
rule { ~request_access_enabled }.prevent :request_access
+ rule { can?(:developer_access) & can?(:create_issue) }.enable :import_issues
+
rule { can?(:developer_access) }.policy do
enable :admin_merge_request
enable :admin_milestone
diff --git a/app/services/ci/retry_build_service.rb b/app/services/ci/retry_build_service.rb
index 218f1e63d08..fab8a179843 100644
--- a/app/services/ci/retry_build_service.rb
+++ b/app/services/ci/retry_build_service.rb
@@ -2,7 +2,7 @@
module Ci
class RetryBuildService < ::BaseService
- CLONE_ACCESSORS = %i[pipeline project ref tag options commands name
+ CLONE_ACCESSORS = %i[pipeline project ref tag options name
allow_failure stage stage_id stage_idx trigger_request
yaml_variables when environment coverage_regex
description tag_list protected].freeze
diff --git a/app/services/issues/import_csv_service.rb b/app/services/issues/import_csv_service.rb
new file mode 100644
index 00000000000..ef08fafa7cc
--- /dev/null
+++ b/app/services/issues/import_csv_service.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+module Issues
+ class ImportCsvService
+ def initialize(user, project, csv_io)
+ @user = user
+ @project = project
+ @csv_io = csv_io
+ @results = { success: 0, error_lines: [], parse_error: false }
+ end
+
+ def execute
+ process_csv
+ email_results_to_user
+
+ @results
+ end
+
+ private
+
+ def process_csv
+ csv_data = @csv_io.open(&:read).force_encoding(Encoding::UTF_8)
+
+ CSV.new(csv_data, col_sep: detect_col_sep(csv_data.lines.first), headers: true).each.with_index(2) do |row, line_no|
+ issue = Issues::CreateService.new(@project, @user, title: row[0], description: row[1]).execute
+
+ if issue.persisted?
+ @results[:success] += 1
+ else
+ @results[:error_lines].push(line_no)
+ end
+ end
+ rescue ArgumentError, CSV::MalformedCSVError
+ @results[:parse_error] = true
+ end
+
+ def email_results_to_user
+ Notify.import_issues_csv_email(@user.id, @project.id, @results).deliver_now
+ end
+
+ def detect_col_sep(header)
+ if header.include?(",")
+ ","
+ elsif header.include?(";")
+ ";"
+ elsif header.include?("\t")
+ "\t"
+ else
+ raise CSV::MalformedCSVError
+ end
+ end
+ end
+end
diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb
index 7bb9fa60515..02c2388c05c 100644
--- a/app/services/merge_requests/create_service.rb
+++ b/app/services/merge_requests/create_service.rb
@@ -26,7 +26,7 @@ module MergeRequests
todo_service.new_merge_request(issuable, current_user)
issuable.cache_merge_request_closes_issues!(current_user)
create_merge_request_pipeline(issuable, current_user)
- update_merge_requests_head_pipeline(issuable)
+ issuable.update_head_pipeline
super
end
@@ -45,20 +45,6 @@ module MergeRequests
private
- def update_merge_requests_head_pipeline(merge_request)
- pipeline = head_pipeline_for(merge_request)
- merge_request.update(head_pipeline_id: pipeline.id) if pipeline
- end
-
- def head_pipeline_for(merge_request)
- return unless merge_request.source_project
-
- sha = merge_request.source_branch_sha
- return unless sha
-
- merge_request.all_pipelines(shas: sha).first
- end
-
def set_projects!
# @project is used to determine whether the user can set the merge request's
# assignee, milestone and labels. Whether they can depends on their
diff --git a/app/services/notes/quick_actions_service.rb b/app/services/notes/quick_actions_service.rb
index 4c14d834949..7ee9732040d 100644
--- a/app/services/notes/quick_actions_service.rb
+++ b/app/services/notes/quick_actions_service.rb
@@ -31,7 +31,7 @@ module Notes
return if command_params.empty?
return unless supported?(note)
- self.class.noteable_update_service(note).new(project, current_user, command_params).execute(note.noteable)
+ self.class.noteable_update_service(note).new(note.parent, current_user, command_params).execute(note.noteable)
end
end
end
diff --git a/app/services/projects/operations/update_service.rb b/app/services/projects/operations/update_service.rb
new file mode 100644
index 00000000000..abd6d8de750
--- /dev/null
+++ b/app/services/projects/operations/update_service.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Projects
+ module Operations
+ class UpdateService < BaseService
+ def execute
+ Projects::UpdateService
+ .new(project, current_user, project_update_params)
+ .execute
+ end
+
+ private
+
+ def project_update_params
+ params.slice(:error_tracking_setting_attributes)
+ end
+ end
+ end
+end
diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb
index d248b10f41e..5c58caee8cd 100644
--- a/app/services/quick_actions/interpret_service.rb
+++ b/app/services/quick_actions/interpret_service.rb
@@ -2,6 +2,7 @@
module QuickActions
class InterpretService < BaseService
+ include Gitlab::Utils::StrongMemoize
include Gitlab::QuickActions::Dsl
attr_reader :issuable
@@ -210,15 +211,9 @@ module QuickActions
end
params '~label1 ~"label 2"'
condition do
- if project
- available_labels = LabelsFinder
- .new(current_user, project_id: project.id, include_ancestor_groups: true)
- .execute
- end
-
- project &&
- current_user.can?(:"admin_#{issuable.to_ability_name}", project) &&
- available_labels.any?
+ parent &&
+ current_user.can?(:"admin_#{issuable.to_ability_name}", parent) &&
+ find_labels.any?
end
command :label do |labels_param|
label_ids = find_label_ids(labels_param)
@@ -245,7 +240,7 @@ module QuickActions
issuable.is_a?(Issuable) &&
issuable.persisted? &&
issuable.labels.any? &&
- current_user.can?(:"admin_#{issuable.to_ability_name}", project)
+ current_user.can?(:"admin_#{issuable.to_ability_name}", parent)
end
command :unlabel do |labels_param = nil|
if labels_param.present?
@@ -674,9 +669,25 @@ module QuickActions
MilestonesFinder.new(params.merge(project_ids: [project.id], group_ids: [project.group&.id])).execute
end
- def find_labels(labels_param)
- extract_references(labels_param, :label) |
- LabelsFinder.new(current_user, project_id: project.id, name: labels_param.split, include_ancestor_groups: true).execute
+ def parent
+ project || group
+ end
+
+ def group
+ strong_memoize(:group) do
+ issuable.group if issuable.respond_to?(:group)
+ end
+ end
+
+ def find_labels(labels_params = nil)
+ finder_params = { include_ancestor_groups: true }
+ finder_params[:project_id] = project.id if project
+ finder_params[:group_id] = group.id if group
+ finder_params[:name] = labels_params.split if labels_params
+
+ result = LabelsFinder.new(current_user, finder_params).execute
+
+ extract_references(labels_params, :label) | result
end
def find_label_references(labels_param)
@@ -707,9 +718,11 @@ module QuickActions
# rubocop: disable CodeReuse/ActiveRecord
def extract_references(arg, type)
+ return [] unless arg
+
ext = Gitlab::ReferenceExtractor.new(project, current_user)
- ext.analyze(arg, author: current_user)
+ ext.analyze(arg, author: current_user, group: group)
ext.references(type)
end
diff --git a/app/services/upload_service.rb b/app/services/upload_service.rb
index 39909ee4f82..41ca95b3b6f 100644
--- a/app/services/upload_service.rb
+++ b/app/services/upload_service.rb
@@ -11,7 +11,7 @@ class UploadService
uploader = @uploader_class.new(@model, nil, @uploader_context)
uploader.store!(@file)
- uploader.to_h
+ uploader
end
private
diff --git a/app/validators/url_validator.rb b/app/validators/url_validator.rb
index 5feb0b0f05b..d3e32818dc7 100644
--- a/app/validators/url_validator.rb
+++ b/app/validators/url_validator.rb
@@ -26,6 +26,7 @@
# - allow_local_network: Allow urls pointing to private network addresses. Default: true
# - ports: Allowed ports. Default: all.
# - enforce_user: Validate user format. Default: false
+# - enforce_sanitization: Validate that there are no html/css/js tags. Default: false
#
# Example:
# class User < ActiveRecord::Base
@@ -70,7 +71,8 @@ class UrlValidator < ActiveModel::EachValidator
allow_localhost: true,
allow_local_network: true,
ascii_only: false,
- enforce_user: false
+ enforce_user: false,
+ enforce_sanitization: false
}
end
diff --git a/app/views/admin/users/_user.html.haml b/app/views/admin/users/_user.html.haml
index b2163ee85fa..a4e2c3252af 100644
--- a/app/views/admin/users/_user.html.haml
+++ b/app/views/admin/users/_user.html.haml
@@ -3,7 +3,7 @@
= image_tag avatar_icon_for_user(user), class: "avatar", alt: ''
.row-main-content
.user-name.row-title.str-truncated-100
- = link_to user.name, [:admin, user]
+ = link_to user.name, [:admin, user], class: "js-user-link", data: { user_id: user.id }
- if user.blocked?
%span.badge.badge-danger blocked
- if user.admin?
diff --git a/app/views/clusters/clusters/show.html.haml b/app/views/clusters/clusters/show.html.haml
index b1aa8e5d477..89a2dfdd69f 100644
--- a/app/views/clusters/clusters/show.html.haml
+++ b/app/views/clusters/clusters/show.html.haml
@@ -16,6 +16,7 @@
install_jupyter_path: clusterable.install_applications_cluster_path(@cluster, :jupyter),
install_knative_path: clusterable.install_applications_cluster_path(@cluster, :knative),
toggle_status: @cluster.enabled? ? 'true': 'false',
+ has_rbac: @cluster.platform_kubernetes_rbac? ? 'true': 'false',
cluster_type: @cluster.cluster_type,
cluster_status: @cluster.status_name,
cluster_status_reason: @cluster.status_reason,
diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml
index d8017742c90..e516c76400a 100644
--- a/app/views/layouts/nav/sidebar/_project.html.haml
+++ b/app/views/layouts/nav/sidebar/_project.html.haml
@@ -339,7 +339,10 @@
= link_to project_settings_ci_cd_path(@project), title: _('CI / CD') do
%span
= _('CI / CD')
- = render_if_exists 'projects/sidebar/settings_operations'
+ - if settings_operations_available?
+ = nav_link(controller: [:operations]) do
+ = link_to project_settings_operations_path(@project), title: _('Operations') do
+ = _('Operations')
- if @project.pages_available?
= nav_link(controller: :pages) do
= link_to project_pages_path(@project), title: _('Pages') do
diff --git a/app/views/notify/import_issues_csv_email.html.haml b/app/views/notify/import_issues_csv_email.html.haml
new file mode 100644
index 00000000000..f30d2b5f078
--- /dev/null
+++ b/app/views/notify/import_issues_csv_email.html.haml
@@ -0,0 +1,18 @@
+- text_style = 'font-size:16px; text-align:center; line-height:30px;'
+
+%p{ style: text_style }
+ Your CSV import for project
+ %a{ href: project_url(@project), style: "color:#3777b0; text-decoration:none;" }
+ = @project.full_name
+ has been completed.
+
+%p{ style: text_style }
+ #{pluralize(@results[:success], 'issue')} imported.
+
+- if @results[:error_lines].present?
+ %p{ style: text_style }
+ Errors found on line #{'number'.pluralize(@results[:error_lines].size)}: #{@results[:error_lines].join(', ')}. Please check if these lines have an issue title.
+
+- if @results[:parse_error]
+ %p{ style: text_style }
+ Error parsing CSV file. Please make sure it has the correct format: a delimited text file that uses a comma to separate values.
diff --git a/app/views/notify/import_issues_csv_email.text.erb b/app/views/notify/import_issues_csv_email.text.erb
new file mode 100644
index 00000000000..1117f90714d
--- /dev/null
+++ b/app/views/notify/import_issues_csv_email.text.erb
@@ -0,0 +1,11 @@
+Your CSV import for project <%= @project.full_name %> (<%= project_url(@project) %>) has been completed.
+
+<%= pluralize(@results[:success], 'issue') %> imported.
+
+<% if @results[:error_lines].present? %>
+Errors found on line <%= 'number'.pluralize(@results[:error_lines].size) %>: <%= @results[:error_lines].join(', ') %>. Please check if these lines have an issue title.
+<% end %>
+
+<% if @results[:parse_error] %>
+Error parsing CSV file. Please make sure it has the correct format: a delimited text file that uses a comma to separate values.
+<% end %>
diff --git a/app/views/projects/_issuable_by_email.html.haml b/app/views/projects/_issuable_by_email.html.haml
index d59191a6f87..c8ad5919596 100644
--- a/app/views/projects/_issuable_by_email.html.haml
+++ b/app/views/projects/_issuable_by_email.html.haml
@@ -36,7 +36,12 @@
%p
= render 'by_email_description'
%p
- This is a private email address, generated just for you.
+ This is a private email address
+
+ %a{ href: 'https://docs.gitlab.com/ee/development/emails.html#email-namespace', target: "_blank", rel: "noopener" }
+ %i.fa.fa-question-circle{ 'aria-label': "Learn more about incoming email addresses" }
+
+ , generated just for you.
Anyone who gets ahold of it can create issues or merge requests as if they were you.
You should
diff --git a/app/views/projects/blob/viewers/_gitlab_ci_yml.html.haml b/app/views/projects/blob/viewers/_gitlab_ci_yml.html.haml
index 5be7cc7f25a..61d67a88a5a 100644
--- a/app/views/projects/blob/viewers/_gitlab_ci_yml.html.haml
+++ b/app/views/projects/blob/viewers/_gitlab_ci_yml.html.haml
@@ -1,9 +1,9 @@
-- if viewer.valid?(@project, @commit.sha)
+- if viewer.valid?(project: @project, sha: @commit.sha, user: @current_user)
= icon('check fw')
This GitLab CI configuration is valid.
- else
= icon('warning fw')
This GitLab CI configuration is invalid:
- = viewer.validation_message(@project, @commit.sha)
+ = viewer.validation_message(project: @project, sha: @commit.sha, user: @current_user)
= link_to 'Learn more', help_page_path('ci/yaml/README')
diff --git a/app/views/projects/ci/lints/_create.html.haml b/app/views/projects/ci/lints/_create.html.haml
index 30bf1384b22..b4c18374220 100644
--- a/app/views/projects/ci/lints/_create.html.haml
+++ b/app/views/projects/ci/lints/_create.html.haml
@@ -13,20 +13,23 @@
%tbody
- @stages.each do |stage|
- @builds.select { |build| build[:stage] == stage }.each do |build|
+ - job = @jobs[build[:name].to_sym]
%tr
%td #{stage.capitalize} Job - #{build[:name]}
%td
- %pre= build[:commands]
+ %pre= job[:before_script].to_a.join('\n')
+ %pre= job[:script].to_a.join('\n')
+ %pre= job[:after_script].to_a.join('\n')
%br
%b Tag list:
= build[:tag_list].to_a.join(", ")
%br
%b Only policy:
- = @jobs[build[:name].to_sym][:only].to_a.join(", ")
+ = job[:only].to_a.join(", ")
%br
%b Except policy:
- = @jobs[build[:name].to_sym][:except].to_a.join(", ")
+ = job[:except].to_a.join(", ")
%br
%b Environment:
= build[:environment]
diff --git a/app/views/projects/cleanup/_show.html.haml b/app/views/projects/cleanup/_show.html.haml
index cecc139b183..888be4ee282 100644
--- a/app/views/projects/cleanup/_show.html.haml
+++ b/app/views/projects/cleanup/_show.html.haml
@@ -24,6 +24,6 @@
= _("No file selected")
= f.file_field :bfg_object_map, accept: 'text/plain', class: "hidden js-object-map-input", required: true
.form-text.text-muted
- = _("The maximum file size allowed is %{max_attachment_size}mb") % { max_attachment_size: Gitlab::CurrentSettings.max_attachment_size }
+ = _("The maximum file size allowed is %{size}.") % { size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes) }
= f.submit _('Start cleanup'), class: 'btn btn-success'
diff --git a/app/views/projects/issues/_import_export.svg b/app/views/projects/issues/_import_export.svg
new file mode 100644
index 00000000000..53c35d12f57
--- /dev/null
+++ b/app/views/projects/issues/_import_export.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 238 111" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><rect id="4" width="82" rx="3" height="28" fill="#fff"/><path id="5" d="m68.926 12.09v-2.41c0-.665-.437-.888-.975-.507l-6.552 4.631c-.542.383-.539.998 0 1.379l6.552 4.631c.542.383.975.154.975-.507v-2.41h4.874c.668 0 1.2-.538 1.2-1.201v-2.406c0-.668-.537-1.201-1.2-1.201h-4.874" fill="#fc8a51"/><path id="6" d="m4 24h74v-20h-74v20m-4-21c0-1.655 1.338-2.996 2.991-2.996h76.02c1.652 0 2.991 1.35 2.991 2.996v22.01c0 1.655-1.338 2.996-2.991 2.996h-76.02c-1.652 0-2.991-1.35-2.991-2.996v-22.01"/><circle id="2" cx="16" cy="14" r="7"/><circle id="0" cx="16" cy="14" r="7"/><mask id="3" width="14" height="14" x="0" y="0" fill="#fff"><use xlink:href="#2"/></mask><mask id="1" width="14" height="14" x="0" y="0" fill="#fff"><use xlink:href="#0"/></mask></defs><g fill="none" fill-rule="evenodd"><rect width="98" height="111" fill="#fff" rx="6"/><path fill="#e5e5e5" fill-rule="nonzero" d="m4 6.01v98.99c0 1.11.897 2.01 2 2.01h85.998c1.105 0 2-.897 2-2.01v-98.99c0-1.11-.897-2.01-2-2.01h-85.998c-1.105 0-2 .897-2 2.01m-4 0c0-3.318 2.685-6.01 6-6.01h85.998c3.314 0 6 2.689 6 6.01v98.99c0 3.318-2.685 6.01-6 6.01h-85.998c-3.314 0-6-2.689-6-6.01v-98.99"/><rect width="76" height="85" x="11" y="12" fill="#f9f9f9" rx="3"/><g transform="translate(37 59)"><use xlink:href="#4"/><path fill="#e5e5e5" fill-rule="nonzero" d="m4 24h74v-20h-74v20m-4-21c0-1.655 1.338-2.996 2.991-2.996h76.02c1.652 0 2.991 1.35 2.991 2.996v22.01c0 1.655-1.338 2.996-2.991 2.996h-76.02c-1.652 0-2.991-1.35-2.991-2.996v-22.01"/><use fill="#fff" stroke="#6b4fbb" stroke-width="8" mask="url(#1)" xlink:href="#0"/><use xlink:href="#5"/></g><g transform="translate(140)"><path fill="#fff" d="m0 4h94v103h-94z"/><path fill="#e5e5e5" fill-rule="nonzero" d="m0 74v30.993c0 3.318 2.687 6.01 6 6.01h85.998c3.316 0 6-2.69 6-6.01v-98.99c0-3.318-2.687-6.01-6-6.01h-85.998c-3.316 0-6 2.69-6 6.01v.993h4v-.993c0-1.11.896-2.01 2-2.01h85.998c1.105 0 2 .897 2 2.01v98.99c0 1.11-.896 2.01-2 2.01h-85.998c-1.105 0-2-.897-2-2.01v-30.993h-4"/><g fill="#f9f9f9"><rect width="82" height="28" x="8" y="12" rx="3"/><rect width="82" height="28" x="8" y="43" rx="3"/></g></g><g fill-rule="nonzero" transform="translate(148 73)"><use fill="#e5e5e5" xlink:href="#6"/><path fill="#6b4fbb" d="m17 17c1.657 0 3-1.343 3-3 0-1.657-1.343-3-3-3-1.657 0-3 1.343-3 3 0 1.657 1.343 3 3 3m0 4c-3.866 0-7-3.134-7-7 0-3.866 3.134-7 7-7 3.866 0 7 3.134 7 7 0 3.866-3.134 7-7 7"/></g><g transform="translate(25 24)"><use xlink:href="#4"/><use fill="#e5e5e5" fill-rule="nonzero" xlink:href="#6"/><use fill="#fff" stroke="#6b4fbb" stroke-width="8" mask="url(#3)" xlink:href="#2"/><use xlink:href="#5"/></g><g transform="translate(107 10)"><use xlink:href="#4"/><use fill="#fc8a51" fill-opacity=".3" fill-rule="nonzero" xlink:href="#6"/><path fill="#6b4fbb" fill-rule="nonzero" d="m16 17c1.657 0 3-1.343 3-3 0-1.657-1.343-3-3-3-1.657 0-3 1.343-3 3 0 1.657 1.343 3 3 3m0 4c-3.866 0-7-3.134-7-7 0-3.866 3.134-7 7-7 3.866 0 7 3.134 7 7 0 3.866-3.134 7-7 7" id="7"/><use xlink:href="#5"/></g><g transform="translate(128 41)"><use xlink:href="#4"/><use fill="#fc8a51" fill-opacity=".3" fill-rule="nonzero" xlink:href="#6"/><use xlink:href="#7"/><path fill="#fc8a51" d="m66.926 12.09v-2.41c0-.665-.437-.888-.975-.507l-6.552 4.631c-.542.383-.539.998 0 1.379l6.552 4.631c.542.383.975.154.975-.507v-2.41h4.874c.668 0 1.2-.538 1.2-1.201v-2.406c0-.668-.537-1.201-1.2-1.201h-4.874"/></g></g></svg> \ No newline at end of file
diff --git a/app/views/projects/issues/_nav_btns.html.haml b/app/views/projects/issues/_nav_btns.html.haml
index e4a0d4b8479..fd6559e37ba 100644
--- a/app/views/projects/issues/_nav_btns.html.haml
+++ b/app/views/projects/issues/_nav_btns.html.haml
@@ -1,11 +1,30 @@
-= render 'shared/issuable/feed_buttons'
-
-- if @can_bulk_update
- = button_tag "Edit issues", class: "btn btn-default append-right-10 js-bulk-update-toggle"
-- if show_new_issue_link?(@project)
- = link_to "New issue", new_project_issue_path(@project,
- issue: { assignee_id: finder.assignee.try(:id),
- milestone_id: finder.milestones.first.try(:id) }),
- class: "btn btn-success",
- title: "New issue",
- id: "new_issue_link"
+- show_feed_buttons = local_assigns.fetch(:show_feed_buttons, true)
+- show_import_button = local_assigns.fetch(:show_import_button, true) && Feature.enabled?(:issues_import_csv) && can?(current_user, :import_issues, @project)
+- show_export_button = local_assigns.fetch(:show_export_button, true)
+
+.nav-controls.issues-nav-controls
+ - if show_feed_buttons
+ = render 'shared/issuable/feed_buttons'
+
+ .btn-group.append-right-10<
+ - if show_export_button
+ = render_if_exists 'projects/issues/export_csv/button'
+
+ - if show_import_button
+ = render 'projects/issues/import_csv/button'
+
+ - if @can_bulk_update
+ = button_tag _("Edit issues"), class: "btn btn-default append-right-10 js-bulk-update-toggle"
+ - if show_new_issue_link?(@project)
+ = link_to _("New issue"), new_project_issue_path(@project,
+ issue: { assignee_id: finder.assignee.try(:id),
+ milestone_id: finder.milestones.first.try(:id) }),
+ class: "btn btn-success",
+ title: _("New issue"),
+ id: "new_issue_link"
+
+- if show_export_button
+ = render_if_exists 'projects/issues/export_csv/modal'
+
+- if show_import_button
+ = render 'projects/issues/import_csv/modal'
diff --git a/app/views/projects/issues/import_csv/_button.html.haml b/app/views/projects/issues/import_csv/_button.html.haml
new file mode 100644
index 00000000000..acc2c50294f
--- /dev/null
+++ b/app/views/projects/issues/import_csv/_button.html.haml
@@ -0,0 +1,9 @@
+- type = local_assigns.fetch(:type, :icon)
+
+%button.csv-import-button.btn{ title: _('Import CSV'), class: ('has-tooltip' if type == :icon),
+ data: { toggle: 'modal', target: '.issues-import-modal' } }
+ - if type == :icon
+ = sprite_icon('upload')
+ - else
+ = _('Import CSV')
+
diff --git a/app/views/projects/issues/import_csv/_modal.html.haml b/app/views/projects/issues/import_csv/_modal.html.haml
new file mode 100644
index 00000000000..18768307341
--- /dev/null
+++ b/app/views/projects/issues/import_csv/_modal.html.haml
@@ -0,0 +1,24 @@
+.issues-import-modal.modal
+ .modal-dialog
+ .modal-content
+ = form_tag import_csv_namespace_project_issues_path, multipart: true do
+ .modal-header
+ %h3
+ = _('Import issues')
+ .import-export-svg-container
+ = render 'projects/issues/import_export.svg'
+ %a.close{ href: '#', 'data-dismiss' => 'modal' } ×
+ .modal-body
+ .modal-text
+ %p
+ = _("Your issues will be imported in the background. Once finished, you'll get a confirmation email.")
+ .form-group
+ = label_tag :file, _('Upload CSV file'), class: 'label-bold'
+ %div
+ = file_field_tag :file, accept: '.csv,text/csv', required: true
+ %p.text-secondary
+ = _('It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected.')
+ = _('The maximum file size allowed is %{size}.') % { size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes) }
+ .modal-footer
+ %button{ type: 'submit', class: 'btn btn-success', title: _('Import issues') }
+ = _('Import issues')
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index 1e7737aeb97..39e9e9171cf 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -11,8 +11,7 @@
%div{ class: (container_class) }
.top-area
= render 'shared/issuable/nav', type: :issues
- .nav-controls
- = render "projects/issues/nav_btns"
+ = render "projects/issues/nav_btns"
= render 'shared/issuable/search_bar', type: :issues
- if @can_bulk_update
@@ -23,4 +22,4 @@
- if new_issue_email
= render 'projects/issuable_by_email', email: new_issue_email, issuable_type: 'issue'
- else
- = render 'shared/empty_states/issues', button_path: new_project_issue_path(@project)
+ = render 'shared/empty_states/issues', button_path: new_project_issue_path(@project), show_import_button: true
diff --git a/app/views/projects/releases/index.html.haml b/app/views/projects/releases/index.html.haml
index f01d4e826b9..28bb4e032eb 100644
--- a/app/views/projects/releases/index.html.haml
+++ b/app/views/projects/releases/index.html.haml
@@ -2,4 +2,4 @@
- page_title _('Releases')
%div{ class: container_class }
- #js-releases-page{ data: { project_id: @project.id, illustration_path: image_path('illustrations/releases.svg'), documentation_path: help_page_path('user/project/releases') } }
+ #js-releases-page{ data: { project_id: @project.id, illustration_path: image_path('illustrations/releases.svg'), documentation_path: help_page_path('user/project/releases/index') } }
diff --git a/app/views/projects/settings/operations/_error_tracking.html.haml b/app/views/projects/settings/operations/_error_tracking.html.haml
new file mode 100644
index 00000000000..71335e4dfd0
--- /dev/null
+++ b/app/views/projects/settings/operations/_error_tracking.html.haml
@@ -0,0 +1,30 @@
+- return unless Feature.enabled?(:error_tracking, @project) && can?(current_user, :read_environment, @project)
+
+- setting = error_tracking_setting
+
+%section.settings.expanded.border-0.no-animate
+ .settings-header
+ %h4
+ = _('Error Tracking')
+ %p
+ = _('To link Sentry to GitLab, enter your Sentry URL and Auth Token.')
+ .settings-content
+ = form_for @project, url: project_settings_operations_path(@project), method: :patch do |f|
+ = form_errors(@project)
+ .form-group
+ = f.fields_for :error_tracking_setting_attributes, setting do |form|
+ .form-check.form-group
+ = form.check_box :enabled, class: 'form-check-input'
+ = form.label :enabled, _('Active'), class: 'form-check-label'
+ .form-group
+ = form.label :api_url, _('Sentry API URL'), class: 'label-bold'
+ = form.url_field :api_url, class: 'form-control', placeholder: _('http://<sentry-host>/api/0/projects/{organization_slug}/{project_slug}/issues/')
+ %p.form-text.text-muted
+ = _('Enter your Sentry API URL')
+ .form-group
+ = form.label :token, _('Auth Token'), class: 'label-bold'
+ = form.text_field :token, class: 'form-control'
+ %p.form-text.text-muted
+ = _('Find and manage Auth Tokens in your Sentry account settings page.')
+
+ = f.submit _('Save changes'), class: 'btn btn-success'
diff --git a/app/views/projects/settings/operations/show.html.haml b/app/views/projects/settings/operations/show.html.haml
new file mode 100644
index 00000000000..b36fa9a5f51
--- /dev/null
+++ b/app/views/projects/settings/operations/show.html.haml
@@ -0,0 +1,5 @@
+- @content_class = 'limit-container-width' unless fluid_layout
+- page_title _('Operations')
+
+= render 'projects/settings/operations/error_tracking', expanded: true
+= render_if_exists 'projects/settings/operations/tracing'
diff --git a/app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml b/app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml
index 0d0a3c1aa64..422be28737c 100644
--- a/app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml
+++ b/app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml
@@ -1,4 +1,4 @@
-- if show_auto_devops_implicitly_enabled_banner?(project)
+- if show_auto_devops_implicitly_enabled_banner?(project, current_user)
.auto-devops-implicitly-enabled-banner.alert.alert-warning
- more_information_link = link_to _('More information'), help_page_path('topics/autodevops/index.md'), target: '_blank', class: 'alert-link'
- auto_devops_message = s_("AutoDevOps|The Auto DevOps pipeline has been enabled and will be used if no alternative CI configuration file is found. %{more_information_link}") % { more_information_link: more_information_link }
diff --git a/app/views/shared/_flash_user_callout.html.haml b/app/views/shared/_flash_user_callout.html.haml
new file mode 100644
index 00000000000..fe175195e66
--- /dev/null
+++ b/app/views/shared/_flash_user_callout.html.haml
@@ -0,0 +1,11 @@
+- callout_data = { uid: "callout_feature_#{feature_name}_dismissed", feature_id: feature_name, dismiss_endpoint: user_callouts_path }
+- extra_flash_class = local_assigns.fetch(:extra_flash_class, nil)
+
+.flash-container.flash-container-page.user-callout{ data: callout_data }
+ -# We currently only support `alert`, `warning`, `notice`, `success`
+ %div{ class: "flash-#{flash_type}" }
+ %div{ class: "#{(container_class unless fluid_layout)} #{(extra_flash_class unless @no_container)} #{@content_class}" }
+ %span= message
+ %button.btn.btn-default.close.js-close{ type: 'button',
+ 'aria-label' => _('Dismiss') }
+ = sprite_icon('close', css_class: 'dismiss-icon')
diff --git a/app/views/shared/empty_states/_issues.html.haml b/app/views/shared/empty_states/_issues.html.haml
index 0ddc56dc6c3..0434860dec4 100644
--- a/app/views/shared/empty_states/_issues.html.haml
+++ b/app/views/shared/empty_states/_issues.html.haml
@@ -1,5 +1,6 @@
- button_path = local_assigns.fetch(:button_path, false)
- project_select_button = local_assigns.fetch(:project_select_button, false)
+- show_import_button = local_assigns.fetch(:show_import_button, false) && Feature.enabled?(:issues_import_csv) && can?(current_user, :import_issues, @project)
- has_button = button_path || project_select_button
.row.empty-state
@@ -21,12 +22,20 @@
- if has_button
.text-center
- if project_select_button
- = render 'shared/new_project_item_select', path: 'issues/new', label: 'New issue', type: :issues, with_feature_enabled: 'issues'
+ = render 'shared/new_project_item_select', path: 'issues/new', label: _('New issue'), type: :issues, with_feature_enabled: 'issues'
- else
- = link_to 'New issue', button_path, class: 'btn btn-success', title: 'New issue', id: 'new_issue_link'
+ = link_to _('New issue'), button_path, class: 'btn btn-success', title: _('New issue'), id: 'new_issue_link'
+
+ - if show_import_button
+ = render 'projects/issues/import_csv/button', type: :text
+
- else
%h4.text-center= _("There are no issues to show")
%p
= _("The Issue Tracker is the place to add things that need to be improved or solved in a project. You can register or sign in to create issues for this project.")
.text-center
= link_to _('Register / Sign In'), new_user_session_path, class: 'btn btn-success'
+
+- if show_import_button
+ = render 'projects/issues/import_csv/modal'
+
diff --git a/app/views/shared/issuable/_feed_buttons.html.haml b/app/views/shared/issuable/_feed_buttons.html.haml
index d4834090413..83f60fa6fe2 100644
--- a/app/views/shared/issuable/_feed_buttons.html.haml
+++ b/app/views/shared/issuable/_feed_buttons.html.haml
@@ -1,4 +1,4 @@
-= link_to safe_params.merge(rss_url_options), class: 'btn has-tooltip', data: { container: 'body' }, title: 'Subscribe to RSS feed' do
+= link_to safe_params.merge(rss_url_options), class: 'btn has-tooltip', data: { container: 'body' }, title: _('Subscribe to RSS feed') do
= icon('rss')
-= link_to safe_params.merge(calendar_url_options), class: 'btn has-tooltip', data: { container: 'body' }, title: 'Subscribe to calendar' do
+= link_to safe_params.merge(calendar_url_options), class: 'btn has-tooltip', data: { container: 'body' }, title: _('Subscribe to calendar') do
= custom_icon('icon_calendar')
diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml
deleted file mode 100644
index 2ca4657851c..00000000000
--- a/app/views/shared/issuable/_filter.html.haml
+++ /dev/null
@@ -1,32 +0,0 @@
-.issues-filters
- .issues-details-filters.row-content-block.second-block
- = form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_title, :label_name, :search]), method: :get, class: 'filter-form js-filter-form' do
- - if params[:search].present?
- = hidden_field_tag :search, params[:search]
- .issues-other-filters
- .filter-item.inline
- - if params[:author_id].present?
- = hidden_field_tag(:author_id, params[:author_id])
- = dropdown_tag(user_dropdown_label(params[:author_id], "Author"), options: { toggle_class: "js-user-search js-filter-submit js-author-search", title: "Filter by author", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-author js-filter-submit",
- placeholder: "Search authors", data: { any_user: "Any Author", first_user: current_user&.username, current_user: true, project_id: @project&.id, group_id: @group&.id, selected: params[:author_id], field_name: "author_id", default_label: "Author" } })
-
- .filter-item.inline
- - if params[:assignee_id].present?
- = hidden_field_tag(:assignee_id, params[:assignee_id])
- = dropdown_tag(user_dropdown_label(params[:assignee_id], "Assignee"), options: { toggle_class: "js-user-search js-filter-submit js-assignee-search", title: "Filter by assignee", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee js-filter-submit",
- placeholder: "Search assignee", data: { any_user: "Any Assignee", first_user: current_user&.username, null_user: true, current_user: true, project_id: @project&.id, group_id: @group&.id, selected: params[:assignee_id], field_name: "assignee_id", default_label: "Assignee" } })
-
- .filter-item.inline.milestone-filter
- = render "shared/issuable/milestone_dropdown", selected: finder.milestones.try(:first), name: :milestone_title, show_any: true, show_upcoming: true, show_started: true
-
- .filter-item.inline.labels-filter
- = render "shared/issuable/label_dropdown", selected: selected_labels, use_id: false, selected_toggle: params[:label_name], data_options: { field_name: "label_name[]" }
-
- - unless @no_filters_set
- .float-right
- = render 'shared/issuable/sort_dropdown'
-
- - has_labels = @labels && @labels.any?
- .row-content-block.second-block.filtered-labels{ class: ("hidden" unless has_labels) }
- - if has_labels
- = render 'shared/labels_row', labels: @labels
diff --git a/app/views/shared/issuable/form/_merge_params.html.haml b/app/views/shared/issuable/form/_merge_params.html.haml
index 1881875b7c0..ca3141b2cc3 100644
--- a/app/views/shared/issuable/form/_merge_params.html.haml
+++ b/app/views/shared/issuable/form/_merge_params.html.haml
@@ -19,4 +19,4 @@
= check_box_tag 'merge_request[squash]', '1', issuable.squash, class: 'form-check-input'
= label_tag 'merge_request[squash]', class: 'form-check-label' do
Squash commits when merge request is accepted.
- = link_to 'About this feature', help_page_path('user/project/merge_requests/squash_and_merge')
+ = link_to icon('question-circle'), help_page_path('user/project/merge_requests/squash_and_merge'), target: '_blank'
diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml
index 6b3841ebbc4..2db1f67a793 100644
--- a/app/views/shared/members/_member.html.haml
+++ b/app/views/shared/members/_member.html.haml
@@ -10,7 +10,7 @@
- if user
= image_tag avatar_icon_for_user(user, 40), class: "avatar s40", alt: ''
.user-info
- = link_to user.name, user_path(user), class: 'member'
+ = link_to user.name, user_path(user), class: 'member js-user-link', data: { user_id: user.id }
= user_status(user)
%span.cgray= user.to_reference
diff --git a/app/views/shared/notes/_comment_button.html.haml b/app/views/shared/notes/_comment_button.html.haml
index 0674c822d63..f487c0bf0d5 100644
--- a/app/views/shared/notes/_comment_button.html.haml
+++ b/app/views/shared/notes/_comment_button.html.haml
@@ -1,30 +1,31 @@
- noteable_name = @note.noteable.human_class_name
.float-left.btn-group.append-right-10.droplab-dropdown.comment-type-dropdown.js-comment-type-dropdown
- %input.btn.btn-nr.btn-success.comment-btn.js-comment-button.js-comment-submit-button{ type: 'submit', value: 'Comment' }
+ %input.btn.btn-nr.btn-success.comment-btn.js-comment-button.js-comment-submit-button{ type: 'submit', value: _('Comment') }
- if @note.can_be_discussion_note?
- = button_tag type: 'button', class: 'btn btn-nr dropdown-toggle comment-btn js-note-new-discussion js-disable-on-submit', data: { 'dropdown-trigger' => '#resolvable-comment-menu' }, 'aria-label' => 'Open comment type dropdown' do
+ = button_tag type: 'button', class: 'btn btn-nr dropdown-toggle comment-btn js-note-new-discussion js-disable-on-submit', data: { 'dropdown-trigger' => '#resolvable-comment-menu' }, 'aria-label' => _('Open comment type dropdown') do
= icon('caret-down', class: 'toggle-icon')
%ul#resolvable-comment-menu.dropdown-menu.dropdown-open-top{ data: { dropdown: true } }
- %li#comment.droplab-item-selected{ data: { value: '', 'submit-text' => 'Comment', 'close-text' => "Comment & close #{noteable_name}", 'reopen-text' => "Comment & reopen #{noteable_name}" } }
+ %li#comment.droplab-item-selected{ data: { value: '', 'submit-text' => _('Comment'), 'close-text' => _("Comment & close %{noteable_name}") % { noteable_name: noteable_name }, 'reopen-text' => _("Comment & reopen %{noteable_name}") % { noteable_name: noteable_name } } }
%button.btn.btn-transparent
= icon('check', class: 'icon')
.description
- %strong Comment
+ %strong= _("Comment")
%p
- Add a general comment to this #{noteable_name}.
+ = _("Add a general comment to this %{noteable_name}.") % { noteable_name: noteable_name }
%li.divider.droplab-item-ignore
- %li#discussion{ data: { value: 'DiscussionNote', 'submit-text' => 'Start discussion', 'close-text' => "Start discussion & close #{noteable_name}", 'reopen-text' => "Start discussion & reopen #{noteable_name}" } }
+ %li#discussion{ data: { value: 'DiscussionNote', 'submit-text' => _('Start discussion'), 'close-text' => _("Start discussion & close %{noteable_name}") % { noteable_name: noteable_name }, 'reopen-text' => _("Start discussion & reopen %{noteable_name}") % { noteable_name: noteable_name } } }
%button.btn.btn-transparent
= icon('check', class: 'icon')
.description
- %strong Start discussion
+ %strong= _("Start discussion")
%p
= succeed '.' do
- Discuss a specific suggestion or question
- if @note.noteable.supports_resolvable_notes?
- that needs to be resolved
+ = _('Discuss a specific suggestion or question that needs to be resolved')
+ - else
+ = _('Discuss a specific suggestion or question')
diff --git a/app/views/shared/notes/_edit.html.haml b/app/views/shared/notes/_edit.html.haml
index f4b3aac29b4..84a3ef9d8fe 100644
--- a/app/views/shared/notes/_edit.html.haml
+++ b/app/views/shared/notes/_edit.html.haml
@@ -1 +1 @@
-%textarea.hidden.js-task-list-field.original-task-list{ data: {update_url: note_url(note) } }= note.note
+%textarea.hidden.js-task-list-field.original-task-list{ data: { update_url: note_url(note) } }= note.note
diff --git a/app/views/shared/notes/_edit_form.html.haml b/app/views/shared/notes/_edit_form.html.haml
index fec966069b9..6fe511c2999 100644
--- a/app/views/shared/notes/_edit_form.html.haml
+++ b/app/views/shared/notes/_edit_form.html.haml
@@ -3,12 +3,12 @@
= hidden_field_tag :target_id, '', class: 'js-form-target-id'
= hidden_field_tag :target_type, '', class: 'js-form-target-type'
= render layout: 'projects/md_preview', locals: { url: preview_markdown_path(project), referenced_users: true } do
- = render 'projects/zen', attr: 'note[note]', classes: 'note-textarea js-note-text js-task-list-field', placeholder: "Write a comment or drag your files here…"
+ = render 'projects/zen', attr: 'note[note]', classes: 'note-textarea js-note-text js-task-list-field', placeholder: _("Write a comment or drag your files here…")
= render 'shared/notes/hints'
.note-form-actions.clearfix
.settings-message.note-edit-warning.js-finish-edit-warning
- Finish editing this message first!
- = submit_tag 'Save comment', class: 'btn btn-nr btn-success js-comment-save-button'
+ = _("Finish editing this message first!")
+ = submit_tag _('Save comment'), class: 'btn btn-nr btn-success js-comment-save-button'
%button.btn.btn-nr.btn-cancel.note-edit-cancel{ type: 'button' }
- Cancel
+ = _("Cancel")
diff --git a/app/views/shared/notes/_form.html.haml b/app/views/shared/notes/_form.html.haml
index c360f1ffe2a..6a1eea85fde 100644
--- a/app/views/shared/notes/_form.html.haml
+++ b/app/views/shared/notes/_form.html.haml
@@ -29,7 +29,7 @@
= render 'projects/zen', f: f,
attr: :note,
classes: 'note-textarea js-note-text',
- placeholder: "Write a comment or drag your files here…",
+ placeholder: _("Write a comment or drag your files here…"),
supports_quick_actions: supports_quick_actions,
supports_autocomplete: supports_autocomplete
= render 'shared/notes/hints', supports_quick_actions: supports_quick_actions
@@ -40,5 +40,5 @@
= yield(:note_actions)
- %a.btn.btn-cancel.js-note-discard{ role: "button", data: {cancel_text: "Cancel" } }
- Discard draft
+ %a.btn.btn-cancel.js-close-discussion-note-form.hide{ role: "button", data: { cancel_text: _("Cancel") } }
+ = _('Cancel')
diff --git a/app/views/shared/notes/_hints.html.haml b/app/views/shared/notes/_hints.html.haml
index 00eae553279..46f3f8428f1 100644
--- a/app/views/shared/notes/_hints.html.haml
+++ b/app/views/shared/notes/_hints.html.haml
@@ -1,10 +1,10 @@
- supports_quick_actions = local_assigns.fetch(:supports_quick_actions, false)
.comment-toolbar.clearfix
.toolbar-text
- = link_to 'Markdown', help_page_path('user/markdown'), target: '_blank', tabindex: -1
+ = link_to _('Markdown'), help_page_path('user/markdown'), target: '_blank', tabindex: -1
- if supports_quick_actions
and
- = link_to 'quick actions', help_page_path('user/project/quick_actions'), target: '_blank', tabindex: -1
+ = link_to _('quick actions'), help_page_path('user/project/quick_actions'), target: '_blank', tabindex: -1
are
- else
is
@@ -24,12 +24,12 @@
= icon('file-image-o', class: 'toolbar-button-icon')
%span.uploading-error-message
-# Populated by app/assets/javascripts/dropzone_input.js
- %button.retry-uploading-link{ type: 'button' } Try again
+ %button.retry-uploading-link{ type: 'button' }= _("Try again")
or
- %button.attach-new-file.markdown-selector{ type: 'button' } attach a new file
+ %button.attach-new-file.markdown-selector{ type: 'button' }= _("attach a new file")
%button.markdown-selector.button-attach-file{ type: 'button', tabindex: '-1' }
= icon('file-image-o', class: 'toolbar-button-icon')
- Attach a file
+ = _("Attach a file")
- %button.btn.btn-default.btn-sm.hide.button-cancel-uploading-files{ type: 'button' } Cancel
+ %button.btn.btn-default.btn-sm.hide.button-cancel-uploading-files{ type: 'button' }= _("Cancel")
diff --git a/app/views/shared/notes/_note.html.haml b/app/views/shared/notes/_note.html.haml
index e125d7f108a..cb5c64fb91d 100644
--- a/app/views/shared/notes/_note.html.haml
+++ b/app/views/shared/notes/_note.html.haml
@@ -62,7 +62,7 @@
= render 'award_emoji/awards_block', awardable: note, inline: false
- if note.system
.system-note-commit-list-toggler.hide
- Toggle commit list
+ = _("Toggle commit list")
%i.fa.fa-angle-down
- if note.attachment.url
.note-attachment
@@ -74,5 +74,5 @@
= icon('paperclip')
= note.attachment_identifier
= link_to delete_attachment_project_note_path(note.project, note),
- title: 'Delete this attachment', method: :delete, remote: true, data: { confirm: 'Are you sure you want to remove the attachment?' }, class: 'danger js-note-attachment-delete' do
+ title: _('Delete this attachment'), method: :delete, remote: true, data: { confirm: _('Are you sure you want to remove the attachment?') }, class: 'danger js-note-attachment-delete' do
= icon('trash-o', class: 'cred')
diff --git a/app/views/shared/notes/_notes_with_form.html.haml b/app/views/shared/notes/_notes_with_form.html.haml
index 4c4050c6054..002189e6ecd 100644
--- a/app/views/shared/notes/_notes_with_form.html.haml
+++ b/app/views/shared/notes/_notes_with_form.html.haml
@@ -19,20 +19,14 @@
= render "shared/notes/form", view: diff_view, supports_autocomplete: autocomplete
- elsif !current_user
.disabled-comment.text-center.prepend-top-default
- Please
- = link_to "register", new_session_path(:user, redirect_to_referer: 'yes', anchor: 'register-pane'), class: 'js-register-link'
- or
- = link_to "sign in", new_session_path(:user, redirect_to_referer: 'yes'), class: 'js-sign-in-link'
- to comment
+ - link_to_register = link_to(_("register"), new_session_path(:user, redirect_to_referer: 'yes', anchor: 'register-pane'), class: 'js-register-link')
+ - link_to_sign_in = link_to(_("sign in"), new_session_path(:user, redirect_to_referer: 'yes'), class: 'js-sign-in-link')
+ = _("Please %{link_to_register} or %{link_to_sign_in} to comment").html_safe % { link_to_register: link_to_register, link_to_sign_in: link_to_sign_in }
- elsif discussion_locked
.disabled-comment.text-center.prepend-top-default
%span.issuable-note-warning
= sprite_icon('lock', size: 16, css_class: 'icon')
%span
- This
- = issuable.class.to_s.titleize.downcase
- is locked. Only
- %b project members
- can comment.
+ = _("This %{issuable} is locked. Only <strong>project members</strong> can comment.").html_safe % { issuable: issuable.class.to_s.titleize.downcase }
-# haml-lint:disable InlineJavaScript
%script.js-notes-data{ type: "application/json" }= initial_notes_data(autocomplete).to_json.html_safe
diff --git a/app/views/shared/snippets/_snippet.html.haml b/app/views/shared/snippets/_snippet.html.haml
index 5069e2e4ca6..42af97bc6af 100644
--- a/app/views/shared/snippets/_snippet.html.haml
+++ b/app/views/shared/snippets/_snippet.html.haml
@@ -25,7 +25,7 @@
#{snippet.to_reference} &middot;
authored #{time_ago_with_tooltip(snippet.created_at, placement: 'bottom', html_class: 'snippet-created-ago')}
by
- = link_to user_snippets_path(snippet.author) do
+ = link_to user_snippets_path(snippet.author), class: "js-user-link", data: { user_id: snippet.author.id } do
= snippet.author_name
- if link_project && snippet.project_id?
%span.d-none.d-sm-inline-block
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index d3cf21db335..223ddc80c88 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -140,3 +140,4 @@
- detect_repository_languages
- repository_cleanup
- delete_stored_files
+- import_issues_csv
diff --git a/app/workers/import_issues_csv_worker.rb b/app/workers/import_issues_csv_worker.rb
new file mode 100644
index 00000000000..d44fdfec8ae
--- /dev/null
+++ b/app/workers/import_issues_csv_worker.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class ImportIssuesCsvWorker
+ include ApplicationWorker
+
+ sidekiq_retries_exhausted do |job|
+ Upload.find(job['args'][2]).destroy
+ end
+
+ def perform(current_user_id, project_id, upload_id)
+ @user = User.find(current_user_id)
+ @project = Project.find(project_id)
+ @upload = Upload.find(upload_id)
+
+ importer = Issues::ImportCsvService.new(@user, @project, @upload.build_uploader)
+ importer.execute
+
+ @upload.destroy
+ end
+end
diff --git a/app/workers/update_head_pipeline_for_merge_request_worker.rb b/app/workers/update_head_pipeline_for_merge_request_worker.rb
index e8494ffa002..4ec2b9d8fbe 100644
--- a/app/workers/update_head_pipeline_for_merge_request_worker.rb
+++ b/app/workers/update_head_pipeline_for_merge_request_worker.rb
@@ -7,25 +7,8 @@ class UpdateHeadPipelineForMergeRequestWorker
queue_namespace :pipeline_processing
def perform(merge_request_id)
- merge_request = MergeRequest.find(merge_request_id)
-
- sha = merge_request.diff_head_sha
- pipeline = merge_request.all_pipelines(shas: sha).first
-
- return unless pipeline && pipeline.latest?
-
- if merge_request.diff_head_sha != pipeline.sha
- log_error_message_for(merge_request)
-
- return
+ MergeRequest.find_by_id(merge_request_id).try do |merge_request|
+ merge_request.update_head_pipeline
end
-
- merge_request.update_attribute(:head_pipeline_id, pipeline.id)
- end
-
- def log_error_message_for(merge_request)
- Rails.logger.error(
- "Outdated head pipeline for active merge request: id=#{merge_request.id}, source_branch=#{merge_request.source_branch}, diff_head_sha=#{merge_request.diff_head_sha}"
- )
end
end
diff --git a/changelogs/unreleased/40473-api-support-for-kubernetes-integration.yml b/changelogs/unreleased/40473-api-support-for-kubernetes-integration.yml
new file mode 100644
index 00000000000..5567aad6320
--- /dev/null
+++ b/changelogs/unreleased/40473-api-support-for-kubernetes-integration.yml
@@ -0,0 +1,5 @@
+---
+title: Add API Support for Kubernetes integration
+merge_request: 23922
+author:
+type: added
diff --git a/changelogs/unreleased/49231-import-issues-csv.yml b/changelogs/unreleased/49231-import-issues-csv.yml
new file mode 100644
index 00000000000..c10bd8143b2
--- /dev/null
+++ b/changelogs/unreleased/49231-import-issues-csv.yml
@@ -0,0 +1,5 @@
+---
+title: Add importing of issues from CSV file
+merge_request: 23532
+author:
+type: added
diff --git a/changelogs/unreleased/52446-hide-ado-project-banner-for-ci-file-or-ci-disabled.yml b/changelogs/unreleased/52446-hide-ado-project-banner-for-ci-file-or-ci-disabled.yml
new file mode 100644
index 00000000000..bd8d0699bd1
--- /dev/null
+++ b/changelogs/unreleased/52446-hide-ado-project-banner-for-ci-file-or-ci-disabled.yml
@@ -0,0 +1,5 @@
+---
+title: Don't show Auto DevOps enabled banner for projects with CI file or CI disabled
+merge_request: 24067
+author:
+type: other
diff --git a/changelogs/unreleased/53796-discard-draft-comment-button-to-easy-to-accidentally-hit-on-mobile.yml b/changelogs/unreleased/53796-discard-draft-comment-button-to-easy-to-accidentally-hit-on-mobile.yml
new file mode 100644
index 00000000000..083b5f21a52
--- /dev/null
+++ b/changelogs/unreleased/53796-discard-draft-comment-button-to-easy-to-accidentally-hit-on-mobile.yml
@@ -0,0 +1,5 @@
+---
+title: Removed discard draft comment button form notes
+merge_request: 24185
+author:
+type: removed
diff --git a/changelogs/unreleased/54142-pages-in-project-s-permission-should-be-named-pages-access-control.yml b/changelogs/unreleased/54142-pages-in-project-s-permission-should-be-named-pages-access-control.yml
new file mode 100644
index 00000000000..b45ebaa1a02
--- /dev/null
+++ b/changelogs/unreleased/54142-pages-in-project-s-permission-should-be-named-pages-access-control.yml
@@ -0,0 +1,5 @@
+---
+title: Make the Pages permission setting more clear
+merge_request: 23146
+author:
+type: changed
diff --git a/changelogs/unreleased/54311-fix-board-add-label.yml b/changelogs/unreleased/54311-fix-board-add-label.yml
new file mode 100644
index 00000000000..8fd8f7a0381
--- /dev/null
+++ b/changelogs/unreleased/54311-fix-board-add-label.yml
@@ -0,0 +1,5 @@
+---
+title: Fix error when creating labels in a new issue in the boards page
+merge_request: 24039
+author: Ruben Moya
+type: fixed
diff --git a/changelogs/unreleased/54981-extended-user-centric-tooltips-add-missing-cases.yml b/changelogs/unreleased/54981-extended-user-centric-tooltips-add-missing-cases.yml
new file mode 100644
index 00000000000..25ae6d88428
--- /dev/null
+++ b/changelogs/unreleased/54981-extended-user-centric-tooltips-add-missing-cases.yml
@@ -0,0 +1,5 @@
+---
+title: User Popovers for Commit Infos, Member Lists and Snippets
+merge_request: 24132
+author:
+type: added
diff --git a/changelogs/unreleased/55192-about-link-in-new-window.yml b/changelogs/unreleased/55192-about-link-in-new-window.yml
new file mode 100644
index 00000000000..b686150942b
--- /dev/null
+++ b/changelogs/unreleased/55192-about-link-in-new-window.yml
@@ -0,0 +1,5 @@
+---
+title: Resolve About this feature link should open in new window
+merge_request: 24149
+author:
+type: fixed
diff --git a/changelogs/unreleased/55670-remove-app-views-shared-issuable-_filter-html-haml.yml b/changelogs/unreleased/55670-remove-app-views-shared-issuable-_filter-html-haml.yml
new file mode 100644
index 00000000000..9d37f798250
--- /dev/null
+++ b/changelogs/unreleased/55670-remove-app-views-shared-issuable-_filter-html-haml.yml
@@ -0,0 +1,5 @@
+---
+title: Remove app/views/shared/issuable/_filter.html.haml
+merge_request: 24008
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/55721-externalization-for-pipeline-tags.yml b/changelogs/unreleased/55721-externalization-for-pipeline-tags.yml
new file mode 100644
index 00000000000..4062300e73f
--- /dev/null
+++ b/changelogs/unreleased/55721-externalization-for-pipeline-tags.yml
@@ -0,0 +1,5 @@
+---
+title: Correctly externalize pipeline tags
+merge_request: 24028
+author:
+type: fixed
diff --git a/changelogs/unreleased/deprecated-migration-inheritance-2.yml b/changelogs/unreleased/deprecated-migration-inheritance-2.yml
new file mode 100644
index 00000000000..467a521dbd4
--- /dev/null
+++ b/changelogs/unreleased/deprecated-migration-inheritance-2.yml
@@ -0,0 +1,5 @@
+---
+title: ActiveRecord::Migration -> ActiveRecord::Migration[5.0] for AddIndexesToCiBuildsAndPipelines
+merge_request: 24167
+author: Jasper Maes
+type: other
diff --git a/changelogs/unreleased/gt-externalize-app-views-shared-notes.yml b/changelogs/unreleased/gt-externalize-app-views-shared-notes.yml
new file mode 100644
index 00000000000..39ca6b67a54
--- /dev/null
+++ b/changelogs/unreleased/gt-externalize-app-views-shared-notes.yml
@@ -0,0 +1,5 @@
+---
+title: Externalize strings from `/app/views/shared/notes`
+merge_request: 23696
+author: Tao Wang
+type: other
diff --git a/changelogs/unreleased/include-project.yml b/changelogs/unreleased/include-project.yml
new file mode 100644
index 00000000000..c63ac490d21
--- /dev/null
+++ b/changelogs/unreleased/include-project.yml
@@ -0,0 +1,5 @@
+---
+title: Allow to include files from another projects in gitlab-ci.yml
+merge_request: 24101
+author:
+type: added
diff --git a/changelogs/unreleased/knative-rbac-check.yml b/changelogs/unreleased/knative-rbac-check.yml
new file mode 100644
index 00000000000..0c40bb46e7f
--- /dev/null
+++ b/changelogs/unreleased/knative-rbac-check.yml
@@ -0,0 +1,5 @@
+---
+title: Require Knative to be installed only on an RBAC kubernetes cluster
+merge_request: 23807
+author: Chris Baumbauer
+type: changed
diff --git a/changelogs/unreleased/sh-fix-clone-url-for-https.yml b/changelogs/unreleased/sh-fix-clone-url-for-https.yml
deleted file mode 100644
index 6a17d566685..00000000000
--- a/changelogs/unreleased/sh-fix-clone-url-for-https.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix clone URL not showing if protocol is HTTPS
-merge_request: 24131
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-fix-issue-55914.yml b/changelogs/unreleased/sh-fix-issue-55914.yml
new file mode 100644
index 00000000000..f6f372f59c7
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-issue-55914.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Bitbucket Server import only including first 25 pull requests
+merge_request: 24178
+author:
+type: fixed
diff --git a/changelogs/unreleased/suggestion-dashes.yml b/changelogs/unreleased/suggestion-dashes.yml
new file mode 100644
index 00000000000..e99ab30b263
--- /dev/null
+++ b/changelogs/unreleased/suggestion-dashes.yml
@@ -0,0 +1,5 @@
+---
+title: Fixed diff suggestions removing dashes
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/user-update-head-pipeline-worker.yml b/changelogs/unreleased/user-update-head-pipeline-worker.yml
new file mode 100644
index 00000000000..fd88697f239
--- /dev/null
+++ b/changelogs/unreleased/user-update-head-pipeline-worker.yml
@@ -0,0 +1,5 @@
+---
+title: Refactor the logic of updating head pipelines for merge requests
+merge_request: 23502
+author:
+type: other
diff --git a/config/initializers/ar_mysql_jsonb_support.rb b/config/initializers/ar_mysql_jsonb_support.rb
new file mode 100644
index 00000000000..63a0b05119a
--- /dev/null
+++ b/config/initializers/ar_mysql_jsonb_support.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'active_record/connection_adapters/abstract_mysql_adapter'
+require 'active_record/connection_adapters/mysql/schema_definitions'
+
+# MySQL (5.6) and MariaDB (10.1) are currently supported versions within GitLab,
+# Since they do not support native `json` datatype we force to emulate it as `text`
+
+if Gitlab::Database.mysql?
+ module ActiveRecord
+ module ConnectionAdapters
+ class AbstractMysqlAdapter
+ JSON_DATASIZE = 1.megabyte
+
+ NATIVE_DATABASE_TYPES.merge!(
+ json: { name: "text", limit: JSON_DATASIZE },
+ jsonb: { name: "text", limit: JSON_DATASIZE }
+ )
+ end
+
+ module MySQL
+ module ColumnMethods
+ # We add `jsonb` helper, as `json` is already defined for `MySQL` since Rails 5
+ def jsonb(*args, **options)
+ args.each { |name| column(name, :json, options) }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/config/routes/project.rb b/config/routes/project.rb
index 03c95b61e51..cf5a57300cf 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -361,6 +361,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
collection do
post :bulk_update
+ post :import_csv
end
end
@@ -445,6 +446,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
# its preferable to keep it below all other project routes
draw :wiki
draw :repository
+
+ namespace :settings do
+ resource :operations, only: [:show, :update]
+ end
end
resources(:projects,
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index 3ee32678f34..3e8c218052d 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -85,3 +85,4 @@
- [repository_cleanup, 1]
- [delete_stored_files, 1]
- [remote_mirror_notification, 2]
+ - [import_issues_csv, 2]
diff --git a/db/fixtures/development/14_pipelines.rb b/db/fixtures/development/14_pipelines.rb
index bdc0a2db7db..db043e39d2c 100644
--- a/db/fixtures/development/14_pipelines.rb
+++ b/db/fixtures/development/14_pipelines.rb
@@ -102,14 +102,15 @@ class Gitlab::Seeder::Pipelines
[]
end
-
def create_pipeline!(project, ref, commit)
project.ci_pipelines.create!(sha: commit.id, ref: ref, source: :push)
end
def build_create!(pipeline, opts = {})
attributes = job_attributes(pipeline, opts)
- .merge(commands: '$ build command')
+
+ attributes[:options] ||= {}
+ attributes[:options][:script] = 'build command'
Ci::Build.create!(attributes).tap do |build|
# We need to set build trace and artifacts after saving a build
diff --git a/db/migrate/20181119132520_add_indexes_to_ci_builds_and_pipelines.rb b/db/migrate/20181119132520_add_indexes_to_ci_builds_and_pipelines.rb
index adbc3928b26..cb01fa113eb 100644
--- a/db/migrate/20181119132520_add_indexes_to_ci_builds_and_pipelines.rb
+++ b/db/migrate/20181119132520_add_indexes_to_ci_builds_and_pipelines.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class AddIndexesToCiBuildsAndPipelines < ActiveRecord::Migration
+class AddIndexesToCiBuildsAndPipelines < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
diff --git a/db/migrate/20181212171634_create_error_tracking_settings.rb b/db/migrate/20181212171634_create_error_tracking_settings.rb
new file mode 100644
index 00000000000..18c38bd2c47
--- /dev/null
+++ b/db/migrate/20181212171634_create_error_tracking_settings.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class CreateErrorTrackingSettings < ActiveRecord::Migration[5.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ create_table :project_error_tracking_settings, id: :int, primary_key: :project_id, default: nil do |t|
+ t.boolean :enabled, null: false, default: true
+ t.string :api_url, null: false
+ t.string :encrypted_token
+ t.string :encrypted_token_iv
+ t.foreign_key :projects, column: :project_id, on_delete: :cascade
+ end
+ end
+end
diff --git a/db/migrate/20181219145521_add_options_to_build_metadata.rb b/db/migrate/20181219145521_add_options_to_build_metadata.rb
new file mode 100644
index 00000000000..dc9569babc2
--- /dev/null
+++ b/db/migrate/20181219145521_add_options_to_build_metadata.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class AddOptionsToBuildMetadata < ActiveRecord::Migration[5.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ add_column :ci_builds_metadata, :config_options, :jsonb
+ add_column :ci_builds_metadata, :config_variables, :jsonb
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 97daf8ee617..87826881d58 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -374,6 +374,8 @@ ActiveRecord::Schema.define(version: 20190103140724) do
t.integer "project_id", null: false
t.integer "timeout"
t.integer "timeout_source", default: 1, null: false
+ t.jsonb "config_options"
+ t.jsonb "config_variables"
t.index ["build_id"], name: "index_ci_builds_metadata_on_build_id", unique: true, using: :btree
t.index ["project_id"], name: "index_ci_builds_metadata_on_project_id", using: :btree
end
@@ -1571,6 +1573,13 @@ ActiveRecord::Schema.define(version: 20190103140724) do
t.index ["project_id", "deploy_token_id"], name: "index_project_deploy_tokens_on_project_id_and_deploy_token_id", unique: true, using: :btree
end
+ create_table "project_error_tracking_settings", primary_key: "project_id", id: :integer, force: :cascade do |t|
+ t.boolean "enabled", default: true, null: false
+ t.string "api_url", null: false
+ t.string "encrypted_token"
+ t.string "encrypted_token_iv"
+ end
+
create_table "project_features", force: :cascade do |t|
t.integer "project_id", null: false
t.integer "merge_requests_access_level"
@@ -2432,6 +2441,7 @@ ActiveRecord::Schema.define(version: 20190103140724) do
add_foreign_key "project_custom_attributes", "projects", on_delete: :cascade
add_foreign_key "project_deploy_tokens", "deploy_tokens", on_delete: :cascade
add_foreign_key "project_deploy_tokens", "projects", on_delete: :cascade
+ add_foreign_key "project_error_tracking_settings", "projects", on_delete: :cascade
add_foreign_key "project_features", "projects", name: "fk_18513d9b92", on_delete: :cascade
add_foreign_key "project_group_links", "projects", name: "fk_daa8cee94c", on_delete: :cascade
add_foreign_key "project_import_data", "projects", name: "fk_ffb9ee3a10", on_delete: :cascade
diff --git a/doc/api/README.md b/doc/api/README.md
index fd5e88cb9d5..d481d0699e7 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -194,13 +194,13 @@ You can use a [personal access token][pat] to authenticate with the API by passi
Example of using the personal access token in a parameter:
```shell
-curl https://gitlab.example.com/api/v4/projects?private_token=9koXpg98eAheJpvBs5tK
+curl https://gitlab.example.com/api/v4/projects?private_token=<your_access_token>
```
Example of using the personal access token in a header:
```shell
-curl --header "Private-Token: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects
+curl --header "Private-Token: <your_access_token>" https://gitlab.example.com/api/v4/projects
```
Read more about [personal access tokens][pat].
@@ -319,22 +319,22 @@ Example of a valid API call and a request using cURL with sudo request,
providing a username:
```
-GET /projects?private_token=9koXpg98eAheJpvBs5tK&sudo=username
+GET /projects?private_token=<your_access_token>&sudo=username
```
```shell
-curl --header "Private-Token: 9koXpg98eAheJpvBs5tK" --header "Sudo: username" "https://gitlab.example.com/api/v4/projects"
+curl --header "Private-Token: <your_access_token>" --header "Sudo: username" "https://gitlab.example.com/api/v4/projects"
```
Example of a valid API call and a request using cURL with sudo request,
providing an ID:
```
-GET /projects?private_token=9koXpg98eAheJpvBs5tK&sudo=23
+GET /projects?private_token=<your_access_token>&sudo=23
```
```shell
-curl --header "Private-Token: 9koXpg98eAheJpvBs5tK" --header "Sudo: 23" "https://gitlab.example.com/api/v4/projects"
+curl --header "Private-Token: <your_access_token>" --header "Sudo: 23" "https://gitlab.example.com/api/v4/projects"
```
## Status codes
@@ -383,7 +383,7 @@ resources you can pass the following parameters:
In the example below, we list 50 [namespaces](namespaces.md) per page.
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/namespaces?per_page=50
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/namespaces?per_page=50
```
### Pagination Link header
@@ -397,7 +397,7 @@ and we request the second page (`page=2`) of [comments](notes.md) of the issue
with ID `8` which belongs to the project with ID `8`:
```bash
-curl --head --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/8/issues/8/notes?per_page=3&page=2
+curl --head --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/8/issues/8/notes?per_page=3&page=2
```
The response will then be:
@@ -465,7 +465,7 @@ We can call the API with `array` and `hash` types parameters as shown below:
`import_sources` is a parameter of type `array`:
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" \
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
-d "import_sources[]=github" \
-d "import_sources[]=bitbucket" \
"https://gitlab.example.com/api/v4/some_endpoint
@@ -476,7 +476,7 @@ curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" \
`override_params` is a parameter of type `hash`:
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" \
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
--form "namespace=email" \
--form "path=impapi" \
--form "file=@/path/to/somefile.txt"
diff --git a/doc/api/access_requests.md b/doc/api/access_requests.md
index 4b2014ca843..973c3968d90 100644
--- a/doc/api/access_requests.md
+++ b/doc/api/access_requests.md
@@ -28,8 +28,8 @@ GET /projects/:id/access_requests
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/:id/access_requests
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/access_requests
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/access_requests
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/:id/access_requests
```
Example response:
@@ -69,8 +69,8 @@ POST /projects/:id/access_requests
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/:id/access_requests
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/access_requests
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/access_requests
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/:id/access_requests
```
Example response:
@@ -102,8 +102,8 @@ PUT /projects/:id/access_requests/:user_id/approve
| `access_level` | integer | no | A valid access level (defaults: `30`, developer access level) |
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/:id/access_requests/:user_id/approve?access_level=20
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/access_requests/:user_id/approve?access_level=20
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/access_requests/:user_id/approve?access_level=20
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/:id/access_requests/:user_id/approve?access_level=20
```
Example response:
@@ -134,6 +134,6 @@ DELETE /projects/:id/access_requests/:user_id
| `user_id` | integer | yes | The user ID of the access requester |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/:id/access_requests/:user_id
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/access_requests/:user_id
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/access_requests/:user_id
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/:id/access_requests/:user_id
```
diff --git a/doc/api/applications.md b/doc/api/applications.md
index d74a3cdf5c1..7f95c136168 100644
--- a/doc/api/applications.md
+++ b/doc/api/applications.md
@@ -23,7 +23,7 @@ POST /applications
| `scopes` | string | yes | The scopes of the application |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --data "name=MyApplication&redirect_uri=http://redirect.uri&scopes=" https://gitlab.example.com/api/v4/applications
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --data "name=MyApplication&redirect_uri=http://redirect.uri&scopes=" https://gitlab.example.com/api/v4/applications
```
Example response:
@@ -47,7 +47,7 @@ GET /applications
```
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/applications
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/applications
```
Example response:
@@ -80,5 +80,5 @@ Parameters:
- `id` (required) - The id of the application (not the application_id)
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/applications/:id
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/applications/:id
```
diff --git a/doc/api/award_emoji.md b/doc/api/award_emoji.md
index 3f9542d6653..41e39c31069 100644
--- a/doc/api/award_emoji.md
+++ b/doc/api/award_emoji.md
@@ -27,7 +27,7 @@ Parameters:
| `awardable_id` | integer | yes | The ID (`iid` for merge requests/issues, `id` for snippets) of an awardable |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/80/award_emoji
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/issues/80/award_emoji
```
Example Response:
@@ -88,7 +88,7 @@ Parameters:
| `award_id` | integer | yes | The ID of the award emoji |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/80/award_emoji/1
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/issues/80/award_emoji/1
```
Example Response:
@@ -131,7 +131,7 @@ Parameters:
| `name` | string | yes | The name of the emoji, without colons |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/80/award_emoji?name=blowfish
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/issues/80/award_emoji?name=blowfish
```
Example Response:
@@ -175,7 +175,7 @@ Parameters:
| `award_id` | integer | yes | The ID of an award_emoji |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/80/award_emoji/344
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/issues/80/award_emoji/344
```
## Award Emoji on Notes
@@ -201,7 +201,7 @@ Parameters:
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/80/notes/1/award_emoji
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/issues/80/notes/1/award_emoji
```
Example Response:
@@ -243,7 +243,7 @@ Parameters:
| `award_id` | integer | yes | The ID of the award emoji |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/80/notes/1/award_emoji/2
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/issues/80/notes/1/award_emoji/2
```
Example Response:
@@ -283,7 +283,7 @@ Parameters:
| `name` | string | yes | The name of the emoji, without colons |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/80/notes/1/award_emoji?name=rocket
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/issues/80/notes/1/award_emoji?name=rocket
```
Example Response:
@@ -326,7 +326,7 @@ Parameters:
| `award_id` | integer | yes | The ID of an award_emoji |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/80/award_emoji/345
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/issues/80/award_emoji/345
```
[ce-4575]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4575
diff --git a/doc/api/boards.md b/doc/api/boards.md
index 5f006f4f012..2a2622736c3 100644
--- a/doc/api/boards.md
+++ b/doc/api/boards.md
@@ -18,7 +18,7 @@ GET /projects/:id/boards
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/boards
```
Example response:
@@ -87,7 +87,7 @@ GET /projects/:id/boards/:board_id
| `board_id` | integer | yes | The ID of a board |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/boards/1
```
Example response:
@@ -156,7 +156,7 @@ GET /projects/:id/boards/:board_id/lists
| `board_id` | integer | yes | The ID of a board |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1/lists
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/boards/1/lists
```
Example response:
@@ -208,7 +208,7 @@ GET /projects/:id/boards/:board_id/lists/:list_id
| `list_id`| integer | yes | The ID of a board's list |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1/lists/1
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/boards/1/lists/1
```
Example response:
@@ -240,7 +240,7 @@ POST /projects/:id/boards/:board_id/lists
| `label_id` | integer | yes | The ID of a label |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1/lists?label_id=5
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/boards/1/lists?label_id=5
```
Example response:
@@ -273,7 +273,7 @@ PUT /projects/:id/boards/:board_id/lists/:list_id
| `position` | integer | yes | The position of the list |
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1/lists/1?position=2
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/boards/1/lists/1?position=2
```
Example response:
@@ -305,5 +305,5 @@ DELETE /projects/:id/boards/:board_id/lists/:list_id
| `list_id` | integer | yes | The ID of a board's list |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1/lists/1
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/boards/1/lists/1
```
diff --git a/doc/api/branches.md b/doc/api/branches.md
index 4abf0639eb0..3b55154887d 100644
--- a/doc/api/branches.md
+++ b/doc/api/branches.md
@@ -16,7 +16,7 @@ GET /projects/:id/repository/branches
| `search` | string | no | Return list of branches matching the search criteria. |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/repository/branches
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/repository/branches
```
Example response:
@@ -66,7 +66,7 @@ GET /projects/:id/repository/branches/:branch
| `branch` | string | yes | The name of the branch |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/repository/branches/master
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/repository/branches/master
```
Example response:
@@ -111,7 +111,7 @@ PUT /projects/:id/repository/branches/:branch/protect
```
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/repository/branches/master/protect?developers_can_push=true&developers_can_merge=true
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/repository/branches/master/protect?developers_can_push=true&developers_can_merge=true
```
| Attribute | Type | Required | Description |
@@ -163,7 +163,7 @@ PUT /projects/:id/repository/branches/:branch/unprotect
```
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/repository/branches/master/unprotect
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/repository/branches/master/unprotect
```
| Attribute | Type | Required | Description |
@@ -213,7 +213,7 @@ POST /projects/:id/repository/branches
| `ref` | string | yes | The branch name or commit SHA to create branch from |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/repository/branches?branch=newbranch&ref=master"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/branches?branch=newbranch&ref=master"
```
Example response:
@@ -259,7 +259,7 @@ DELETE /projects/:id/repository/branches/:branch
In case of an error, an explaining message is provided.
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/repository/branches/newbranch"
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/branches/newbranch"
```
## Delete merged branches
@@ -278,5 +278,5 @@ DELETE /projects/:id/repository/merged_branches
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/repository/merged_branches"
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/merged_branches"
```
diff --git a/doc/api/broadcast_messages.md b/doc/api/broadcast_messages.md
index a8a248a17f4..fe370682308 100644
--- a/doc/api/broadcast_messages.md
+++ b/doc/api/broadcast_messages.md
@@ -13,7 +13,7 @@ GET /broadcast_messages
```
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/broadcast_messages
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/broadcast_messages
```
Example response:
@@ -43,7 +43,7 @@ GET /broadcast_messages/:id
| `id` | integer | yes | Broadcast message ID |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/broadcast_messages/1
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/broadcast_messages/1
```
Example response:
@@ -75,7 +75,7 @@ POST /broadcast_messages
| `font` | string | no | Foreground color hex code |
```bash
-curl --data "message=Deploy in progress&color=#cecece" --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/broadcast_messages
+curl --data "message=Deploy in progress&color=#cecece" --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/broadcast_messages
```
Example response:
@@ -108,7 +108,7 @@ PUT /broadcast_messages/:id
| `font` | string | no | Foreground color hex code |
```bash
-curl --request PUT --data "message=Update message&color=#000" --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/broadcast_messages/1
+curl --request PUT --data "message=Update message&color=#000" --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/broadcast_messages/1
```
Example response:
@@ -136,5 +136,5 @@ DELETE /broadcast_messages/:id
| `id` | integer | yes | Broadcast message ID |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/broadcast_messages/1
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/broadcast_messages/1
```
diff --git a/doc/api/commits.md b/doc/api/commits.md
index 6c16216429d..14742f034e0 100644
--- a/doc/api/commits.md
+++ b/doc/api/commits.md
@@ -20,7 +20,7 @@ GET /projects/:id/repository/commits
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/repository/commits"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/commits"
```
Example response:
@@ -127,7 +127,7 @@ PAYLOAD=$(cat << 'JSON'
}
JSON
)
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --header "Content-Type: application/json" --data "$PAYLOAD" https://gitlab.example.com/api/v4/projects/1/repository/commits
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --header "Content-Type: application/json" --data "$PAYLOAD" https://gitlab.example.com/api/v4/projects/1/repository/commits
```
Example response:
@@ -173,7 +173,7 @@ Parameters:
| `stats` | boolean | no | Include commit stats. Default is true |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/repository/commits/master
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/commits/master
```
Example response:
@@ -229,7 +229,7 @@ Parameters:
| `type` | string | no | The scope of commits. Possible values `branch`, `tag`, `all`. Default is `all`. |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/repository/commits/5937ac0a7beb003549fc5fd26fc247adbce4a52e/refs?type=all"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/commits/5937ac0a7beb003549fc5fd26fc247adbce4a52e/refs?type=all"
```
Example response:
@@ -263,7 +263,7 @@ Parameters:
| `branch` | string | yes | The name of the branch |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form "branch=master" "https://gitlab.example.com/api/v4/projects/5/repository/commits/master/cherry_pick"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "branch=master" "https://gitlab.example.com/api/v4/projects/5/repository/commits/master/cherry_pick"
```
Example response:
@@ -307,7 +307,7 @@ Parameters:
| `branch` | string | yes | Target branch name |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form "branch=master" "https://gitlab.example.com/api/v4/projects/5/repository/commits/a738f717824ff53aebad8b090c1b79a14f2bd9e8/revert"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "branch=master" "https://gitlab.example.com/api/v4/projects/5/repository/commits/a738f717824ff53aebad8b090c1b79a14f2bd9e8/revert"
```
Example response:
@@ -345,7 +345,7 @@ Parameters:
| `sha` | string | yes | The commit hash or name of a repository branch or tag |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/repository/commits/master/diff"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/commits/master/diff"
```
Example response:
@@ -381,7 +381,7 @@ Parameters:
| `sha` | string | yes | The commit hash or name of a repository branch or tag |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/repository/commits/master/comments"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/commits/master/comments"
```
Example response:
@@ -434,7 +434,7 @@ POST /projects/:id/repository/commits/:sha/comments
| `line_type` | string | no | The line type. Takes `new` or `old` as arguments |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form "note=Nice picture man\!" --form "path=dudeism.md" --form "line=11" --form "line_type=new" https://gitlab.example.com/api/v4/projects/17/repository/commits/18f3e63d05582537db6d183d9d557be09e1f90c8/comments
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "note=Nice picture man\!" --form "path=dudeism.md" --form "line=11" --form "line_type=new" https://gitlab.example.com/api/v4/projects/17/repository/commits/18f3e63d05582537db6d183d9d557be09e1f90c8/comments
```
Example response:
@@ -480,7 +480,7 @@ GET /projects/:id/repository/commits/:sha/statuses
| `all` | boolean | no | Return all statuses, not only the latest ones
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/17/repository/commits/18f3e63d05582537db6d183d9d557be09e1f90c8/statuses
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/17/repository/commits/18f3e63d05582537db6d183d9d557be09e1f90c8/statuses
```
Example response:
@@ -556,7 +556,7 @@ POST /projects/:id/statuses/:sha
| `coverage` | float | no | The total code coverage
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/17/statuses/18f3e63d05582537db6d183d9d557be09e1f90c8?state=success"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/17/statuses/18f3e63d05582537db6d183d9d557be09e1f90c8?state=success"
```
Example response:
@@ -603,7 +603,7 @@ GET /projects/:id/repository/commits/:sha/merge_requests
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/repository/commits/af5b13261899fb2c0db30abdd0af8b07cb44fdc5/merge_requests"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/commits/af5b13261899fb2c0db30abdd0af8b07cb44fdc5/merge_requests"
```
Example response:
diff --git a/doc/api/custom_attributes.md b/doc/api/custom_attributes.md
index 91d1b0e1520..d270b804ad5 100644
--- a/doc/api/custom_attributes.md
+++ b/doc/api/custom_attributes.md
@@ -20,7 +20,7 @@ GET /projects/:id/custom_attributes
| `id` | integer | yes | The ID of a resource |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/users/42/custom_attributes
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/users/42/custom_attributes
```
Example response:
@@ -54,7 +54,7 @@ GET /projects/:id/custom_attributes/:key
| `key` | string | yes | The key of the custom attribute |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/users/42/custom_attributes/location
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/users/42/custom_attributes/location
```
Example response:
@@ -84,7 +84,7 @@ PUT /projects/:id/custom_attributes/:key
| `value` | string | yes | The value of the custom attribute |
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --data "value=Greenland" https://gitlab.example.com/api/v4/users/42/custom_attributes/location
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --data "value=Greenland" https://gitlab.example.com/api/v4/users/42/custom_attributes/location
```
Example response:
@@ -112,5 +112,5 @@ DELETE /projects/:id/custom_attributes/:key
| `key` | string | yes | The key of the custom attribute |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/users/42/custom_attributes/location
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/users/42/custom_attributes/location
```
diff --git a/doc/api/deploy_key_multiple_projects.md b/doc/api/deploy_key_multiple_projects.md
index 127f9a196de..0c9e3e66cae 100644
--- a/doc/api/deploy_key_multiple_projects.md
+++ b/doc/api/deploy_key_multiple_projects.md
@@ -7,23 +7,23 @@ First, find the ID of the projects you're interested in, by either listing all
projects:
```
-curl --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' https://gitlab.example.com/api/v4/projects
+curl --header 'PRIVATE-TOKEN: <your_access_token>' https://gitlab.example.com/api/v4/projects
```
Or finding the ID of a group and then listing all projects in that group:
```
-curl --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' https://gitlab.example.com/api/v4/groups
+curl --header 'PRIVATE-TOKEN: <your_access_token>' https://gitlab.example.com/api/v4/groups
# For group 1234:
-curl --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' https://gitlab.example.com/api/v4/groups/1234
+curl --header 'PRIVATE-TOKEN: <your_access_token>' https://gitlab.example.com/api/v4/groups/1234
```
With those IDs, add the same deploy key to all:
```
for project_id in 321 456 987; do
- curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --header "Content-Type: application/json" \
+ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --header "Content-Type: application/json" \
--data '{"title": "my key", "key": "ssh-rsa AAAA..."}' https://gitlab.example.com/api/v4/projects/${project_id}/deploy_keys
done
```
diff --git a/doc/api/deploy_keys.md b/doc/api/deploy_keys.md
index 698fa22a438..1d7523fcc3d 100644
--- a/doc/api/deploy_keys.md
+++ b/doc/api/deploy_keys.md
@@ -9,7 +9,7 @@ GET /deploy_keys
```
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/deploy_keys"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/deploy_keys"
```
Example response:
@@ -44,7 +44,7 @@ GET /projects/:id/deploy_keys
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/deploy_keys"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/deploy_keys"
```
Example response:
@@ -84,7 +84,7 @@ Parameters:
| `key_id` | integer | yes | The ID of the deploy key |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/deploy_keys/11"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/deploy_keys/11"
```
Example response:
@@ -118,7 +118,7 @@ POST /projects/:id/deploy_keys
| `can_push` | boolean | no | Can deploy key push to the project's repository |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --header "Content-Type: application/json" --data '{"title": "My deploy key", "key": "ssh-rsa AAAA...", "can_push": "true"}' "https://gitlab.example.com/api/v4/projects/5/deploy_keys/"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --header "Content-Type: application/json" --data '{"title": "My deploy key", "key": "ssh-rsa AAAA...", "can_push": "true"}' "https://gitlab.example.com/api/v4/projects/5/deploy_keys/"
```
Example response:
@@ -148,7 +148,7 @@ PUT /projects/:id/deploy_keys/:key_id
| `can_push` | boolean | no | Can deploy key push to the project's repository |
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --header "Content-Type: application/json" --data '{"title": "New deploy key", "can_push": true}' "https://gitlab.example.com/api/v4/projects/5/deploy_keys/11"
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --header "Content-Type: application/json" --data '{"title": "New deploy key", "can_push": true}' "https://gitlab.example.com/api/v4/projects/5/deploy_keys/11"
```
Example response:
@@ -177,7 +177,7 @@ DELETE /projects/:id/deploy_keys/:key_id
| `key_id` | integer | yes | The ID of the deploy key |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/deploy_keys/13"
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/deploy_keys/13"
```
## Enable a deploy key
@@ -185,7 +185,7 @@ curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gi
Enables a deploy key for a project so this can be used. Returns the enabled key, with a status code 201 when successful.
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/deploy_keys/13/enable
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/deploy_keys/13/enable
```
| Attribute | Type | Required | Description |
diff --git a/doc/api/deployments.md b/doc/api/deployments.md
index 1963b0a21de..0a67f134d54 100644
--- a/doc/api/deployments.md
+++ b/doc/api/deployments.md
@@ -15,7 +15,7 @@ GET /projects/:id/deployments
| `sort` | string | no | Return deployments sorted in `asc` or `desc` order. Default is `asc` |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/deployments"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/deployments"
```
Example of response
@@ -155,7 +155,7 @@ GET /projects/:id/deployments/:deployment_id
| `deployment_id` | integer | yes | The ID of the deployment |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/deployments/1"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/deployments/1"
```
Example of response
diff --git a/doc/api/discussions.md b/doc/api/discussions.md
index 3538a577c8e..79090ea5254 100644
--- a/doc/api/discussions.md
+++ b/doc/api/discussions.md
@@ -97,7 +97,7 @@ GET /projects/:id/issues/:issue_iid/discussions
```
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions
```
### Get single issue discussion
@@ -117,7 +117,7 @@ Parameters:
| `discussion_id` | integer | yes | The ID of a discussion |
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7
```
### Create new issue discussion
@@ -139,7 +139,7 @@ Parameters:
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z (requires admin or project/group owner rights) |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions?body=comment
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions?body=comment
```
### Add note to existing issue discussion
@@ -162,7 +162,7 @@ Parameters:
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z (requires admin or project/group owner rights) |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
```
### Modify existing issue discussion note
@@ -184,7 +184,7 @@ Parameters:
| `body` | string | yes | The content of a discussion |
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?body=comment
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?body=comment
```
### Delete an issue discussion note
@@ -205,7 +205,7 @@ Parameters:
| `note_id` | integer | yes | The ID of a discussion note |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions/636
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions/636
```
## Snippets
@@ -303,7 +303,7 @@ GET /projects/:id/snippets/:snippet_id/discussions
```
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions
```
### Get single snippet discussion
@@ -323,7 +323,7 @@ Parameters:
| `discussion_id` | integer | yes | The ID of a discussion |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7
```
### Create new snippet discussion
@@ -345,7 +345,7 @@ Parameters:
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z (requires admin or project/group owner rights) |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions?body=comment
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions?body=comment
```
### Add note to existing snippet discussion
@@ -368,7 +368,7 @@ Parameters:
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z (requires admin or project/group owner rights) |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
```
### Modify existing snippet discussion note
@@ -390,7 +390,7 @@ Parameters:
| `body` | string | yes | The content of a discussion |
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?body=comment
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?body=comment
```
### Delete an snippet discussion note
@@ -411,7 +411,7 @@ Parameters:
| `note_id` | integer | yes | The ID of a discussion note |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/636
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/636
```
## Merge requests
@@ -562,7 +562,7 @@ Diff comments contain also position:
```
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions
```
### Get single merge request discussion
@@ -582,7 +582,7 @@ Parameters:
| `discussion_id` | integer | yes | The ID of a discussion |
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7
```
### Create new merge request discussion
@@ -617,7 +617,7 @@ Parameters:
| `position[y]` | integer | no | Y coordinate (for 'image' diff notes) |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions?body=comment
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions?body=comment
```
### Resolve a merge request discussion
@@ -638,7 +638,7 @@ Parameters:
| `resolved` | boolean | yes | Resolve/unresolve the discussion |
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7?resolved=true
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7?resolved=true
```
@@ -662,7 +662,7 @@ Parameters:
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z (requires admin or project/group owner rights) |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
```
### Modify an existing merge request discussion note
@@ -685,13 +685,13 @@ Parameters:
| `resolved` | boolean | no | Resolve/unresolve the note (exactly one of `body` or `resolved` must be set |
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?body=comment
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?body=comment
```
Resolving a note:
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?resolved=true
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?resolved=true
```
### Delete a merge request discussion note
@@ -712,7 +712,7 @@ Parameters:
| `note_id` | integer | yes | The ID of a discussion note |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions/636
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/discussions/636
```
## Commits
@@ -855,7 +855,7 @@ Diff comments contain also position:
```
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions
```
### Get single commit discussion
@@ -875,7 +875,7 @@ Parameters:
| `discussion_id` | integer | yes | The ID of a discussion |
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7
```
### Create new commit discussion
@@ -910,7 +910,7 @@ Parameters:
| `position[y]` | integer | no | Y coordinate (for 'image' diff notes) |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions?body=comment
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions?body=comment
```
### Add note to existing commit discussion
@@ -933,7 +933,7 @@ Parameters:
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z (requires admin or project/group owner rights) |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
```
### Modify an existing commit discussion note
@@ -955,13 +955,13 @@ Parameters:
| `body` | string | no | The content of a note |
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?body=comment
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?body=comment
```
Resolving a note:
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?resolved=true
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?resolved=true
```
### Delete a commit discussion note
@@ -982,5 +982,5 @@ Parameters:
| `note_id` | integer | yes | The ID of a discussion note |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions/636
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/commits/11/discussions/636
```
diff --git a/doc/api/environments.md b/doc/api/environments.md
index 29da4590a59..4a38dd73747 100644
--- a/doc/api/environments.md
+++ b/doc/api/environments.md
@@ -13,7 +13,7 @@ GET /projects/:id/environments
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/environments
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/environments
```
Example response:
@@ -46,7 +46,7 @@ POST /projects/:id/environments
| `external_url` | string | no | Place to link to for this environment |
```bash
-curl --data "name=deploy&external_url=https://deploy.example.gitlab.com" --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/environments"
+curl --data "name=deploy&external_url=https://deploy.example.gitlab.com" --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/environments"
```
Example response:
@@ -78,7 +78,7 @@ PUT /projects/:id/environments/:environments_id
| `external_url` | string | no | The new external_url |
```bash
-curl --request PUT --data "name=staging&external_url=https://staging.example.gitlab.com" --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/environments/1"
+curl --request PUT --data "name=staging&external_url=https://staging.example.gitlab.com" --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/environments/1"
```
Example response:
@@ -106,7 +106,7 @@ DELETE /projects/:id/environments/:environment_id
| `environment_id` | integer | yes | The ID of the environment |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/environments/1"
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/environments/1"
```
## Stop an environment
@@ -123,7 +123,7 @@ POST /projects/:id/environments/:environment_id/stop
| `environment_id` | integer | yes | The ID of the environment |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/environments/1/stop"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/environments/1/stop"
```
Example response:
diff --git a/doc/api/events.md b/doc/api/events.md
index e1c6b801a77..6dca8e52f69 100644
--- a/doc/api/events.md
+++ b/doc/api/events.md
@@ -71,7 +71,7 @@ Parameters:
Example request:
```
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/events?target_type=issue&action=created&after=2017-01-31&before=2017-03-01
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/events?target_type=issue&action=created&after=2017-01-31&before=2017-03-01
```
Example response:
@@ -143,7 +143,7 @@ Parameters:
| `sort` | string | no | Sort events in `asc` or `desc` order by `created_at`. Default is `desc` |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/users/:id/events
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/users/:id/events
```
Example response:
@@ -276,7 +276,7 @@ Parameters:
Example request:
```
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:project_id/events?target_type=issue&action=created&after=2017-01-31&before=2017-03-01
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/:project_id/events?target_type=issue&action=created&after=2017-01-31&before=2017-03-01
```
Example response:
diff --git a/doc/api/features.md b/doc/api/features.md
index 6ee1c36ef5b..59f1005ef72 100644
--- a/doc/api/features.md
+++ b/doc/api/features.md
@@ -14,7 +14,7 @@ GET /features
```
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/features
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/features
```
Example response:
@@ -65,7 +65,7 @@ Note that you can enable or disable a feature for both a `feature_group` and a
`user` with a single API call.
```bash
-curl --data "value=30" --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/features/new_library
+curl --data "value=30" --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/features/new_library
```
Example response:
diff --git a/doc/api/graphql/index.md b/doc/api/graphql/index.md
index 71922318227..ec48bf4940b 100644
--- a/doc/api/graphql/index.md
+++ b/doc/api/graphql/index.md
@@ -24,7 +24,7 @@ feature flag. You can enable the feature using the [features api][features-api]
For example:
```shell
-curl --data "value=100" --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/features/graphql
+curl --data "value=100" --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/features/graphql
```
## Available queries
diff --git a/doc/api/group_badges.md b/doc/api/group_badges.md
index f2353542a5c..f88689d80c6 100644
--- a/doc/api/group_badges.md
+++ b/doc/api/group_badges.md
@@ -28,7 +28,7 @@ GET /groups/:id/badges
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/:id/badges
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/badges
```
Example response:
@@ -68,7 +68,7 @@ GET /groups/:id/badges/:badge_id
| `badge_id` | integer | yes | The badge ID |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/:id/badges/:badge_id
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/badges/:badge_id
```
Example response:
@@ -99,7 +99,7 @@ POST /groups/:id/badges
| `image_url` | string | yes | URL of the badge image |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --data "link_url=https://gitlab.com/gitlab-org/gitlab-ce/commits/master&image_url=https://shields.io/my/badge1&position=0" https://gitlab.example.com/api/v4/groups/:id/badges
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --data "link_url=https://gitlab.com/gitlab-org/gitlab-ce/commits/master&image_url=https://shields.io/my/badge1&position=0" https://gitlab.example.com/api/v4/groups/:id/badges
```
Example response:
@@ -131,7 +131,7 @@ PUT /groups/:id/badges/:badge_id
| `image_url` | string | no | URL of the badge image |
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/:id/badges/:badge_id
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/badges/:badge_id
```
Example response:
@@ -161,7 +161,7 @@ DELETE /groups/:id/badges/:badge_id
| `badge_id` | integer | yes | The badge ID |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/:id/badges/:badge_id
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/badges/:badge_id
```
## Preview a badge from a group
@@ -179,7 +179,7 @@ GET /groups/:id/badges/render
| `image_url` | string | yes | URL of the badge image |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/:id/badges/render?link_url=http%3A%2F%2Fexample.com%2Fci_status.svg%3Fproject%3D%25%7Bproject_path%7D%26ref%3D%25%7Bdefault_branch%7D&image_url=https%3A%2F%2Fshields.io%2Fmy%2Fbadge
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/badges/render?link_url=http%3A%2F%2Fexample.com%2Fci_status.svg%3Fproject%3D%25%7Bproject_path%7D%26ref%3D%25%7Bdefault_branch%7D&image_url=https%3A%2F%2Fshields.io%2Fmy%2Fbadge
```
Example response:
diff --git a/doc/api/group_boards.md b/doc/api/group_boards.md
index 373904e50c4..9b0ac23b41c 100644
--- a/doc/api/group_boards.md
+++ b/doc/api/group_boards.md
@@ -18,7 +18,7 @@ GET /groups/:id/boards
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/5/boards
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/boards
```
Example response:
@@ -75,7 +75,7 @@ GET /groups/:id/boards/:board_id
| `board_id` | integer | yes | The ID of a board |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/5/boards/1
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/boards/1
```
Example response:
@@ -131,7 +131,7 @@ GET /groups/:id/boards/:board_id/lists
| `board_id` | integer | yes | The ID of a board |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/5/boards/1/lists
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/boards/1/lists
```
Example response:
@@ -183,7 +183,7 @@ GET /groups/:id/boards/:board_id/lists/:list_id
| `list_id` | integer | yes | The ID of a board's list |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/5/boards/1/lists/1
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/boards/1/lists/1
```
Example response:
@@ -215,7 +215,7 @@ POST /groups/:id/boards/:board_id/lists
| `label_id` | integer | yes | The ID of a label |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/5/boards/1/lists?label_id=5
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/boards/1/lists?label_id=5
```
Example response:
@@ -248,7 +248,7 @@ PUT /groups/:id/boards/:board_id/lists/:list_id
| `position` | integer | yes | The position of the list |
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/group/5/boards/1/lists/1?position=2
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/group/5/boards/1/lists/1?position=2
```
Example response:
@@ -280,5 +280,5 @@ DELETE /groups/:id/boards/:board_id/lists/:list_id
| `list_id` | integer | yes | The ID of a board's list |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/5/boards/1/lists/1
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/boards/1/lists/1
```
diff --git a/doc/api/group_level_variables.md b/doc/api/group_level_variables.md
index 33c6da08018..3551bfa3f8b 100644
--- a/doc/api/group_level_variables.md
+++ b/doc/api/group_level_variables.md
@@ -15,7 +15,7 @@ GET /groups/:id/variables
| `id` | integer/string | yes | The ID of a group or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
```
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/groups/1/variables"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/1/variables"
```
```json
@@ -45,7 +45,7 @@ GET /groups/:id/variables/:key
| `key` | string | yes | The `key` of a variable |
```
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/groups/1/variables/TEST_VARIABLE_1"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/1/variables/TEST_VARIABLE_1"
```
```json
@@ -71,7 +71,7 @@ POST /groups/:id/variables
| `protected` | boolean | no | Whether the variable is protected |
```
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/groups/1/variables" --form "key=NEW_VARIABLE" --form "value=new value"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/1/variables" --form "key=NEW_VARIABLE" --form "value=new value"
```
```json
@@ -98,7 +98,7 @@ PUT /groups/:id/variables/:key
| `protected` | boolean | no | Whether the variable is protected |
```
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/groups/1/variables/NEW_VARIABLE" --form "value=updated value"
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/1/variables/NEW_VARIABLE" --form "value=updated value"
```
```json
@@ -123,7 +123,7 @@ DELETE /groups/:id/variables/:key
| `key` | string | yes | The `key` of a variable |
```
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/groups/1/variables/VARIABLE_1"
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/1/variables/VARIABLE_1"
```
[ce-34519]: https://gitlab.com/gitlab-org/gitlab-ce/issues/34519
diff --git a/doc/api/group_milestones.md b/doc/api/group_milestones.md
index e396f4411e6..7be01ce9c6d 100644
--- a/doc/api/group_milestones.md
+++ b/doc/api/group_milestones.md
@@ -26,7 +26,7 @@ Parameters:
| `search` | string | optional | Return only milestones with a title or description matching the provided string |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/5/milestones
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/milestones
```
Example Response:
diff --git a/doc/api/groups.md b/doc/api/groups.md
index 59444a98086..2d9114c40ea 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -220,7 +220,7 @@ Parameters:
| `with_projects` | boolean | no | Include details from projects that belong to the specified group (defaults to `true`). |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/4
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/4
```
Example response:
@@ -375,7 +375,7 @@ Example response:
When adding the parameter `with_projects=false`, projects will not be returned.
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/4?with_projects=false
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/4?with_projects=false
```
Example response:
@@ -452,7 +452,7 @@ PUT /groups/:id
| `file_template_project_id` | integer | no | **(Premium)** The ID of a project to load custom file templates from |
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/groups/5?name=Experimental"
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/5?name=Experimental"
```
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 6a99c52234d..fb06119063f 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -52,7 +52,7 @@ GET /issues?my_reaction_emoji=star
| `updated_before` | datetime | no | Return issues updated on or before the given time |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/issues
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/issues
```
Example response:
@@ -166,7 +166,7 @@ GET /groups/:id/issues?my_reaction_emoji=star
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/4/issues
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/4/issues
```
Example response:
@@ -279,7 +279,7 @@ GET /projects/:id/issues?my_reaction_emoji=star
| `updated_before` | datetime | no | Return issues updated on or before the given time |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/4/issues
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/4/issues
```
Example response:
@@ -373,7 +373,7 @@ GET /projects/:id/issues/:issue_iid
| `issue_iid` | integer | yes | The internal ID of a project's issue |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/4/issues/41
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/4/issues/41
```
Example response:
@@ -476,7 +476,7 @@ POST /projects/:id/issues
| `discussion_to_resolve` | string | no | The ID of a discussion to resolve. This will fill in the issue with a default description and mark the discussion as resolved. Use in combination with `merge_request_to_resolve_discussions_of`. |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/4/issues?title=Issues%20with%20auth&labels=bug
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/4/issues?title=Issues%20with%20auth&labels=bug
```
Example response:
@@ -558,7 +558,7 @@ PUT /projects/:id/issues/:issue_iid
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/4/issues/85?state_event=close
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/4/issues/85?state_event=close
```
Example response:
@@ -635,7 +635,7 @@ DELETE /projects/:id/issues/:issue_iid
| `issue_iid` | integer | yes | The internal ID of a project's issue |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/4/issues/85
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/4/issues/85
```
## Move an issue
@@ -658,7 +658,7 @@ POST /projects/:id/issues/:issue_iid/move
| `to_project_id` | integer | yes | The ID of the new project |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form to_project_id=5 https://gitlab.example.com/api/v4/projects/4/issues/85/move
+curl --header "PRIVATE-TOKEN: <your_access_token>" --form to_project_id=5 https://gitlab.example.com/api/v4/projects/4/issues/85/move
```
Example response:
@@ -740,7 +740,7 @@ POST /projects/:id/issues/:issue_iid/subscribe
| `issue_iid` | integer | yes | The internal ID of a project's issue |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/subscribe
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/93/subscribe
```
Example response:
@@ -823,7 +823,7 @@ POST /projects/:id/issues/:issue_iid/unsubscribe
| `issue_iid` | integer | yes | The internal ID of a project's issue |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/unsubscribe
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/93/unsubscribe
```
Example response:
@@ -882,7 +882,7 @@ POST /projects/:id/issues/:issue_iid/todo
| `issue_iid` | integer | yes | The internal ID of a project's issue |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/todo
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/93/todo
```
Example response:
@@ -988,7 +988,7 @@ POST /projects/:id/issues/:issue_iid/time_estimate
| `duration` | string | yes | The duration in human format. e.g: 3h30m |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/time_estimate?duration=3h30m
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/93/time_estimate?duration=3h30m
```
Example response:
@@ -1016,7 +1016,7 @@ POST /projects/:id/issues/:issue_iid/reset_time_estimate
| `issue_iid` | integer | yes | The internal ID of a project's issue |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/reset_time_estimate
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/93/reset_time_estimate
```
Example response:
@@ -1045,7 +1045,7 @@ POST /projects/:id/issues/:issue_iid/add_spent_time
| `duration` | string | yes | The duration in human format. e.g: 3h30m |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/add_spent_time?duration=1h
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/93/add_spent_time?duration=1h
```
Example response:
@@ -1073,7 +1073,7 @@ POST /projects/:id/issues/:issue_iid/reset_spent_time
| `issue_iid` | integer | yes | The internal ID of a project's issue |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/reset_spent_time
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/93/reset_spent_time
```
Example response:
@@ -1099,7 +1099,7 @@ GET /projects/:id/issues/:issue_iid/time_stats
| `issue_iid` | integer | yes | The internal ID of a project's issue |
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/time_stats
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/93/time_stats
```
Example response:
@@ -1127,7 +1127,7 @@ GET /projects/:id/issues/:issue_id/related_merge_requests
| `issue_iid` | integer | yes | The internal ID of a project's issue |
```sh
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/11/related_merge_requests
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/issues/11/related_merge_requests
```
Example response:
@@ -1214,7 +1214,7 @@ GET /projects/:id/issues/:issue_iid/closed_by
| `issue_iid` | integer | yes | The internal ID of a project issue |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/11/closed_by
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/issues/11/closed_by
```
Example response:
@@ -1281,7 +1281,7 @@ GET /projects/:id/issues/:issue_iid/participants
| `issue_iid` | integer | yes | The internal ID of a project's issue |
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/participants
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/93/participants
```
Example response:
@@ -1326,7 +1326,7 @@ GET /projects/:id/issues/:issue_iid/user_agent_detail
| `issue_iid` | integer | yes | The internal ID of a project's issue |
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/user_agent_detail
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/93/user_agent_detail
```
Example response:
diff --git a/doc/api/jobs.md b/doc/api/jobs.md
index d2dd9c676e3..085e321b35f 100644
--- a/doc/api/jobs.md
+++ b/doc/api/jobs.md
@@ -14,7 +14,7 @@ GET /projects/:id/jobs
| `scope` | string **or** array of strings | no | Scope of jobs to show. Either one of or an array of the following: `created`, `pending`, `running`, `failed`, `success`, `canceled`, `skipped`, or `manual`. All jobs are returned if `scope` is not provided. |
```sh
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" 'https://gitlab.example.com/api/v4/projects/1/jobs?scope[]=pending&scope[]=running'
+curl --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/1/jobs?scope[]=pending&scope[]=running'
```
Example of response
@@ -147,7 +147,7 @@ GET /projects/:id/pipelines/:pipeline_id/jobs
| `scope` | string **or** array of strings | no | Scope of jobs to show. Either one of or an array of the following: `created`, `pending`, `running`, `failed`, `success`, `canceled`, `skipped`, or `manual`. All jobs are returned if `scope` is not provided. |
```sh
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" 'https://gitlab.example.com/api/v4/projects/1/pipelines/6/jobs?scope[]=pending&scope[]=running'
+curl --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/1/pipelines/6/jobs?scope[]=pending&scope[]=running'
```
Example of response
@@ -279,7 +279,7 @@ GET /projects/:id/jobs/:job_id
| `job_id` | integer | yes | The ID of a job. |
```sh
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/8"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/8"
```
Example of response
@@ -356,7 +356,7 @@ GET /projects/:id/jobs/:job_id/artifacts
Example requests:
```sh
-curl --location --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/8/artifacts"
+curl --location --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/8/artifacts"
```
Possible response status codes:
@@ -392,7 +392,7 @@ Parameters
Example requests:
```sh
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/artifacts/master/download?job=test"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/artifacts/master/download?job=test"
```
Possible response status codes:
@@ -427,7 +427,7 @@ Parameters
Example request:
```sh
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/5/artifacts/some/release/file.pdf"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/5/artifacts/some/release/file.pdf"
```
Possible response status codes:
@@ -462,7 +462,7 @@ Parameters:
Example request:
```sh
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/artifacts/master/raw/some/release/file.pdf?job=pdf"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/artifacts/master/raw/some/release/file.pdf?job=pdf"
```
Possible response status codes:
@@ -487,7 +487,7 @@ GET /projects/:id/jobs/:job_id/trace
| job_id | integer | yes | The ID of a job. |
```sh
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/8/trace"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/8/trace"
```
Possible response status codes:
@@ -511,7 +511,7 @@ POST /projects/:id/jobs/:job_id/cancel
| `job_id` | integer | yes | The ID of a job. |
```sh
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/1/cancel"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/1/cancel"
```
Example of response
@@ -559,7 +559,7 @@ POST /projects/:id/jobs/:job_id/retry
| `job_id` | integer | yes | The ID of a job. |
```sh
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/1/retry"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/1/retry"
```
Example of response
@@ -611,7 +611,7 @@ Parameters
Example of request
```sh
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/1/erase"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/1/erase"
```
Example of response
@@ -664,7 +664,7 @@ Parameters
Example request:
```sh
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/1/artifacts/keep"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/1/artifacts/keep"
```
Example response:
@@ -713,7 +713,7 @@ POST /projects/:id/jobs/:job_id/play
| `job_id` | integer | yes | The ID of a job. |
```sh
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/1/play"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/1/play"
```
Example of response
diff --git a/doc/api/labels.md b/doc/api/labels.md
index ec93cf50e7a..aec1a2c7592 100644
--- a/doc/api/labels.md
+++ b/doc/api/labels.md
@@ -13,7 +13,7 @@ GET /projects/:id/labels
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/labels
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/labels
```
Example response:
@@ -95,7 +95,7 @@ POST /projects/:id/labels
| `priority` | integer | no | The priority of the label. Must be greater or equal than zero or `null` to remove the priority. |
```bash
-curl --data "name=feature&color=#5843AD" --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/labels"
+curl --data "name=feature&color=#5843AD" --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/labels"
```
Example response:
@@ -128,7 +128,7 @@ DELETE /projects/:id/labels
| `name` | string | yes | The name of the label |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/labels?name=bug"
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/labels?name=bug"
```
## Edit an existing label
@@ -151,7 +151,7 @@ PUT /projects/:id/labels
```bash
-curl --request PUT --data "name=documentation&new_name=docs&color=#8E44AD&description=Documentation" --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/labels"
+curl --request PUT --data "name=documentation&new_name=docs&color=#8E44AD&description=Documentation" --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/labels"
```
Example response:
@@ -186,7 +186,7 @@ POST /projects/:id/labels/:label_id/subscribe
| `label_id` | integer or string | yes | The ID or title of a project's label |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/labels/1/subscribe
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/labels/1/subscribe
```
Example response:
@@ -221,5 +221,5 @@ POST /projects/:id/labels/:label_id/unsubscribe
| `label_id` | integer or string | yes | The ID or title of a project's label |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/labels/1/unsubscribe
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/labels/1/unsubscribe
```
diff --git a/doc/api/members.md b/doc/api/members.md
index bb4fae35f52..0593d2c20ea 100644
--- a/doc/api/members.md
+++ b/doc/api/members.md
@@ -28,8 +28,8 @@ GET /projects/:id/members
| `query` | string | no | A query string to search for members |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/:id/members
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/members
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/members
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/:id/members
```
Example response:
@@ -75,8 +75,8 @@ GET /projects/:id/members/all
| `query` | string | no | A query string to search for members |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/:id/members/all
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/members/all
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/members/all
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/:id/members/all
```
Example response:
@@ -131,8 +131,8 @@ GET /projects/:id/members/:user_id
| `user_id` | integer | yes | The user ID of the member |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/:id/members/:user_id
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/members/:user_id
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/members/:user_id
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/:id/members/:user_id
```
Example response:
@@ -167,8 +167,8 @@ POST /projects/:id/members
| `expires_at` | string | no | A date string in the format YEAR-MONTH-DAY |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --data "user_id=1&access_level=30" https://gitlab.example.com/api/v4/groups/:id/members
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --data "user_id=1&access_level=30" https://gitlab.example.com/api/v4/projects/:id/members
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --data "user_id=1&access_level=30" https://gitlab.example.com/api/v4/groups/:id/members
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --data "user_id=1&access_level=30" https://gitlab.example.com/api/v4/projects/:id/members
```
Example response:
@@ -203,8 +203,8 @@ PUT /projects/:id/members/:user_id
| `expires_at` | string | no | A date string in the format YEAR-MONTH-DAY |
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/:id/members/:user_id?access_level=40
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/members/:user_id?access_level=40
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/members/:user_id?access_level=40
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/:id/members/:user_id?access_level=40
```
Example response:
@@ -237,8 +237,8 @@ DELETE /projects/:id/members/:user_id
| `user_id` | integer | yes | The user ID of the member |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/:id/members/:user_id
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/members/:user_id
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/members/:user_id
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/:id/members/:user_id
```
## Give a group access to a project
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 9ff6c73b1b6..c9b271eada3 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -967,7 +967,7 @@ DELETE /projects/:id/merge_requests/:merge_request_iid
| `merge_request_iid` | integer | yes | The internal ID of the merge request |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/4/merge_requests/85
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/4/merge_requests/85
```
## Accept MR
@@ -1230,7 +1230,7 @@ PUT /projects/:id/merge_requests/:merge_request_iid/rebase
| `merge_request_iid` | integer | yes | The internal ID of the merge request |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/76/merge_requests/1/rebase
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/76/merge_requests/1/rebase
```
This is an asynchronous request. The API will return an empty `202 Accepted`
@@ -1286,7 +1286,7 @@ GET /projects/:id/merge_requests/:merge_request_iid/closes_issues
| `merge_request_iid` | integer | yes | The internal ID of the merge request |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/76/merge_requests/1/closes_issues
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/76/merge_requests/1/closes_issues
```
Example response when the GitLab issue tracker is used:
@@ -1362,7 +1362,7 @@ POST /projects/:id/merge_requests/:merge_request_iid/subscribe
| `merge_request_iid` | integer | yes | The internal ID of the merge request |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/17/subscribe
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/17/subscribe
```
Example response:
@@ -1483,7 +1483,7 @@ POST /projects/:id/merge_requests/:merge_request_iid/unsubscribe
| `merge_request_iid` | integer | yes | The internal ID of the merge request |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/17/unsubscribe
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/17/unsubscribe
```
Example response:
@@ -1604,7 +1604,7 @@ POST /projects/:id/merge_requests/:merge_request_iid/todo
| `merge_request_iid` | integer | yes | The internal ID of the merge request |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/27/todo
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/27/todo
```
Example response:
@@ -1707,7 +1707,7 @@ GET /projects/:id/merge_requests/:merge_request_iid/versions
| `merge_request_iid` | integer | yes | The internal ID of the merge request |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/merge_requests/1/versions
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/merge_requests/1/versions
```
Example response:
@@ -1749,7 +1749,7 @@ GET /projects/:id/merge_requests/:merge_request_iid/versions/:version_id
| `version_id` | integer | yes | The ID of the merge request diff version |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/merge_requests/1/versions/1
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/merge_requests/1/versions/1
```
Example response:
@@ -1816,7 +1816,7 @@ POST /projects/:id/merge_requests/:merge_request_iid/time_estimate
| `duration` | string | yes | The duration in human format. e.g: 3h30m |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/93/time_estimate?duration=3h30m
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/93/time_estimate?duration=3h30m
```
Example response:
@@ -1844,7 +1844,7 @@ POST /projects/:id/merge_requests/:merge_request_iid/reset_time_estimate
| `merge_request_iid` | integer | yes | The internal ID of a project's merge_request |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/93/reset_time_estimate
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/93/reset_time_estimate
```
Example response:
@@ -1873,7 +1873,7 @@ POST /projects/:id/merge_requests/:merge_request_iid/add_spent_time
| `duration` | string | yes | The duration in human format. e.g: 3h30m |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/93/add_spent_time?duration=1h
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/93/add_spent_time?duration=1h
```
Example response:
@@ -1901,7 +1901,7 @@ POST /projects/:id/merge_requests/:merge_request_iid/reset_spent_time
| `merge_request_iid` | integer | yes | The internal ID of a project's merge_request |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/93/reset_spent_time
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/93/reset_spent_time
```
Example response:
@@ -1927,7 +1927,7 @@ GET /projects/:id/merge_requests/:merge_request_iid/time_stats
| `merge_request_iid` | integer | yes | The internal ID of the merge request |
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/93/time_stats
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/93/time_stats
```
Example response:
diff --git a/doc/api/milestones.md b/doc/api/milestones.md
index 7ac97edc7ae..fa8f8a0bcf0 100644
--- a/doc/api/milestones.md
+++ b/doc/api/milestones.md
@@ -23,7 +23,7 @@ Parameters:
| `search` | string | optional | Return only milestones with a title or description matching the provided string |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/milestones
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/milestones
```
Example Response:
diff --git a/doc/api/namespaces.md b/doc/api/namespaces.md
index 656bf07bb55..b8bc4c40124 100644
--- a/doc/api/namespaces.md
+++ b/doc/api/namespaces.md
@@ -19,7 +19,7 @@ GET /namespaces
Example request:
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/namespaces
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/namespaces
```
Example response:
@@ -71,7 +71,7 @@ GET /namespaces?search=foobar
Example request:
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/namespaces?search=twitter
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/namespaces?search=twitter
```
Example response:
@@ -105,7 +105,7 @@ GET /namespaces/:id
Example request:
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/namespaces/2
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/namespaces/2
```
Example response:
@@ -125,7 +125,7 @@ Example response:
Example request:
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/namespaces/group1
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/namespaces/group1
```
Example response:
diff --git a/doc/api/notes.md b/doc/api/notes.md
index 9f6740ad86a..dd4e18b14e6 100644
--- a/doc/api/notes.md
+++ b/doc/api/notes.md
@@ -66,7 +66,7 @@ GET /projects/:id/issues/:issue_iid/notes?sort=asc&order_by=updated_at
```
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/notes
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/11/notes
```
### Get single issue note
@@ -84,7 +84,7 @@ Parameters:
- `note_id` (required) - The ID of an issue note
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/notes/1
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/11/notes/1
```
### Create new issue note
@@ -103,7 +103,7 @@ Parameters:
- `created_at` (optional) - Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z (requires admin or project/group owner rights)
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/notes?body=note
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/11/notes?body=note
```
### Modify existing issue note
@@ -122,7 +122,7 @@ Parameters:
- `body` (required) - The content of a note
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/notes?body=note
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/11/notes?body=note
```
### Delete an issue note
@@ -142,7 +142,7 @@ Parameters:
| `note_id` | integer | yes | The ID of a note |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/notes/636
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/11/notes/636
```
## Snippets
@@ -164,7 +164,7 @@ GET /projects/:id/snippets/:snippet_id/notes?sort=asc&order_by=updated_at
| `order_by` | string | no | Return snippet notes ordered by `created_at` or `updated_at` fields. Default is `created_at`
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/notes
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/snippets/11/notes
```
### Get single snippet note
@@ -201,7 +201,7 @@ Parameters:
```
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/notes/11
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/snippets/11/notes/11
```
### Create new snippet note
@@ -221,7 +221,7 @@ Parameters:
- `created_at` (optional) - Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippet/11/notes?body=note
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/snippet/11/notes?body=note
```
### Modify existing snippet note
@@ -240,7 +240,7 @@ Parameters:
- `body` (required) - The content of a note
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/notes?body=note
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/snippets/11/notes?body=note
```
### Delete a snippet note
@@ -260,7 +260,7 @@ Parameters:
| `note_id` | integer | yes | The ID of a note |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/52/notes/1659
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/snippets/52/notes/1659
```
## Merge Requests
@@ -282,7 +282,7 @@ GET /projects/:id/merge_requests/:merge_request_iid/notes?sort=asc&order_by=upda
| `order_by` | string | no | Return merge request notes ordered by `created_at` or `updated_at` fields. Default is `created_at`
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/notes
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/notes
```
### Get single merge request note
@@ -323,7 +323,7 @@ Parameters:
```
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/notes/1
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/notes/1
```
### Create new merge request note
@@ -359,7 +359,7 @@ Parameters:
- `body` (required) - The content of a note
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/notes?body=note
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/notes?body=note
```
### Delete a merge request note
@@ -379,5 +379,5 @@ Parameters:
| `note_id` | integer | yes | The ID of a note |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/7/notes/1602
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/7/notes/1602
```
diff --git a/doc/api/notification_settings.md b/doc/api/notification_settings.md
index 165b9a11c7a..e21e73c7dac 100644
--- a/doc/api/notification_settings.md
+++ b/doc/api/notification_settings.md
@@ -43,7 +43,7 @@ GET /notification_settings
```
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/notification_settings
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/notification_settings
```
Example response:
@@ -64,7 +64,7 @@ PUT /notification_settings
```
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/notification_settings?level=watch
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/notification_settings?level=watch
```
| Attribute | Type | Required | Description |
@@ -105,8 +105,8 @@ GET /projects/:id/notification_settings
```
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/5/notification_settings
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/8/notification_settings
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/notification_settings
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/8/notification_settings
```
| Attribute | Type | Required | Description |
@@ -131,8 +131,8 @@ PUT /projects/:id/notification_settings
```
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/5/notification_settings?level=watch
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/8/notification_settings?level=custom&new_note=true
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/notification_settings?level=watch
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/8/notification_settings?level=custom&new_note=true
```
| Attribute | Type | Required | Description |
diff --git a/doc/api/pages_domains.md b/doc/api/pages_domains.md
index da2ffcfe40a..4c41350dcdb 100644
--- a/doc/api/pages_domains.md
+++ b/doc/api/pages_domains.md
@@ -13,7 +13,7 @@ GET /pages/domains
```
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/pages/domains
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/pages/domains
```
```json
@@ -43,7 +43,7 @@ GET /projects/:id/pages/domains
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/pages/domains
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/pages/domains
```
```json
@@ -79,7 +79,7 @@ GET /projects/:id/pages/domains/:domain
| `domain` | string | yes | The domain |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/pages/domains/www.domain.example
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/pages/domains/www.domain.example
```
```json
@@ -90,7 +90,7 @@ curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/a
```
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example
```
```json
@@ -122,11 +122,11 @@ POST /projects/:id/pages/domains
| `key` | file/string | no | The certificate key in PEM format. |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form "domain=ssl.domain.example" --form "certificate=@/path/to/cert.pem" --form "key=@/path/to/key.pem" https://gitlab.example.com/api/v4/projects/5/pages/domains
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "domain=ssl.domain.example" --form "certificate=@/path/to/cert.pem" --form "key=@/path/to/key.pem" https://gitlab.example.com/api/v4/projects/5/pages/domains
```
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form "domain=ssl.domain.example" --form "certificate=$CERT_PEM" --form "key=$KEY_PEM" https://gitlab.example.com/api/v4/projects/5/pages/domains
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "domain=ssl.domain.example" --form "certificate=$CERT_PEM" --form "key=$KEY_PEM" https://gitlab.example.com/api/v4/projects/5/pages/domains
```
```json
@@ -158,11 +158,11 @@ PUT /projects/:id/pages/domains/:domain
| `key` | file/string | no | The certificate key in PEM format. |
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form "certificate=@/path/to/cert.pem" --form "key=@/path/to/key.pem" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --form "certificate=@/path/to/cert.pem" --form "key=@/path/to/key.pem" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example
```
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form "certificate=$CERT_PEM" --form "key=$KEY_PEM" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --form "certificate=$CERT_PEM" --form "key=$KEY_PEM" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example
```
```json
@@ -192,5 +192,5 @@ DELETE /projects/:id/pages/domains/:domain
| `domain` | string | yes | The domain |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example
```
diff --git a/doc/api/pipeline_triggers.md b/doc/api/pipeline_triggers.md
index e881e61d4ef..736312df116 100644
--- a/doc/api/pipeline_triggers.md
+++ b/doc/api/pipeline_triggers.md
@@ -15,7 +15,7 @@ GET /projects/:id/triggers
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
```
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/triggers"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/triggers"
```
```json
@@ -46,7 +46,7 @@ GET /projects/:id/triggers/:trigger_id
| `trigger_id` | integer | yes | The trigger id |
```
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/triggers/5"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/triggers/5"
```
```json
@@ -75,7 +75,7 @@ POST /projects/:id/triggers
| `description` | string | yes | The trigger name |
```
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form description="my description" "https://gitlab.example.com/api/v4/projects/1/triggers"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form description="my description" "https://gitlab.example.com/api/v4/projects/1/triggers"
```
```json
@@ -105,7 +105,7 @@ PUT /projects/:id/triggers/:trigger_id
| `description` | string | no | The trigger name |
```
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form description="my description" "https://gitlab.example.com/api/v4/projects/1/triggers/10"
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --form description="my description" "https://gitlab.example.com/api/v4/projects/1/triggers/10"
```
```json
@@ -134,7 +134,7 @@ POST /projects/:id/triggers/:trigger_id/take_ownership
| `trigger_id` | integer | yes | The trigger id |
```
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/triggers/10/take_ownership"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/triggers/10/take_ownership"
```
```json
@@ -163,5 +163,5 @@ DELETE /projects/:id/triggers/:trigger_id
| `trigger_id` | integer | yes | The trigger id |
```
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/triggers/5"
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/triggers/5"
```
diff --git a/doc/api/pipelines.md b/doc/api/pipelines.md
index 7b4c9a8fbb3..43bbf463c8d 100644
--- a/doc/api/pipelines.md
+++ b/doc/api/pipelines.md
@@ -22,7 +22,7 @@ GET /projects/:id/pipelines
| `sort` | string | no | Sort pipelines in `asc` or `desc` order (default: `desc`) |
```
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/pipelines"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/pipelines"
```
Example of response
@@ -60,7 +60,7 @@ GET /projects/:id/pipelines/:pipeline_id
| `pipeline_id` | integer | yes | The ID of a pipeline |
```
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/pipelines/46"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/pipelines/46"
```
Example of response
@@ -108,7 +108,7 @@ POST /projects/:id/pipeline
| `variables` | array | no | An array containing the variables available in the pipeline, matching the structure [{ 'key' => 'UPLOAD_TO_S3', 'value' => 'true' }] |
```
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/pipeline?ref=master"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/pipeline?ref=master"
```
Example of response
@@ -155,7 +155,7 @@ POST /projects/:id/pipelines/:pipeline_id/retry
| `pipeline_id` | integer | yes | The ID of a pipeline |
```
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/pipelines/46/retry"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/pipelines/46/retry"
```
Response:
@@ -202,7 +202,7 @@ POST /projects/:id/pipelines/:pipeline_id/cancel
| `pipeline_id` | integer | yes | The ID of a pipeline |
```
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/pipelines/46/cancel"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/pipelines/46/cancel"
```
Response:
@@ -249,7 +249,7 @@ DELETE /projects/:id/pipelines/:pipeline_id
| `pipeline_id` | integer | yes | The ID of a pipeline |
```
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --request "DELETE" "https://gitlab.example.com/api/v4/projects/1/pipelines/46"
+curl --header "PRIVATE-TOKEN: <your_access_token>" --request "DELETE" "https://gitlab.example.com/api/v4/projects/1/pipelines/46"
```
[ce-5837]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5837
diff --git a/doc/api/project_badges.md b/doc/api/project_badges.md
index 94389273e9c..3a7b3d8975e 100644
--- a/doc/api/project_badges.md
+++ b/doc/api/project_badges.md
@@ -25,7 +25,7 @@ GET /projects/:id/badges
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/badges
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/:id/badges
```
Example response:
@@ -65,7 +65,7 @@ GET /projects/:id/badges/:badge_id
| `badge_id` | integer | yes | The badge ID |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/badges/:badge_id
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/:id/badges/:badge_id
```
Example response:
@@ -96,7 +96,7 @@ POST /projects/:id/badges
| `image_url` | string | yes | URL of the badge image |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --data "link_url=https://gitlab.com/gitlab-org/gitlab-ce/commits/master&image_url=https://shields.io/my/badge1&position=0" https://gitlab.example.com/api/v4/projects/:id/badges
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --data "link_url=https://gitlab.com/gitlab-org/gitlab-ce/commits/master&image_url=https://shields.io/my/badge1&position=0" https://gitlab.example.com/api/v4/projects/:id/badges
```
Example response:
@@ -128,7 +128,7 @@ PUT /projects/:id/badges/:badge_id
| `image_url` | string | no | URL of the badge image |
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/badges/:badge_id
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/:id/badges/:badge_id
```
Example response:
@@ -158,7 +158,7 @@ DELETE /projects/:id/badges/:badge_id
| `badge_id` | integer | yes | The badge ID |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/badges/:badge_id
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/:id/badges/:badge_id
```
## Preview a badge from a project
@@ -176,7 +176,7 @@ GET /projects/:id/badges/render
| `image_url` | string | yes | URL of the badge image |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/badges/render?link_url=http%3A%2F%2Fexample.com%2Fci_status.svg%3Fproject%3D%25%7Bproject_path%7D%26ref%3D%25%7Bdefault_branch%7D&image_url=https%3A%2F%2Fshields.io%2Fmy%2Fbadge
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/:id/badges/render?link_url=http%3A%2F%2Fexample.com%2Fci_status.svg%3Fproject%3D%25%7Bproject_path%7D%26ref%3D%25%7Bdefault_branch%7D&image_url=https%3A%2F%2Fshields.io%2Fmy%2Fbadge
```
Example response:
diff --git a/doc/api/project_import_export.md b/doc/api/project_import_export.md
index 83e405141f1..fc91c5741da 100644
--- a/doc/api/project_import_export.md
+++ b/doc/api/project_import_export.md
@@ -30,7 +30,7 @@ POST /projects/:id/export
```console
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/export \
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/export \
--data "upload[http_method]=PUT" \
--data-urlencode "upload[url]=https://example-bucket.s3.eu-west-3.amazonaws.com/backup?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIMBJHN2O62W8IELQ%2F20180312%2Feu-west-3%2Fs3%2Faws4_request&X-Amz-Date=20180312T110328Z&X-Amz-Expires=900&X-Amz-SignedHeaders=host&X-Amz-Signature=8413facb20ff33a49a147a0b4abcff4c8487cc33ee1f7e450c46e8f695569dbd"
```
@@ -54,7 +54,7 @@ GET /projects/:id/export
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
```console
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/export
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/export
```
Status can be one of `none`, `started`, `after_export_action` or `finished`. The
@@ -95,7 +95,7 @@ GET /projects/:id/export/download
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
```console
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --remote-header-name --remote-name https://gitlab.example.com/api/v4/projects/5/export/download
+curl --header "PRIVATE-TOKEN: <your_access_token>" --remote-header-name --remote-name https://gitlab.example.com/api/v4/projects/5/export/download
```
```console
@@ -125,7 +125,7 @@ The `file=` parameter must point to a file on your file system and be preceded
by `@`. For example:
```console
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form "path=api-project" --form "file=@/path/to/file" https://gitlab.example.com/api/v4/projects/import
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "path=api-project" --form "file=@/path/to/file" https://gitlab.example.com/api/v4/projects/import
```
cURL doesn't support posting a file from a remote server. Importing a project from a remote server can be accomplished through something like the following:
@@ -145,7 +145,7 @@ data = {
"namespace": "example-group"
}
headers = {
- 'Private-Token': "9koXpg98eAheJpvBs5tK"
+ 'Private-Token': "<your_access_token>"
}
requests.post(url, headers=headers, data=data, files=files)
@@ -177,7 +177,7 @@ GET /projects/:id/import
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
```console
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/import
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/import
```
Status can be one of `none`, `scheduled`, `failed`, `started`, or `finished`.
diff --git a/doc/api/project_level_variables.md b/doc/api/project_level_variables.md
index 82ac0b09027..438bebe62f5 100644
--- a/doc/api/project_level_variables.md
+++ b/doc/api/project_level_variables.md
@@ -13,7 +13,7 @@ GET /projects/:id/variables
| `id` | integer/string | yes | The ID of a project or [urlencoded NAMESPACE/PROJECT_NAME of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
```
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/variables"
```
```json
@@ -43,7 +43,7 @@ GET /projects/:id/variables/:key
| `key` | string | yes | The `key` of a variable |
```
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables/TEST_VARIABLE_1"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/variables/TEST_VARIABLE_1"
```
```json
@@ -69,7 +69,7 @@ POST /projects/:id/variables
| `protected` | boolean | no | Whether the variable is protected |
```
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables" --form "key=NEW_VARIABLE" --form "value=new value"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/variables" --form "key=NEW_VARIABLE" --form "value=new value"
```
```json
@@ -96,7 +96,7 @@ PUT /projects/:id/variables/:key
| `protected` | boolean | no | Whether the variable is protected |
```
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables/NEW_VARIABLE" --form "value=updated value"
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/variables/NEW_VARIABLE" --form "value=updated value"
```
```json
@@ -121,5 +121,5 @@ DELETE /projects/:id/variables/:key
| `key` | string | yes | The `key` of a variable |
```
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables/VARIABLE_1"
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/variables/VARIABLE_1"
```
diff --git a/doc/api/project_snippets.md b/doc/api/project_snippets.md
index cc495c5d091..8f4640fcbd6 100644
--- a/doc/api/project_snippets.md
+++ b/doc/api/project_snippets.md
@@ -137,7 +137,7 @@ GET /projects/:id/snippets/:snippet_id/user_agent_detail
| `snippet_id` | Integer | yes | The ID of a snippet |
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/snippets/2/user_agent_detail
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/snippets/2/user_agent_detail
```
Example response:
diff --git a/doc/api/projects.md b/doc/api/projects.md
index ef51ea20e7f..465b1494b2a 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -798,7 +798,7 @@ GET /projects/:id/forks
| `min_access_level` | integer | no | Limit by current user minimal [access level](members.md) |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/forks"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/forks"
```
Example responses:
@@ -878,7 +878,7 @@ POST /projects/:id/star
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/star"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/star"
```
Example response:
@@ -964,7 +964,7 @@ POST /projects/:id/unstar
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/unstar"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/unstar"
```
Example response:
@@ -1046,7 +1046,7 @@ GET /projects/:id/languages
```
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/languages"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/languages"
```
Example response:
@@ -1074,7 +1074,7 @@ POST /projects/:id/archive
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/archive"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/archive"
```
Example response:
@@ -1178,7 +1178,7 @@ POST /projects/:id/unarchive
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/unarchive"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/unarchive"
```
Example response:
@@ -1299,7 +1299,7 @@ The `file=` parameter must point to a file on your filesystem and be preceded
by `@`. For example:
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form "file=@dk.png" https://gitlab.example.com/api/v4/projects/5/uploads
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "file=@dk.png" https://gitlab.example.com/api/v4/projects/5/uploads
```
Returned object:
@@ -1345,7 +1345,7 @@ DELETE /projects/:id/share/:group_id
| `group_id` | integer | yes | The ID of the group |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/share/17
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/share/17
```
## Hooks
@@ -1513,7 +1513,7 @@ GET /projects
| `sort` | string | no | Return requests sorted in `asc` or `desc` order |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects?search=test
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects?search=test
```
## Start the Housekeeping task for a Project
diff --git a/doc/api/protected_branches.md b/doc/api/protected_branches.md
index ed8837574a0..fa04680d406 100644
--- a/doc/api/protected_branches.md
+++ b/doc/api/protected_branches.md
@@ -24,7 +24,7 @@ GET /projects/:id/protected_branches
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" 'https://gitlab.example.com/api/v4/projects/5/protected_branches'
+curl --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/5/protected_branches'
```
Example response:
@@ -64,7 +64,7 @@ GET /projects/:id/protected_branches/:name
| `name` | string | yes | The name of the branch or wildcard |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" 'https://gitlab.example.com/api/v4/projects/5/protected_branches/master'
+curl --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/5/protected_branches/master'
```
Example response:
@@ -97,7 +97,7 @@ POST /projects/:id/protected_branches
```
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" 'https://gitlab.example.com/api/v4/projects/5/protected_branches?name=*-stable&push_access_level=30&merge_access_level=30'
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/5/protected_branches?name=*-stable&push_access_level=30&merge_access_level=30'
```
| Attribute | Type | Required | Description |
@@ -136,7 +136,7 @@ DELETE /projects/:id/protected_branches/:name
```
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" 'https://gitlab.example.com/api/v4/projects/5/protected_branches/*-stable'
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/5/protected_branches/*-stable'
```
| Attribute | Type | Required | Description |
diff --git a/doc/api/protected_tags.md b/doc/api/protected_tags.md
index aa750e467f8..3adca61a108 100644
--- a/doc/api/protected_tags.md
+++ b/doc/api/protected_tags.md
@@ -25,7 +25,7 @@ GET /projects/:id/protected_tags
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" 'https://gitlab.example.com/api/v4/projects/5/protected_tags'
+curl --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/5/protected_tags'
```
Example response:
@@ -60,7 +60,7 @@ GET /projects/:id/protected_tags/:name
| `name` | string | yes | The name of the tag or wildcard |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" 'https://gitlab.example.com/api/v4/projects/5/protected_tags/release-1-0'
+curl --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/5/protected_tags/release-1-0'
```
Example response:
@@ -87,7 +87,7 @@ POST /projects/:id/protected_tags
```
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" 'https://gitlab.example.com/api/v4/projects/5/protected_tags?name=*-stable&create_access_level=30'
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/5/protected_tags?name=*-stable&create_access_level=30'
```
| Attribute | Type | Required | Description |
@@ -119,7 +119,7 @@ DELETE /projects/:id/protected_tags/:name
```
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" 'https://gitlab.example.com/api/v4/projects/5/protected_tags/*-stable'
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/5/protected_tags/*-stable'
```
| Attribute | Type | Required | Description |
diff --git a/doc/api/releases.md b/doc/api/releases.md
index bfd0cc1c4ea..4613fe3482a 100644
--- a/doc/api/releases.md
+++ b/doc/api/releases.md
@@ -1,7 +1,7 @@
# Releases API
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/41766) in GitLab 11.7.
-> - Using this API you can manipulate GitLab's [Release](../user/project/releases.md) entries.
+> - Using this API you can manipulate GitLab's [Release](../user/project/releases/index.md) entries.
## List Releases
diff --git a/doc/api/repositories.md b/doc/api/repositories.md
index 55f5a4cc3b2..9f552a10589 100644
--- a/doc/api/repositories.md
+++ b/doc/api/repositories.md
@@ -212,7 +212,7 @@ Response:
## Merge Base
-Get the common ancestor for 2 refs (commit SHAs, branch names or tags).
+Get the common ancestor for 2 or more refs (commit SHAs, branch names or tags).
```
GET /projects/:id/repository/merge_base
@@ -224,7 +224,7 @@ GET /projects/:id/repository/merge_base
| `refs` | array | yes | The refs to find the common ancestor of, multiple refs can be passed |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/repository/merge_base?refs[]=304d257dcb821665ab5110318fc58a007bd104ed&refs[]=0031876facac3f2b2702a0e53a26e89939a42209"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/merge_base?refs[]=304d257dcb821665ab5110318fc58a007bd104ed&refs[]=0031876facac3f2b2702a0e53a26e89939a42209"
```
Example response:
diff --git a/doc/api/repository_files.md b/doc/api/repository_files.md
index 5f587f480b6..8c1d982f394 100644
--- a/doc/api/repository_files.md
+++ b/doc/api/repository_files.md
@@ -25,7 +25,7 @@ GET /projects/:id/repository/files/:file_path
```
```bash
-curl --request GET --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fmodels%2Fkey%2Erb?ref=master'
+curl --request GET --header 'PRIVATE-TOKEN: <your_access_token>' 'https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fmodels%2Fkey%2Erb?ref=master'
```
Example response:
@@ -60,7 +60,7 @@ HEAD /projects/:id/repository/files/:file_path
```
```bash
-curl --head --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fmodels%2Fkey%2Erb?ref=master'
+curl --head --header 'PRIVATE-TOKEN: <your_access_token>' 'https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fmodels%2Fkey%2Erb?ref=master'
```
Example response:
@@ -87,7 +87,7 @@ GET /projects/:id/repository/files/:file_path/raw
```
```bash
-curl --request GET --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fmodels%2Fkey%2Erb/raw?ref=master'
+curl --request GET --header 'PRIVATE-TOKEN: <your_access_token>' 'https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fmodels%2Fkey%2Erb/raw?ref=master'
```
Parameters:
@@ -107,7 +107,7 @@ POST /projects/:id/repository/files/:file_path
```
```bash
-curl --request POST --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' --header "Content-Type: application/json" \
+curl --request POST --header 'PRIVATE-TOKEN: <your_access_token>' --header "Content-Type: application/json" \
--data '{"branch": "master", "author_email": "author@example.com", "author_name": "Firstname Lastname", \
"content": "some content", "commit_message": "create a new file"}' \
'https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fproject%2Erb'
@@ -142,7 +142,7 @@ PUT /projects/:id/repository/files/:file_path
```
```bash
-curl --request PUT --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' --header "Content-Type: application/json" \
+curl --request PUT --header 'PRIVATE-TOKEN: <your_access_token>' --header "Content-Type: application/json" \
--data '{"branch": "master", "author_email": "author@example.com", "author_name": "Firstname Lastname", \
"content": "some content", "commit_message": "update file"}' \
'https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fproject%2Erb'
@@ -187,7 +187,7 @@ DELETE /projects/:id/repository/files/:file_path
```
```bash
-curl --request DELETE --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' --header "Content-Type: application/json" \
+curl --request DELETE --header 'PRIVATE-TOKEN: <your_access_token>' --header "Content-Type: application/json" \
--data '{"branch": "master", "author_email": "author@example.com", "author_name": "Firstname Lastname", \
"commit_message": "delete file"}' \
'https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fproject%2Erb'
diff --git a/doc/api/repository_submodules.md b/doc/api/repository_submodules.md
index 11b04c81172..2c44c4abc93 100644
--- a/doc/api/repository_submodules.md
+++ b/doc/api/repository_submodules.md
@@ -22,7 +22,7 @@ PUT /projects/:id/repository/submodules/:submodule
| `commit_message` | string | no | Commit message. If no message is provided, a default one will be set |
```sh
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/repository/submodules/lib%2Fmodules%2Fexample"
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/submodules/lib%2Fmodules%2Fexample"
--data "branch=master&commit_sha=3ddec28ea23acc5caa5d8331a6ecb2a65fc03e88&commit_message=Update submodule reference"
```
diff --git a/doc/api/resource_label_events.md b/doc/api/resource_label_events.md
index 33e4821ccf4..e1f9ffa9472 100644
--- a/doc/api/resource_label_events.md
+++ b/doc/api/resource_label_events.md
@@ -65,7 +65,7 @@ GET /projects/:id/issues/:issue_iid/resource_label_events
```
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/resource_label_events
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/11/resource_label_events
```
### Get single issue label event
@@ -85,7 +85,7 @@ Parameters:
| `resource_label_event_id` | integer | yes | The ID of a label event |
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/resource_label_events/1
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/11/resource_label_events/1
```
## Merge requests
@@ -151,7 +151,7 @@ GET /projects/:id/merge_requests/:merge_request_iid/resource_label_events
```
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/resource_label_events
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/resource_label_events
```
### Get single merge request label event
@@ -171,5 +171,5 @@ Parameters:
| `resource_label_event_id` | integer | yes | The ID of a label event |
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/resource_label_events/120
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/resource_label_events/120
```
diff --git a/doc/api/runners.md b/doc/api/runners.md
index 071c13f41cb..4aa0e4543e5 100644
--- a/doc/api/runners.md
+++ b/doc/api/runners.md
@@ -22,7 +22,7 @@ GET /runners?status=active
| `status` | string | no | The status of runners to show, one of: `active`, `paused`, `online`, `offline` |
```
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/runners"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/runners"
```
Example response:
@@ -71,7 +71,7 @@ GET /runners/all?status=active
| `status` | string | no | The status of runners to show, one of: `active`, `paused`, `online`, `offline` |
```
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/runners/all"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/runners/all"
```
Example response:
@@ -134,7 +134,7 @@ GET /runners/:id
| `id` | integer | yes | The ID of a runner |
```
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/runners/6"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/runners/6"
```
Example response:
@@ -193,7 +193,7 @@ PUT /runners/:id
| `maximum_timeout` | integer | no | Maximum timeout set when this Runner will handle the job |
```
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/runners/6" --form "description=test-1-20150125-test" --form "tag_list=ruby,mysql,tag1,tag2"
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/runners/6" --form "description=test-1-20150125-test" --form "tag_list=ruby,mysql,tag1,tag2"
```
Example response:
@@ -247,7 +247,7 @@ DELETE /runners/:id
| `id` | integer | yes | The ID of a runner |
```
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/runners/6"
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/runners/6"
```
## List runner's jobs
@@ -264,7 +264,7 @@ GET /runners/:id/jobs
| `status` | string | no | Status of the job; one of: `running`, `success`, `failed`, `canceled` |
```
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/runners/1/jobs?status=running"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/runners/1/jobs?status=running"
```
Example response:
@@ -357,7 +357,7 @@ GET /projects/:id/runners?status=active
| `status` | string | no | The status of runners to show, one of: `active`, `paused`, `online`, `offline` |
```
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/9/runners"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/9/runners"
```
Example response:
@@ -401,7 +401,7 @@ POST /projects/:id/runners
| `runner_id` | integer | yes | The ID of a runner |
```
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/9/runners" --form "runner_id=9"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/9/runners" --form "runner_id=9"
```
Example response:
@@ -435,7 +435,7 @@ DELETE /projects/:id/runners/:runner_id
| `runner_id` | integer | yes | The ID of a runner |
```
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/9/runners/9"
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/9/runners/9"
```
## Register a new Runner
diff --git a/doc/api/search.md b/doc/api/search.md
index 7e3ae7404a3..aaaed7d9956 100644
--- a/doc/api/search.md
+++ b/doc/api/search.md
@@ -24,7 +24,7 @@ The response depends on the requested scope.
### Scope: projects
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/search?scope=projects&search=flight
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/search?scope=projects&search=flight
```
Example response:
@@ -55,7 +55,7 @@ Example response:
### Scope: issues
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/search?scope=issues&search=file
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/search?scope=issues&search=file
```
Example response:
@@ -120,7 +120,7 @@ Example response:
### Scope: merge_requests
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/search?scope=merge_requests&search=file
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/search?scope=merge_requests&search=file
```
Example response:
@@ -197,7 +197,7 @@ Example response:
### Scope: milestones
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/search?scope=milestones&search=release
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/search?scope=milestones&search=release
```
Example response:
@@ -222,7 +222,7 @@ Example response:
### Scope: snippet_titles
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/search?scope=snippet_titles&search=sample
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/search?scope=snippet_titles&search=sample
```
Example response:
@@ -253,7 +253,7 @@ Example response:
### Scope: snippet_blobs
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/search?scope=snippet_blos&search=test
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/search?scope=snippet_blos&search=test
```
Example response:
@@ -305,7 +305,7 @@ The response depends on the requested scope.
### Scope: projects
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/3/search?scope=projects&search=flight
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/3/search?scope=projects&search=flight
```
Example response:
@@ -336,7 +336,7 @@ Example response:
### Scope: issues
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/3/search?scope=issues&search=file
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/3/search?scope=issues&search=file
```
Example response:
@@ -401,7 +401,7 @@ Example response:
### Scope: merge_requests
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/3/search?scope=merge_requests&search=file
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/3/search?scope=merge_requests&search=file
```
Example response:
@@ -478,7 +478,7 @@ Example response:
### Scope: milestones
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/3/search?scope=milestones&search=release
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/3/search?scope=milestones&search=release
```
Example response:
@@ -524,7 +524,7 @@ The response depends on the requested scope.
### Scope: issues
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/12/search?scope=issues&search=file
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/12/search?scope=issues&search=file
```
Example response:
@@ -589,7 +589,7 @@ Example response:
### Scope: merge_requests
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/6/search?scope=merge_requests&search=file
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/6/search?scope=merge_requests&search=file
```
Example response:
@@ -666,7 +666,7 @@ Example response:
### Scope: milestones
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/12/search?scope=milestones&search=release
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/12/search?scope=milestones&search=release
```
Example response:
@@ -691,7 +691,7 @@ Example response:
### Scope: notes
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/6/search?scope=notes&search=maxime
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/6/search?scope=notes&search=maxime
```
Example response:
@@ -740,7 +740,7 @@ results:
times in the content.
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/6/search?scope=wiki_blobs&search=bye
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/6/search?scope=wiki_blobs&search=bye
```
Example response:
@@ -763,7 +763,7 @@ Example response:
### Scope: commits
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/6/search?scope=commits&search=bye
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/6/search?scope=commits&search=bye
```
Example response:
@@ -810,7 +810,7 @@ Blobs searches are performed on both filenames and contents. Search results:
times in the content.
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/6/search?scope=blobs&search=installation
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/6/search?scope=blobs&search=installation
```
Example response:
diff --git a/doc/api/services.md b/doc/api/services.md
index c4edaa17815..868bcdd07fc 100644
--- a/doc/api/services.md
+++ b/doc/api/services.md
@@ -639,7 +639,7 @@ Example response:
"job_events": true,
"pipeline_events": true,
"properties": {
- "token": "9koXpg98eAheJpvBs5tK"
+ "token": "<your_access_token>"
}
}
```
diff --git a/doc/api/settings.md b/doc/api/settings.md
index 9b38e3a4eb7..9998a93de03 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -19,7 +19,7 @@ GET /application/settings
```
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/application/settings
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/application/settings
```
Example response:
@@ -75,7 +75,7 @@ PUT /application/settings
```
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/application/settings?signup_enabled=false&default_project_visibility=internal
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/application/settings?signup_enabled=false&default_project_visibility=internal
```
Example response:
diff --git a/doc/api/sidekiq_metrics.md b/doc/api/sidekiq_metrics.md
index b9500916cf2..95dcf2d5277 100644
--- a/doc/api/sidekiq_metrics.md
+++ b/doc/api/sidekiq_metrics.md
@@ -15,7 +15,7 @@ GET /sidekiq/queue_metrics
```
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/sidekiq/queue_metrics
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/sidekiq/queue_metrics
```
Example response:
@@ -40,7 +40,7 @@ GET /sidekiq/process_metrics
```
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/sidekiq/process_metrics
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/sidekiq/process_metrics
```
Example response:
@@ -82,7 +82,7 @@ GET /sidekiq/job_stats
```
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/sidekiq/job_stats
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/sidekiq/job_stats
```
Example response:
@@ -106,7 +106,7 @@ GET /sidekiq/compound_metrics
```
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/sidekiq/compound_metrics
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/sidekiq/compound_metrics
```
Example response:
diff --git a/doc/api/snippets.md b/doc/api/snippets.md
index e840e640377..2cbd041d132 100644
--- a/doc/api/snippets.md
+++ b/doc/api/snippets.md
@@ -38,7 +38,7 @@ Parameters:
| `id` | Integer | yes | The ID of a snippet |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/snippets/1
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/snippets/1
```
Example response:
@@ -80,7 +80,7 @@ Parameters:
| `id` | Integer | yes | The ID of a snippet |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/snippets/1/raw
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/snippets/1/raw
```
Example response:
@@ -208,7 +208,7 @@ Parameters:
```
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/snippets/1"
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/snippets/1"
```
upon successful delete a `204 No content` HTTP code shall be expected, with no data,
@@ -226,7 +226,7 @@ GET /snippets/public
| `page` | Integer | no | the page to retrieve |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/snippets/public?per_page=2&page=1
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/snippets/public?per_page=2&page=1
```
Example response:
@@ -288,7 +288,7 @@ GET /snippets/:id/user_agent_detail
| `id` | Integer | yes | The ID of a snippet |
```bash
-curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/snippets/1/user_agent_detail
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/snippets/1/user_agent_detail
```
Example response:
diff --git a/doc/api/suggestions.md b/doc/api/suggestions.md
index 9d76ef0c4bf..e88d536282a 100644
--- a/doc/api/suggestions.md
+++ b/doc/api/suggestions.md
@@ -16,7 +16,7 @@ PUT /suggestions/:id/apply
| `id` | integer/string | yes | The ID of a suggestion |
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/suggestions/5/apply
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/suggestions/5/apply
```
Example response:
diff --git a/doc/api/system_hooks.md b/doc/api/system_hooks.md
index 7b8db6cfa8f..f8563e819db 100644
--- a/doc/api/system_hooks.md
+++ b/doc/api/system_hooks.md
@@ -20,7 +20,7 @@ GET /hooks
Example request:
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/hooks
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/hooks
```
Example response:
@@ -63,7 +63,7 @@ POST /hooks
Example request:
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/hooks?url=https://gitlab.example.com/hook"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/hooks?url=https://gitlab.example.com/hook"
```
Example response:
@@ -96,7 +96,7 @@ GET /hooks/:id
Example request:
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/hooks/2
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/hooks/2
```
Example response:
@@ -129,5 +129,5 @@ DELETE /hooks/:id
Example request:
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/hooks/2
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/hooks/2
``` \ No newline at end of file
diff --git a/doc/api/tags.md b/doc/api/tags.md
index 826900ca518..fc86aaa6757 100644
--- a/doc/api/tags.md
+++ b/doc/api/tags.md
@@ -65,7 +65,7 @@ Parameters:
| `tag_name` | string | yes | The name of the tag |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/repository/tags/v1.0.0
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/repository/tags/v1.0.0
```
Example Response:
diff --git a/doc/api/templates/licenses.md b/doc/api/templates/licenses.md
index 8d1006e08c5..5feb1e498bd 100644
--- a/doc/api/templates/licenses.md
+++ b/doc/api/templates/licenses.md
@@ -116,7 +116,7 @@ If you omit the `fullname` parameter but authenticate your request, the name of
the authenticated user will be used to replace the copyright holder placeholder.
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/templates/licenses/mit?project=My+Cool+Project
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/templates/licenses/mit?project=My+Cool+Project
```
Example response:
diff --git a/doc/api/todos.md b/doc/api/todos.md
index 0843e4eedc6..c54c90d9f06 100644
--- a/doc/api/todos.md
+++ b/doc/api/todos.md
@@ -23,7 +23,7 @@ Parameters:
| `type` | string | no | The type of a todo. Can be either `Issue` or `MergeRequest` |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/todos
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/todos
```
Example Response:
@@ -195,7 +195,7 @@ Parameters:
| `id` | integer | yes | The ID of a todo |
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/todos/130/mark_as_done
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/todos/130/mark_as_done
```
Example Response:
@@ -285,8 +285,7 @@ POST /todos/mark_as_done
```
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/todos/donmark_as_donee
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/todos/mark_as_done
```
-
[ce-3188]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/3188
diff --git a/doc/api/users.md b/doc/api/users.md
index 1cf4444319c..6000b9b900f 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -458,7 +458,7 @@ GET /user/status
```
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/user/status"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/user/status"
```
Example response:
@@ -513,7 +513,7 @@ PUT /user/status
When both parameters `emoji` and `message` are empty, the status will be cleared.
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --data "emoji=coffee" --data "message=I crave coffee" https://gitlab.example.com/api/v4/user/status
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --data "emoji=coffee" --data "message=I crave coffee" https://gitlab.example.com/api/v4/user/status
```
Example responses
@@ -679,7 +679,7 @@ GET /user/gpg_keys
```
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/user/gpg_keys
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/user/gpg_keys
```
Example response:
@@ -709,7 +709,7 @@ Parameters:
| `key_id` | integer | yes | The ID of the GPG key |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/user/gpg_keys/1
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/user/gpg_keys/1
```
Example response:
@@ -737,7 +737,7 @@ Parameters:
| key | string | yes | The new GPG key |
```bash
-curl --data "key=-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n\r\nxsBNBFV..." --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/user/gpg_keys
+curl --data "key=-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n\r\nxsBNBFV..." --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/user/gpg_keys
```
Example response:
@@ -767,7 +767,7 @@ Parameters:
| `key_id` | integer | yes | The ID of the GPG key |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/user/gpg_keys/1
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/user/gpg_keys/1
```
Returns `204 No Content` on success, or `404 Not found` if the key cannot be found.
@@ -787,7 +787,7 @@ Parameters:
| `id` | integer | yes | The ID of the user |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/users/2/gpg_keys
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/users/2/gpg_keys
```
Example response:
@@ -818,7 +818,7 @@ Parameters:
| `key_id` | integer | yes | The ID of the GPG key |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/users/2/gpg_keys/1
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/users/2/gpg_keys/1
```
Example response:
@@ -847,7 +847,7 @@ Parameters:
| `key_id` | integer | yes | The ID of the GPG key |
```bash
-curl --data "key=-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n\r\nxsBNBFV..." --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/users/2/gpg_keys
+curl --data "key=-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n\r\nxsBNBFV..." --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/users/2/gpg_keys
```
Example response:
@@ -878,7 +878,7 @@ Parameters:
| `key_id` | integer | yes | The ID of the GPG key |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/users/2/gpg_keys/1
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/users/2/gpg_keys/1
```
## List emails
@@ -1063,7 +1063,7 @@ Parameters:
| `state` | string | no | filter tokens based on state (`all`, `active`, `inactive`) |
```
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/users/42/impersonation_tokens
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/users/42/impersonation_tokens
```
Example response:
@@ -1115,7 +1115,7 @@ Parameters:
| `impersonation_token_id` | integer | yes | The ID of the impersonation token |
```
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/users/42/impersonation_tokens/2
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/users/42/impersonation_tokens/2
```
Example response:
@@ -1160,7 +1160,7 @@ Parameters:
| `scopes` | array | yes | The array of scopes of the impersonation token (`api`, `read_user`) |
```
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --data "name=mytoken" --data "expires_at=2017-04-04" --data "scopes[]=api" https://gitlab.example.com/api/v4/users/42/impersonation_tokens
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --data "name=mytoken" --data "expires_at=2017-04-04" --data "scopes[]=api" https://gitlab.example.com/api/v4/users/42/impersonation_tokens
```
Example response:
@@ -1192,7 +1192,7 @@ DELETE /users/:user_id/impersonation_tokens/:impersonation_token_id
```
```
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/users/42/impersonation_tokens/1
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/users/42/impersonation_tokens/1
```
Parameters:
@@ -1227,7 +1227,7 @@ Parameters:
| `from` | string | no | Date string in the format YEAR-MONTH-DAY, e.g. `2016-03-11`. Defaults to 6 months ago. |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/user/activities
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/user/activities
```
Example response:
diff --git a/doc/api/version.md b/doc/api/version.md
index 8b2a5b51bc5..ac19178b7ad 100644
--- a/doc/api/version.md
+++ b/doc/api/version.md
@@ -10,7 +10,7 @@ GET /version
```
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/version
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/version
```
Example response:
diff --git a/doc/api/wikis.md b/doc/api/wikis.md
index df3b54e8f89..436d06cfd3a 100644
--- a/doc/api/wikis.md
+++ b/doc/api/wikis.md
@@ -18,7 +18,7 @@ GET /projects/:id/wikis
| `with_content` | boolean | no | Include pages' content |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/wikis?with_content=1
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/wikis?with_content=1
```
Example response:
@@ -59,7 +59,7 @@ GET /projects/:id/wikis/:slug
| `slug` | string | yes | The slug (a unique string) of the wiki page |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/wikis/home
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/wikis/home
```
Example response:
@@ -89,7 +89,7 @@ POST /projects/:id/wikis
| `format` | string | no | The format of the wiki page. Available formats are: `markdown` (default), `rdoc`, and `asciidoc` |
```bash
-curl --data "format=rdoc&title=Hello&content=Hello world" --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/wikis"
+curl --data "format=rdoc&title=Hello&content=Hello world" --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/wikis"
```
Example response:
@@ -121,7 +121,7 @@ PUT /projects/:id/wikis/:slug
```bash
-curl --request PUT --data "format=rdoc&content=documentation&title=Docs" --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/wikis/foo"
+curl --request PUT --data "format=rdoc&content=documentation&title=Docs" --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/wikis/foo"
```
Example response:
@@ -149,7 +149,7 @@ DELETE /projects/:id/wikis/:slug
| `slug` | string | yes | The slug (a unique string) of the wiki page |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/wikis/foo"
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/wikis/foo"
```
On success the HTTP status code is `204` and no JSON response is expected.
@@ -177,7 +177,7 @@ The `file=` parameter must point to a file on your filesystem and be preceded
by `@`. For example:
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form "file=@dk.png" https://gitlab.example.com/api/v4/projects/1/wikis/attachments
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "file=@dk.png" https://gitlab.example.com/api/v4/projects/1/wikis/attachments
```
Example response:
diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md
index ed0adc5414b..25d189afb24 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -250,6 +250,23 @@ the project services that you are using to learn which variables they define.
An example project service that defines deployment variables is the
[Kubernetes integration](../../user/project/clusters/index.md#deployment-variables).
+## Auto DevOps application variables
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/49056) in GitLab 11.7.
+
+You can configure [Auto DevOps](../../topics/autodevops/index.md) to
+pass CI variables to the running application by prefixing the key of the
+variable with `K8S_SECRET_`.
+
+These [prefixed
+variables](../../topics/autodevops/index.md#application-secret-variables) will
+then be available as environment variables on the running application
+container.
+
+CAUTION: **Caution:**
+Variables with multiline values are not currently supported due to
+limitations with the current Auto DevOps scripting environment.
+
## Debug tracing
> Introduced in GitLab Runner 1.7.
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index fe09af24fa3..98542c7e82c 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -1649,7 +1649,7 @@ test:
> Behaviour expanded in GitLab 10.8 to allow more flexible overriding.
> [Moved](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/21603)
to GitLab Core in 11.4
-> In GitLab 11.7, support for including [GitLab-supplied templates](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/lib/gitlab/ci/templates) directly [was added](https://gitlab.com/gitlab-org/gitlab-ce/issues/53445).
+> In GitLab 11.7, support for [including GitLab-supplied templates directly](https://gitlab.com/gitlab-org/gitlab-ce/issues/53445) and support for [including templates from another repository](https://gitlab.com/gitlab-org/gitlab-ce/issues/53903) was added.
Using the `include` keyword, you can allow the inclusion of external YAML files.
@@ -1724,7 +1724,7 @@ include:
---
-`include` supports three types of files:
+`include` supports four types of files:
- **local** to the same repository, referenced by using full paths in the same
repository, with `/` being the root directory. For example:
@@ -1750,6 +1750,32 @@ include:
NOTE: **Note:**
We don't support the inclusion of local files through Git submodules paths.
+- **file** from another repository, referenced by using full paths in the same
+ repository, with `/` being the root directory. For example:
+
+ ```yaml
+ include:
+ project: 'my-group/my-project'
+ file: '/templates/.gitlab-ci-template.yml'
+ ```
+
+ You can also specify `ref:`. The default `ref:` is the `HEAD` of the project:
+
+ ```yaml
+ include:
+ - project: 'my-group/my-project'
+ ref: master
+ file: '/templates/.gitlab-ci-template.yml'
+
+ - project: 'my-group/my-project'
+ ref: v1.0.0
+ file: '/templates/.gitlab-ci-template.yml'
+
+ - project: 'my-group/my-project'
+ ref: 787123b47f14b552955ca2786bc9542ae66fee5b # git sha
+ file: '/templates/.gitlab-ci-template.yml'
+ ```
+
- **remote** in a different location, accessed using HTTP/HTTPS, referenced
using the full URL. For example:
diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md
index 8760cd194d4..a18c21d921a 100644
--- a/doc/development/documentation/styleguide.md
+++ b/doc/development/documentation/styleguide.md
@@ -62,7 +62,7 @@ with files organized in the [correct directory](index.md#documentation-directory
link out to their external sites, documentation, and resources.
- Do not duplicate information.
- Structure content in alphabetical order in tables, lists, etc., unless there is
-a logical reason not to (for example, when mirroring the UI or an ordered sequence).
+a logical reason not to (for example, when mirroring the UI or an ordered sequence).
## Language
@@ -210,7 +210,7 @@ For other punctuation rules, please refer to the
- Use inline link markdown markup `[Text](https://example.com)`.
It's easier to read, review, and maintain. **Do not** use `[Text][identifier]`.
- To link to internal documentation, use relative links, not full URLs. Use `../` to
- navigate tp high-level directories, and always add the file name `file.md` at the
+ navigate to high-level directories, and always add the file name `file.md` at the
end of the link with the `.md` extension, not `.html`.
Example: instead of `[text](../../merge_requests/)`, use
`[text](../../merge_requests/index.md)` or, `[text](../../ci/README.md)`, or,
@@ -386,8 +386,32 @@ Which renders to:
## Specific sections and terms
-To mention and/or reference specific terms in GitLab, please follow the styles
-below.
+To maintain consistency through GitLab documentation, the following guides documentation authors
+on agreed styles and usage of terms.
+
+### Describing UI elements
+
+The following are styles to follow when describing UI elements on a screen:
+
+- For elements with a visible label, use that label in bold with matching case. For example, `the **Cancel** button`.
+- For elements with a tooltip or hover label, use that label in bold with matching case. For example, `the **Add status emoji** button`.
+
+### Verbs for UI elements
+
+The following are recommended verbs for specific uses.
+
+| Recommended | Used for | Alternatives |
+|:------------|:---------------------------|:---------------------------|
+| "click" | buttons, links, menu items | "hit", "press", "select" |
+| "check" | checkboxes | "enable", "click", "press" |
+| "select" | dropdowns | "pick" |
+| "expand" | expandable sections | "open" |
+
+### Other Verbs
+
+| Recommended | Used for | Alternatives |
+|:------------|:--------------------------------|:-------------------|
+| "go" | making a browser go to location | "navigate", "open" |
### GitLab versions and tiers
@@ -460,6 +484,10 @@ the special markup `**[STARTER]**` will generate a `span` element to trigger the
badges and tooltips (`<span class="badge-trigger starter">`). When the keyword
"only" is added, the corresponding GitLab.com badge will not be displayed.
+## Specific sections
+
+Certain styles should be applied to specific sections. Styles for specific sections are outlined below.
+
### GitLab Restart
There are many cases that a restart/reconfigure of GitLab is required. To
@@ -536,13 +564,64 @@ the style below as a guide:
In this case:
-- Before each step list the installation method is declared in bold
+- Before each step list the installation method is declared in bold.
- Three dashes (`---`) are used to create a horizontal line and separate the
- two methods
+ two methods.
- The code blocks are indented one or more spaces under the list item to render
- correctly
-- Different highlighting languages are used for each config in the code block
-- The [references](#references) guide is used for reconfigure/restart
+ correctly.
+- Different highlighting languages are used for each config in the code block.
+- The [references](#references) guide is used for reconfigure/restart.
+
+## API
+
+Here is a list of must-have items. Use them in the exact order that appears
+on this document. Further explanation is given below.
+
+- Every method must have the REST API request. For example:
+
+ ```
+ GET /projects/:id/repository/branches
+ ```
+
+- Every method must have a detailed
+ [description of the parameters](#method-description).
+- Every method must have a cURL example.
+- Every method must have a response body (in JSON format).
+
+### API topic template
+
+The following can be used as a template to get started:
+
+```md
+## Descriptive title
+
+One or two sentence description of what endpoint does.
+
+```
+METHOD /endpoint
+```
+
+| Attribute | Type | Required | Description |
+|:------------|:---------|:---------|:----------------------|
+| `attribute` | datatype | yes/no | Detailed description. |
+| `attribute` | datatype | yes/no | Detailed description. |
+
+Example request:
+
+```sh
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" 'https://gitlab.example.com/api/v4/endpoint?parameters'
+```
+
+Example response:
+
+```json
+[
+ {
+ }
+]
+```
+
+```
### Fake tokens
@@ -553,9 +632,9 @@ low.
You can use the following fake tokens as examples.
-| **Token type** | **Token value** |
+| Token type | Token value |
|:----------------------|:-------------------------------------------------------------------|
-| Private user token | `9koXpg98eAheJpvBs5tK` |
+| Private user token | `<your_access_token>` |
| Personal access token | `n671WNGecHugsdEDPsyo` |
| Application ID | `2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6` |
| Application secret | `04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df` |
@@ -567,23 +646,7 @@ You can use the following fake tokens as examples.
| Health check token | `Tu7BgjR9qeZTEyRzGG2P` |
| Request profile token | `7VgpS4Ax5utVD2esNstz` |
-### API
-
-Here is a list of must-have items. Use them in the exact order that appears
-on this document. Further explanation is given below.
-
-- Every method must have the REST API request. For example:
-
- ```
- GET /projects/:id/repository/branches
- ```
-
-- Every method must have a detailed
- [description of the parameters](#method-description).
-- Every method must have a cURL example.
-- Every method must have a response body (in JSON format).
-
-#### Method description
+### Method description
Use the following table headers to describe the methods. Attributes should
always be in code blocks using backticks (``` ` ```).
@@ -599,10 +662,10 @@ Rendered example:
|:----------|:-------|:---------|:--------------------|
| `user` | string | yes | The GitLab username |
-#### cURL commands
+### cURL commands
- Use `https://gitlab.example.com/api/v4/` as an endpoint.
-- Wherever needed use this personal access token: `9koXpg98eAheJpvBs5tK`.
+- Wherever needed use this personal access token: `<your_access_token>`.
- Always put the request first. `GET` is the default so you don't have to
include it.
- Use double quotes to the URL when it includes additional parameters.
@@ -611,63 +674,63 @@ Rendered example:
| Methods | Description |
|:-------------------------------------------|:------------------------------------------------------|
-| `-H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK"` | Use this method as is, whenever authentication needed |
+| `-H "PRIVATE-TOKEN: <your_access_token>"` | Use this method as is, whenever authentication needed |
| `-X POST` | Use this method when creating new objects |
| `-X PUT` | Use this method when updating existing objects |
| `-X DELETE` | Use this method when removing existing objects |
-#### cURL Examples
+### cURL Examples
Below is a set of [cURL][] examples that you can use in the API documentation.
-##### Simple cURL command
+#### Simple cURL command
Get the details of a group:
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/gitlab-org
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/gitlab-org
```
-##### cURL example with parameters passed in the URL
+#### cURL example with parameters passed in the URL
Create a new project under the authenticated user's namespace:
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects?name=foo"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects?name=foo"
```
-##### Post data using cURL's --data
+#### Post data using cURL's --data
Instead of using `-X POST` and appending the parameters to the URI, you can use
cURL's `--data` option. The example below will create a new project `foo` under
the authenticated user's namespace.
```bash
-curl --data "name=foo" --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects"
+curl --data "name=foo" --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects"
```
-##### Post data using JSON content
+#### Post data using JSON content
> **Note:** In this example we create a new group. Watch carefully the single
and double quotes.
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --header "Content-Type: application/json" --data '{"path": "my-group", "name": "My group"}' https://gitlab.example.com/api/v4/groups
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --header "Content-Type: application/json" --data '{"path": "my-group", "name": "My group"}' https://gitlab.example.com/api/v4/groups
```
-##### Post data using form-data
+#### Post data using form-data
Instead of using JSON or urlencode you can use multipart/form-data which
properly handles data encoding:
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form "title=ssh-key" --form "key=ssh-rsa AAAAB3NzaC1yc2EA..." https://gitlab.example.com/api/v4/users/25/keys
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "title=ssh-key" --form "key=ssh-rsa AAAAB3NzaC1yc2EA..." https://gitlab.example.com/api/v4/users/25/keys
```
The above example is run by and administrator and will add an SSH public key
titled ssh-key to user's account which has an id of 25.
-##### Escape special characters
+#### Escape special characters
Spaces or slashes (`/`) may sometimes result to errors, thus it is recommended
to escape them when possible. In the example below we create a new issue which
@@ -675,19 +738,19 @@ contains spaces in its title. Observe how spaces are escaped using the `%20`
ASCII code.
```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/42/issues?title=Hello%20Dude"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/42/issues?title=Hello%20Dude"
```
Use `%2F` for slashes (`/`).
-##### Pass arrays to API calls
+#### Pass arrays to API calls
The GitLab API sometimes accepts arrays of strings or integers. For example, to
restrict the sign-up e-mail domains of a GitLab instance to `*.example.com` and
`example.net`, you would do something like this:
```bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --data "domain_whitelist[]=*.example.com" --data "domain_whitelist[]=example.net" https://gitlab.example.com/api/v4/application/settings
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --data "domain_whitelist[]=*.example.com" --data "domain_whitelist[]=example.net" https://gitlab.example.com/api/v4/application/settings
```
[cURL]: http://curl.haxx.se/ "cURL website"
diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md
index d0a054c3290..23aa318ef91 100644
--- a/doc/development/migration_style_guide.md
+++ b/doc/development/migration_style_guide.md
@@ -325,6 +325,31 @@ This ensures all timestamps have a time zone specified. This in turn means exist
suddenly use a different timezone when the system's timezone changes. It also makes it very clear which
timezone was used in the first place.
+## Storing JSON in database
+
+The Rails 5 natively supports `JSONB` (binary JSON) column type.
+Example migration adding this column:
+
+```ruby
+class AddOptionsToBuildMetadata < ActiveRecord::Migration[5.0]
+ DOWNTIME = false
+
+ def change
+ add_column :ci_builds_metadata, :config_options, :jsonb
+ end
+end
+```
+
+On MySQL the `JSON` and `JSONB` is translated to `TEXT 1MB`, as `JSONB` is PostgreSQL only feature.
+
+For above reason you have to use a serializer to provide a translation layer
+in order to support PostgreSQL and MySQL seamlessly:
+
+```ruby
+class BuildMetadata
+ serialize :config_options, Serializers::JSON # rubocop:disable Cop/ActiveRecordSerialize
+end
+```
## Testing
diff --git a/doc/install/kubernetes/gitlab_omnibus.md b/doc/install/kubernetes/gitlab_omnibus.md
index 498b702cab1..2d9c7f15634 100644
--- a/doc/install/kubernetes/gitlab_omnibus.md
+++ b/doc/install/kubernetes/gitlab_omnibus.md
@@ -32,7 +32,7 @@ The deployment includes:
## Limitations
[High Availability](../../administration/high_availability/README.md) and
-[Geo](https://docs.gitlab.com/ee/gitlab-geo/README.html) are not supported.
+[Geo](https://docs.gitlab.com/ee/administration/geo/replication/index.html) are not supported.
## Requirements
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index e937d372384..008791d5ef6 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -284,21 +284,44 @@ to understand how each one works.
### Auto Build
-Auto Build creates a build of the application in one of two ways:
-
-- If there is a `Dockerfile`, it will use `docker build` to create a Docker image.
-- Otherwise, it will use [Herokuish](https://github.com/gliderlabs/herokuish)
- and [Heroku buildpacks](https://devcenter.heroku.com/articles/buildpacks)
- to automatically detect and build the application into a Docker image.
+Auto Build creates a build of the application using an existing `Dockerfile` or
+Heroku buildpacks.
Either way, the resulting Docker image is automatically pushed to the
[Container Registry][container-registry] and tagged with the commit SHA.
-CAUTION: **Important:**
+#### Auto Build using a Dockerfile
+
+If a project's repository contains a `Dockerfile`, Auto Build will use
+`docker build` to create a Docker image.
+
If you are also using Auto Review Apps and Auto Deploy and choose to provide
your own `Dockerfile`, make sure you expose your application to port
`5000` as this is the port assumed by the default Helm chart.
+#### Auto Build using Heroku buildpacks
+
+Auto Build builds an application using a project's `Dockerfile` if present, or
+otherwise it will use [Herokuish](https://github.com/gliderlabs/herokuish)
+and [Heroku buildpacks](https://devcenter.heroku.com/articles/buildpacks)
+to automatically detect and build the application into a Docker image.
+
+Each buildpack requires certain files to be in your project's repository for
+Auto Build to successfully build your application. For example, the following
+files are required at the root of your application's repository, depending on
+the language:
+
+- A `Pipfile` or `requirements.txt` file for Python projects.
+- A `Gemfile` or `Gemfile.lock` file for Ruby projects.
+
+For the requirements of other languages and frameworks, read the
+[buildpacks docs](https://devcenter.heroku.com/articles/buildpacks#officially-supported-buildpacks).
+
+TIP: **Tip:**
+If Auto Build fails despite the project meeting the buildpack requirements, set
+a project variable `TRACE=true` to enable verbose logging, which may help to
+troubleshoot.
+
### Auto Test
Auto Test automatically runs the appropriate tests for your application using
@@ -679,6 +702,7 @@ also be customized, and you can easily use a [custom buildpack](#custom-buildpac
| `REVIEW_DISABLED` | From GitLab 11.0, this variable can be used to disable the `review` and the manual `review:stop` job. If the variable is present, these jobs will not be created. |
| `DAST_DISABLED` | From GitLab 11.0, this variable can be used to disable the `dast` job. If the variable is present, the job will not be created. |
| `PERFORMANCE_DISABLED` | From GitLab 11.0, this variable can be used to disable the `performance` job. If the variable is present, the job will not be created. |
+| `K8S_SECRET_*` | From GitLab 11.7, any variable prefixed with [`K8S_SECRET_`](#application-secret-variables) will be made available by Auto DevOps as environment variables to the deployed application. |
TIP: **Tip:**
Set up the replica variables using a
@@ -690,6 +714,63 @@ You should *not* scale your application using Kubernetes directly. This can
cause confusion with Helm not detecting the change, and subsequent deploys with
Auto DevOps can undo your changes.
+#### Application secret variables
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/49056) in GitLab 11.7.
+
+Some applications need to define secret variables that are
+accessible by the deployed application. Auto DevOps detects variables where the key starts with
+`K8S_SECRET_` and make these prefixed variables available to the
+deployed application, as environment variables.
+
+To configure your application variables:
+
+1. Go to your project's **Settings > CI/CD**, then expand the section
+ called **Variables**.
+
+2. Create a CI Variable, ensuring the key is prefixed with
+ `K8S_SECRET_`. For example, you can create a variable with key
+`K8S_SECRET_RAILS_MASTER_KEY`.
+
+3. Run an Auto Devops pipeline either by manually creating a new
+ pipeline or by pushing a code change to GitLab.
+
+Auto DevOps pipelines will take your application secret variables to
+populate a Kubernetes secret. This secret is unique per environment.
+When deploying your application, the secret is loaded as environment
+variables in the container running the application. Following the
+example above, you can see the secret below containing the
+`RAILS_MASTER_KEY` variable.
+
+```sh
+$ kubectl get secret production-secret -n minimal-ruby-app-54 -o yaml
+apiVersion: v1
+data:
+ RAILS_MASTER_KEY: MTIzNC10ZXN0
+kind: Secret
+metadata:
+ creationTimestamp: 2018-12-20T01:48:26Z
+ name: production-secret
+ namespace: minimal-ruby-app-54
+ resourceVersion: "429422"
+ selfLink: /api/v1/namespaces/minimal-ruby-app-54/secrets/production-secret
+ uid: 57ac2bfd-03f9-11e9-b812-42010a9400e4
+type: Opaque
+```
+
+CAUTION: **Caution:**
+Variables with multiline values are not currently supported due to
+limitations with the current Auto DevOps scripting environment.
+
+NOTE: **Note:**
+Environment variables are generally considered immutable in a Kubernetes
+pod. Therefore, if you update an application secret without changing any
+code then manually create a new pipeline, you will find that any running
+application pods will not have the updated secrets. In this case, you
+can either push a code update to GitLab to force the Kubernetes
+Deployment to recreate pods or manually delete running pods to
+cause Kubernetes to create new pods with updated secrets.
+
#### Advanced replica variables setup
Apart from the two replica-related variables for production mentioned above,
diff --git a/doc/university/glossary/README.md b/doc/university/glossary/README.md
index 7c7e44d29e7..d34cd1bb1c3 100644
--- a/doc/university/glossary/README.md
+++ b/doc/university/glossary/README.md
@@ -241,7 +241,7 @@ Our free SaaS for public and private repositories.
### GitLab Geo
-Allows you to replicate your GitLab instance to other geographical locations as a read-only fully operational version. It [can be used](https://docs.gitlab.com/ee/gitlab-geo/README.html) for cloning and fetching projects, in addition to reading any data. This will make working with large repositories over large distances much faster.
+Allows you to replicate your GitLab instance to other geographical locations as a read-only fully operational version. It [can be used](https://docs.gitlab.com/ee/administration/geo/replication/index.html) for cloning and fetching projects, in addition to reading any data. This will make working with large repositories over large distances much faster.
### GitLab High Availability
@@ -303,7 +303,7 @@ A [tool](https://docs.gitlab.com/ee/integration/external-issue-tracker.html) use
### Jenkins
-An Open Source CI tool written using the Java programming language. [Jenkins](https://jenkins.io/) does the same job as GitLab CI, Bamboo, and Travis CI. It is extremely popular. Related [documentation](https://docs.gitlab.com/ee/integration/jenkins.html).
+An Open Source CI tool written using the Java programming language. [Jenkins](https://jenkins.io/) does the same job as GitLab CI, Bamboo, and Travis CI. It is extremely popular. Related [documentation](https://docs.gitlab.com/ee/integration/jenkins.html).
### Jira
@@ -407,7 +407,7 @@ A free disaster recovery [software](https://help.ubuntu.com/community/MondoMindi
#### Mount
-External reference:
+External reference:
As stated on the [wikipedia page](https://en.wikipedia.org/wiki/Mount_(Unix)), "Mounting makes file systems, files, directories, devices and special files available for use and available to the user."
@@ -447,7 +447,7 @@ Software for which the original source code is freely [available](https://openso
#### Open Source Stewardship
-[Related blog post](https://about.gitlab.com/2016/01/11/being-a-good-open-source-steward/).
+[Related blog post](https://about.gitlab.com/2016/01/11/being-a-good-open-source-steward/).
### Owner
@@ -557,7 +557,7 @@ Software that is hosted centrally and accessed on-demand (i.e. whenever you want
This term is often used by people when they mean "Version Control."
-### Scrum
+### Scrum
An Agile [framework](https://www.scrum.org/Resources/What-is-Scrum) designed to typically help complete complex software projects. It's made up of several parts: product requirements backlog, sprint planning, sprint (development), sprint review, and retrospec (analyzing the sprint). The goal is to end up with potentially shippable products.
@@ -697,7 +697,7 @@ A [website/system](http://www.wiki.com/) that allows for collaborative editing o
### Working area
-Files that have been modified but are not committed. Check them by using the command "git status".
+Files that have been modified but are not committed. Check them by using the command "git status".
### Working Tree
diff --git a/doc/university/high-availability/aws/README.md b/doc/university/high-availability/aws/README.md
index b21cf27c1d3..2aabbf3be86 100644
--- a/doc/university/high-availability/aws/README.md
+++ b/doc/university/high-availability/aws/README.md
@@ -161,7 +161,7 @@ private subnets.
Now press the Launch a Cache Cluster and choose Redis for our
DB engine. You'll be able to configure details such as replication,
Multi-AZ and node types. The second section will allow us to choose our
-subnet and security group and
+subnet and security group and
![Redis Cluster details](img/redis-cluster-det.png)
@@ -206,7 +206,7 @@ http traffic from anywhere and name it something such as
`gitlab-ec2-security-group`.
While we wait for it to launch we can allocate an Elastic IP and
-associate it with our new EC2 instance.
+associate it with our new EC2 instance.
### RDS and Redis Security Group
@@ -268,8 +268,8 @@ our current case we'll specify the adapter, encoding, host, db name,
username, and password.
gitlab_rails['db_adapter'] = "postgresql"
- gitlab_rails['db_encoding'] = "unicode"
- gitlab_rails['db_database'] = "gitlabhq_production"
+ gitlab_rails['db_encoding'] = "unicode"
+ gitlab_rails['db_database'] = "gitlabhq_production"
gitlab_rails['db_username'] = "gitlab"
gitlab_rails['db_password'] = "mypassword"
gitlab_rails['db_host'] = "<rds-endpoint>"
@@ -288,9 +288,9 @@ to make the EFS integration easier to manage.
Finally, run reconfigure. You might find it useful to run a check and
a service status to make sure everything has been set up correctly.
- sudo gitlab-ctl reconfigure
- sudo gitlab-rake gitlab:check
- sudo gitlab-ctl status
+ sudo gitlab-ctl reconfigure
+ sudo gitlab-rake gitlab:check
+ sudo gitlab-ctl status
If everything looks good copy the Elastic IP over to your browser and
test the instance manually.
@@ -396,4 +396,4 @@ There is a lot of ground yet to cover so have a read through these other
resources and feel free to open an issue to request additional material.
* [GitLab High Availability](http://docs.gitlab.com/ce/administration/high_availability/README.html#sts=High%20Availability)
-* [GitLab Geo](http://docs.gitlab.com/ee/gitlab-geo/README.html)
+* [GitLab Geo](https://docs.gitlab.com/ee/administration/geo/replication/index.html)
diff --git a/doc/user/project/import/repo_by_url.md b/doc/user/project/import/repo_by_url.md
index f43e384de88..c20b1cb7f5e 100644
--- a/doc/user/project/import/repo_by_url.md
+++ b/doc/user/project/import/repo_by_url.md
@@ -6,7 +6,7 @@ You can import your existing repositories by providing the Git URL:
1. Switch to the **Import project** tab
1. Click on the **Repo by URL** button
1. Fill in the "Git repository URL" and the remaining project fields
-1. Click **Create project** to being the import process
+1. Click **Create project** to begin the import process
1. Once complete, you will be redirected to your newly created project
![Import project by repo URL](img/import_projects_from_repo_url.png)
diff --git a/doc/user/project/index.md b/doc/user/project/index.md
index e63ed88249d..d46ae31580a 100644
--- a/doc/user/project/index.md
+++ b/doc/user/project/index.md
@@ -72,12 +72,15 @@ website with GitLab Pages
**Other features:**
-- [Wiki](wiki/index.md): Document your GitLab project in an integrated Wiki
-- [Snippets](../snippets.md): Store, share and collaborate on code snippets
-- [Cycle Analytics](cycle_analytics.md): Review your development lifecycle
-- [Syntax highlighting](highlighting.md): An alternative to customize
-your code blocks, overriding GitLab's default choice of language
-- [Badges](badges.md): Badges for the project overview
+- [Wiki](wiki/index.md): document your GitLab project in an integrated Wiki.
+- [Snippets](../snippets.md): store, share and collaborate on code snippets.
+- [Cycle Analytics](cycle_analytics.md): review your development lifecycle.
+- [Syntax highlighting](highlighting.md): an alternative to customize
+your code blocks, overriding GitLab's default choice of language.
+- [Badges](badges.md): badges for the project overview.
+- [Releases](releases/index.md): a way to track deliverables in your project as snapshot in time of
+the source, build output, and other metadata or artifacts
+associated with a released version of your code.
### Project's integrations
diff --git a/doc/user/project/issues/csv_import.md b/doc/user/project/issues/csv_import.md
new file mode 100644
index 00000000000..001e0d303e9
--- /dev/null
+++ b/doc/user/project/issues/csv_import.md
@@ -0,0 +1,45 @@
+# Importing Issues from CSV
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/23532) in GitLab 11.7.
+
+Issues can be imported by uploading a CSV file. The file will be processed in the background and a notification email
+will be sent to you once the import is completed.
+
+> **Note:** A permission level of `Developer` or higher is required to import issues.
+
+## CSV File Format
+
+### Header row
+
+CSV files must contain a header row with at least two columns: `title` and `description`, in that order.
+
+### Column separator
+
+The column separator is automatically detected from the header row.
+
+Supported separator characters are: commas (`,`), semicolons (`;`), and tabs (`\t`).
+
+### Row separator
+
+Lines ending in either `CRLF` or `LF` are supported.
+
+### Quote character
+
+The double-quote (`"`) character is used to quote fields so you can use the column separator within a field. To insert
+a double-quote (`"`) within a quoted field, use two double-quote characters in succession, i.e. `""`.
+
+### Data rows
+
+After the header row, succeeding rows must follow the same column order. The issue title is required while the
+description is optional.
+
+The user uploading the CSV file will be set as the author of the imported issues.
+
+## Sample Data
+
+```csv
+title,description
+My Issue Title,My Issue Description
+Another Title,"A description, with a comma"
+"One More Title","One More Description"
+```
diff --git a/doc/user/project/issues/img/import_csv_button.png b/doc/user/project/issues/img/import_csv_button.png
new file mode 100644
index 00000000000..ab100a95750
--- /dev/null
+++ b/doc/user/project/issues/img/import_csv_button.png
Binary files differ
diff --git a/doc/user/project/issues/index.md b/doc/user/project/issues/index.md
index 200b3a642a1..40a1f60c4ab 100644
--- a/doc/user/project/issues/index.md
+++ b/doc/user/project/issues/index.md
@@ -142,6 +142,15 @@ to find out more about this feature.
With [GitLab Starter](https://about.gitlab.com/pricing/), you can also
create various boards per project with [Multiple Issue Boards](https://docs.gitlab.com/ee/user/project/issue_board.html#multiple-issue-boards).
+### Import Issues from CSV
+
+From the project-level issues list, you can find the import button near the "Edit issues" button in the upper-right
+side.
+
+![Import CSV button](img/import_csv_button.png)
+
+Learn more about [importing issues from CSV](csv_import.md)
+
### External Issue Tracker
Alternatively to GitLab's built-in Issue Tracker, you can also use an [external
diff --git a/doc/user/project/releases.md b/doc/user/project/releases.md
index 3f3525829b8..737842962a9 100644
--- a/doc/user/project/releases.md
+++ b/doc/user/project/releases.md
@@ -1,59 +1 @@
-# Releases
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/41766) in GitLab 11.7.
-
-It's typical to create a [Git tag](../../university/training/topics/tags.md) at
-the moment of release to introduce a checkpoint in your source code
-history, but in most cases your users will need compiled objects or other
-assets output by your CI system to use them, not just the raw source
-code.
-
-GitLab's **Releases** are a way to track deliverables in your project. Consider them
-a snapshot in time of the source, build output, and other metadata or artifacts
-associated with a released version of your code.
-
-At the moment, you can create Release entries via the [Releases API](../../api/releases.md);
-we recommend doing this as one of the last steps in your CI/CD release pipeline.
-
-## Getting started with Releases
-
-Start by giving a [description](#release-description) to the Release and
-including its [assets](#release-assets), as follows.
-
-### Release description
-
-Every Release has a description. You can add any text you like, but we recommend
-including a changelog to describe the content of your release. This will allow
-your users to quickly scan the differences between each one you publish.
-
-NOTE: **Note:**
-[Git's tagging messages](https://git-scm.com/book/en/v2/Git-Basics-Tagging) and
-Release descriptions are unrelated. Description supports [markdown](../markdown.md).
-
-### Release assets
-
-You can currently add the following types of assets to each Release:
-
-- [Source code](#source-code): state of the repo at the time of the Release
-- [Links](#links): to content such as built binaries or documentation
-
-GitLab will support more asset types in the future, including objects such
-as pre-built packages, compliance/security evidence, or container images.
-
-#### Source code
-
-GitLab automatically generate `zip`, `tar.gz`, `tar.bz2` and `tar`
-archived source code from the given Git tag. These are read-only assets.
-
-#### Links
-
-A link is any URL which can point to whatever you like; documentation, built
-binaries, or other related materials. These can be both internal or external
-links from your GitLab instance.
-
-## Releases list
-
-Navigate to **Project > Releases** in order to see the list of releases for a given
-project.
-
-![Releases list](img/releases.png)
+This document was moved to [another location](releases/index.md).
diff --git a/doc/user/project/img/releases.png b/doc/user/project/releases/img/releases.png
index f8b1b7305ad..f8b1b7305ad 100644
--- a/doc/user/project/img/releases.png
+++ b/doc/user/project/releases/img/releases.png
Binary files differ
diff --git a/doc/user/project/releases/index.md b/doc/user/project/releases/index.md
new file mode 100644
index 00000000000..890d6fbc6c7
--- /dev/null
+++ b/doc/user/project/releases/index.md
@@ -0,0 +1,59 @@
+# Releases
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/41766) in GitLab 11.7.
+
+It's typical to create a [Git tag](../../../university/training/topics/tags.md) at
+the moment of release to introduce a checkpoint in your source code
+history, but in most cases your users will need compiled objects or other
+assets output by your CI system to use them, not just the raw source
+code.
+
+GitLab's **Releases** are a way to track deliverables in your project. Consider them
+a snapshot in time of the source, build output, and other metadata or artifacts
+associated with a released version of your code.
+
+At the moment, you can create Release entries via the [Releases API](../../../api/releases.md);
+we recommend doing this as one of the last steps in your CI/CD release pipeline.
+
+## Getting started with Releases
+
+Start by giving a [description](#release-description) to the Release and
+including its [assets](#release-assets), as follows.
+
+### Release description
+
+Every Release has a description. You can add any text you like, but we recommend
+including a changelog to describe the content of your release. This will allow
+your users to quickly scan the differences between each one you publish.
+
+NOTE: **Note:**
+[Git's tagging messages](https://git-scm.com/book/en/v2/Git-Basics-Tagging) and
+Release descriptions are unrelated. Description supports [markdown](../../markdown.md).
+
+### Release assets
+
+You can currently add the following types of assets to each Release:
+
+- [Source code](#source-code): state of the repo at the time of the Release
+- [Links](#links): to content such as built binaries or documentation
+
+GitLab will support more asset types in the future, including objects such
+as pre-built packages, compliance/security evidence, or container images.
+
+#### Source code
+
+GitLab automatically generate `zip`, `tar.gz`, `tar.bz2` and `tar`
+archived source code from the given Git tag. These are read-only assets.
+
+#### Links
+
+A link is any URL which can point to whatever you like; documentation, built
+binaries, or other related materials. These can be both internal or external
+links from your GitLab instance.
+
+## Releases list
+
+Navigate to **Project > Releases** in order to see the list of releases for a given
+project.
+
+![Releases list](img/releases.png)
diff --git a/doc/workflow/releases.md b/doc/workflow/releases.md
index 02388bb73ea..aa0d2a7f799 100644
--- a/doc/workflow/releases.md
+++ b/doc/workflow/releases.md
@@ -1,16 +1,17 @@
# Releases
-NOTE: In GitLab 11.7, we introduced the full fledged [releases](../user/project/releases.md) feature. You can still create release notes on this page, but the new method is preferred.
+NOTE: In GitLab 11.7, we introduced the full fledged [Releases](../user/project/releases/index.md)
+feature. You can still create release notes on this page, but the new method is preferred.
-You can add release notes to any git tag using the notes feature. Release notes
-behave like any other markdown form in GitLab so you can write text and
+You can add release notes to any git tag using the notes feature. Release notes
+behave like any other markdown form in GitLab so you can write text and
drag-n-drop files to it. Release notes are stored in GitLab's database.
-There are several ways to add release notes:
+There are several ways to add release notes:
-* In the interface, when you create a new git tag
-* In the interface, by adding a note to an existing git tag
-* Using the GitLab API
+- In the interface, when you create a new git tag
+- In the interface, by adding a note to an existing git tag
+- Using the GitLab API
## New tag page with release notes text area
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 19da0b2c434..59b67c67f9d 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -129,6 +129,7 @@ module API
mount ::API::PagesDomains
mount ::API::Pipelines
mount ::API::PipelineSchedules
+ mount ::API::ProjectClusters
mount ::API::ProjectExport
mount ::API::ProjectImport
mount ::API::ProjectHooks
@@ -140,6 +141,7 @@ module API
mount ::API::ProtectedBranches
mount ::API::ProtectedTags
mount ::API::Releases
+ mount ::API::Release::Links
mount ::API::Repositories
mount ::API::Runner
mount ::API::Runners
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 97ccd97e883..a2a3c0a16d7 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -1538,5 +1538,38 @@ module API
expose :from_content
expose :to_content
end
+
+ module Platform
+ class Kubernetes < Grape::Entity
+ expose :api_url
+ expose :namespace
+ expose :authorization_type
+ expose :ca_cert
+ end
+ end
+
+ module Provider
+ class Gcp < Grape::Entity
+ expose :cluster_id
+ expose :status_name
+ expose :gcp_project_id
+ expose :zone
+ expose :machine_type
+ expose :num_nodes
+ expose :endpoint
+ end
+ end
+
+ class Cluster < Grape::Entity
+ expose :id, :name, :created_at
+ expose :provider_type, :platform_type, :environment_scope, :cluster_type
+ expose :user, using: Entities::UserBasic
+ expose :platform_kubernetes, using: Entities::Platform::Kubernetes
+ expose :provider_gcp, using: Entities::Provider::Gcp
+ end
+
+ class ClusterProject < Cluster
+ expose :project, using: Entities::BasicProjectDetails
+ end
end
end
diff --git a/lib/api/lint.rb b/lib/api/lint.rb
index 0342a4b6654..a7672021db0 100644
--- a/lib/api/lint.rb
+++ b/lib/api/lint.rb
@@ -8,7 +8,8 @@ module API
requires :content, type: String, desc: 'Content of .gitlab-ci.yml'
end
post '/lint' do
- error = Gitlab::Ci::YamlProcessor.validation_message(params[:content])
+ error = Gitlab::Ci::YamlProcessor.validation_message(params[:content],
+ user: current_user)
status 200
diff --git a/lib/api/project_clusters.rb b/lib/api/project_clusters.rb
new file mode 100644
index 00000000000..7aada260297
--- /dev/null
+++ b/lib/api/project_clusters.rb
@@ -0,0 +1,142 @@
+# frozen_string_literal: true
+
+module API
+ class ProjectClusters < Grape::API
+ include PaginationParams
+
+ before { authenticate! }
+
+ # EE::API::ProjectClusters will
+ # override these methods
+ helpers do
+ params :create_params_ee do
+ end
+
+ params :update_params_ee do
+ end
+ end
+
+ params do
+ requires :id, type: String, desc: 'The ID of the project'
+ end
+ resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ desc 'Get all clusters from the project' do
+ detail 'This feature was introduced in GitLab 11.7.'
+ success Entities::Cluster
+ end
+ params do
+ use :pagination
+ end
+ get ':id/clusters' do
+ authorize! :read_cluster, user_project
+
+ present paginate(clusters_for_current_user), with: Entities::Cluster
+ end
+
+ desc 'Get specific cluster for the project' do
+ detail 'This feature was introduced in GitLab 11.7.'
+ success Entities::ClusterProject
+ end
+ params do
+ requires :cluster_id, type: Integer, desc: 'The cluster ID'
+ end
+ get ':id/clusters/:cluster_id' do
+ authorize! :read_cluster, cluster
+
+ present cluster, with: Entities::ClusterProject
+ end
+
+ desc 'Adds an existing cluster' do
+ detail 'This feature was introduced in GitLab 11.7.'
+ success Entities::ClusterProject
+ end
+ params do
+ requires :name, type: String, desc: 'Cluster name'
+ optional :enabled, type: Boolean, default: true, desc: 'Determines if cluster is active or not, defaults to true'
+ requires :platform_kubernetes_attributes, type: Hash, desc: %q(Platform Kubernetes data) do
+ requires :api_url, type: String, allow_blank: false, desc: 'URL to access the Kubernetes API'
+ requires :token, type: String, desc: 'Token to authenticate against Kubernetes'
+ optional :ca_cert, type: String, desc: 'TLS certificate (needed if API is using a self-signed TLS certificate)'
+ optional :namespace, type: String, desc: 'Unique namespace related to Project'
+ optional :authorization_type, type: String, values: Clusters::Platforms::Kubernetes.authorization_types.keys, default: 'rbac', desc: 'Cluster authorization type, defaults to RBAC'
+ end
+ use :create_params_ee
+ end
+ post ':id/clusters/user' do
+ authorize! :create_cluster, user_project
+
+ user_cluster = ::Clusters::CreateService
+ .new(current_user, create_cluster_user_params)
+ .execute
+
+ if user_cluster.persisted?
+ present user_cluster, with: Entities::ClusterProject
+ else
+ render_validation_error!(user_cluster)
+ end
+ end
+
+ desc 'Update an existing cluster' do
+ detail 'This feature was introduced in GitLab 11.7.'
+ success Entities::ClusterProject
+ end
+ params do
+ requires :cluster_id, type: Integer, desc: 'The cluster ID'
+ optional :name, type: String, desc: 'Cluster name'
+ optional :platform_kubernetes_attributes, type: Hash, desc: %q(Platform Kubernetes data) do
+ optional :api_url, type: String, desc: 'URL to access the Kubernetes API'
+ optional :token, type: String, desc: 'Token to authenticate against Kubernetes'
+ optional :ca_cert, type: String, desc: 'TLS certificate (needed if API is using a self-signed TLS certificate)'
+ optional :namespace, type: String, desc: 'Unique namespace related to Project'
+ end
+ use :update_params_ee
+ end
+ put ':id/clusters/:cluster_id' do
+ authorize! :update_cluster, cluster
+
+ update_service = Clusters::UpdateService.new(current_user, update_cluster_params)
+
+ if update_service.execute(cluster)
+ present cluster, with: Entities::ClusterProject
+ else
+ render_validation_error!(cluster)
+ end
+ end
+
+ desc 'Remove a cluster' do
+ detail 'This feature was introduced in GitLab 11.7.'
+ success Entities::ClusterProject
+ end
+ params do
+ requires :cluster_id, type: Integer, desc: 'The Cluster ID'
+ end
+ delete ':id/clusters/:cluster_id' do
+ authorize! :admin_cluster, cluster
+
+ destroy_conditionally!(cluster)
+ end
+ end
+
+ helpers do
+ def clusters_for_current_user
+ @clusters_for_current_user ||= ClustersFinder.new(user_project, current_user, :all).execute
+ end
+
+ def cluster
+ @cluster ||= clusters_for_current_user.find(params[:cluster_id])
+ end
+
+ def create_cluster_user_params
+ declared_params.merge({
+ provider_type: :user,
+ platform_type: :kubernetes,
+ clusterable: user_project
+ })
+ end
+
+ def update_cluster_params
+ declared_params(include_missing: false).without(:cluster_id)
+ end
+ end
+ end
+end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index f5d21d8923f..9f3a1699146 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -475,7 +475,7 @@ module API
requires :file, type: File, desc: 'The file to be uploaded'
end
post ":id/uploads" do
- UploadService.new(user_project, params[:file]).execute
+ UploadService.new(user_project, params[:file]).execute.to_h
end
desc 'Get the users list of a project' do
diff --git a/lib/api/release/links.rb b/lib/api/release/links.rb
new file mode 100644
index 00000000000..a75a320e929
--- /dev/null
+++ b/lib/api/release/links.rb
@@ -0,0 +1,117 @@
+# frozen_string_literal: true
+
+module API
+ module Release
+ class Links < Grape::API
+ include PaginationParams
+
+ RELEASE_ENDPOINT_REQUIREMETS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS
+ .merge(tag_name: API::NO_SLASH_URL_PART_REGEX)
+
+ before { error!('404 Not Found', 404) unless Feature.enabled?(:releases_page, user_project) }
+
+ params do
+ requires :id, type: String, desc: 'The ID of a project'
+ end
+ resource 'projects/:id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ params do
+ requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
+ end
+ resource 'releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMETS do
+ resource :assets do
+ desc 'Get a list of links of a release' do
+ detail 'This feature was introduced in GitLab 11.7.'
+ success Entities::Releases::Link
+ end
+ params do
+ use :pagination
+ end
+ get 'links' do
+ authorize! :read_release, release
+
+ present paginate(release.links.sorted), with: Entities::Releases::Link
+ end
+
+ desc 'Create a link of a release' do
+ detail 'This feature was introduced in GitLab 11.7.'
+ success Entities::Releases::Link
+ end
+ params do
+ requires :name, type: String, desc: 'The name of the link'
+ requires :url, type: String, desc: 'The URL of the link'
+ end
+ post 'links' do
+ authorize! :create_release, release
+
+ new_link = release.links.create(declared_params(include_missing: false))
+
+ if new_link.persisted?
+ present new_link, with: Entities::Releases::Link
+ else
+ render_api_error!(new_link.errors.messages, 400)
+ end
+ end
+
+ params do
+ requires :link_id, type: String, desc: 'The id of the link'
+ end
+ resource 'links/:link_id' do
+ desc 'Get a link detail of a release' do
+ detail 'This feature was introduced in GitLab 11.7.'
+ success Entities::Releases::Link
+ end
+ get do
+ authorize! :read_release, release
+
+ present link, with: Entities::Releases::Link
+ end
+
+ desc 'Update a link of a release' do
+ detail 'This feature was introduced in GitLab 11.7.'
+ success Entities::Releases::Link
+ end
+ params do
+ optional :name, type: String, desc: 'The name of the link'
+ optional :url, type: String, desc: 'The URL of the link'
+ at_least_one_of :name, :url
+ end
+ put do
+ authorize! :update_release, release
+
+ if link.update(declared_params(include_missing: false))
+ present link, with: Entities::Releases::Link
+ else
+ render_api_error!(link.errors.messages, 400)
+ end
+ end
+
+ desc 'Delete a link of a release' do
+ detail 'This feature was introduced in GitLab 11.7.'
+ success Entities::Releases::Link
+ end
+ delete do
+ authorize! :destroy_release, release
+
+ if link.destroy
+ present link, with: Entities::Releases::Link
+ else
+ render_api_error!(link.errors.messages, 400)
+ end
+ end
+ end
+ end
+ end
+ end
+
+ helpers do
+ def release
+ @release ||= user_project.releases.find_by_tag!(params[:tag])
+ end
+
+ def link
+ @link ||= release.links.find(params[:link_id])
+ end
+ end
+ end
+ end
+end
diff --git a/lib/bitbucket_server/paginator.rb b/lib/bitbucket_server/paginator.rb
index aa5f84f44b3..9eda1c921b2 100644
--- a/lib/bitbucket_server/paginator.rb
+++ b/lib/bitbucket_server/paginator.rb
@@ -12,7 +12,7 @@ module BitbucketServer
@url = url
@page = nil
@page_offset = page_offset
- @limit = limit || PAGE_LENGTH
+ @limit = limit
@total = 0
end
@@ -34,6 +34,8 @@ module BitbucketServer
attr_reader :connection, :page, :url, :type, :limit
def over_limit?
+ return false unless @limit
+
@limit.positive? && @total >= @limit
end
@@ -42,11 +44,15 @@ module BitbucketServer
end
def starting_offset
- [0, page_offset - 1].max * limit
+ [0, page_offset - 1].max * max_per_page
+ end
+
+ def max_per_page
+ limit || PAGE_LENGTH
end
def fetch_next_page
- parsed_response = connection.get(@url, start: next_offset, limit: @limit)
+ parsed_response = connection.get(@url, start: next_offset, limit: max_per_page)
Page.new(parsed_response, type)
end
end
diff --git a/lib/gitlab/ci/build/step.rb b/lib/gitlab/ci/build/step.rb
index d587c896712..7fcabc035ac 100644
--- a/lib/gitlab/ci/build/step.rb
+++ b/lib/gitlab/ci/build/step.rb
@@ -15,7 +15,6 @@ module Gitlab
def from_commands(job)
self.new(:script).tap do |step|
step.script = job.options[:before_script].to_a + job.options[:script].to_a
- step.script = job.commands.split("\n") if step.script.empty?
step.timeout = job.metadata_timeout
step.when = WHEN_ON_SUCCESS
end
diff --git a/lib/gitlab/ci/config.rb b/lib/gitlab/ci/config.rb
index 11e0352975d..5875479183e 100644
--- a/lib/gitlab/ci/config.rb
+++ b/lib/gitlab/ci/config.rb
@@ -8,9 +8,9 @@ module Gitlab
class Config
ConfigError = Class.new(StandardError)
- def initialize(config, opts = {})
+ def initialize(config, project: nil, sha: nil, user: nil)
@config = Config::Extendable
- .new(build_config(config, opts))
+ .new(build_config(config, project: project, sha: sha, user: user))
.to_hash
@global = Entry::Global.new(@config)
@@ -70,20 +70,21 @@ module Gitlab
private
- def build_config(config, opts = {})
+ def build_config(config, project:, sha:, user:)
initial_config = Gitlab::Config::Loader::Yaml.new(config).load!
- project = opts.fetch(:project, nil)
if project
- process_external_files(initial_config, project, opts)
+ process_external_files(initial_config, project: project, sha: sha, user: user)
else
initial_config
end
end
- def process_external_files(config, project, opts)
- sha = opts.fetch(:sha) { project.repository.root_ref_sha }
- Config::External::Processor.new(config, project: project, sha: sha).perform
+ def process_external_files(config, project:, sha:, user:)
+ Config::External::Processor.new(config,
+ project: project,
+ sha: sha || project.repository.root_ref_sha,
+ user: user).perform
end
end
end
diff --git a/lib/gitlab/ci/config/entry/job.rb b/lib/gitlab/ci/config/entry/job.rb
index 50942fbdb40..3239743bfff 100644
--- a/lib/gitlab/ci/config/entry/job.rb
+++ b/lib/gitlab/ci/config/entry/job.rb
@@ -95,7 +95,7 @@ module Gitlab
helpers :before_script, :script, :stage, :type, :after_script,
:cache, :image, :services, :only, :except, :variables,
- :artifacts, :commands, :environment, :coverage, :retry,
+ :artifacts, :environment, :coverage, :retry,
:parallel
attributes :script, :tags, :allow_failure, :when, :dependencies,
@@ -121,10 +121,6 @@ module Gitlab
@config.merge(to_hash.compact)
end
- def commands
- (before_script_value.to_a + script_value.to_a).join("\n")
- end
-
def manual_action?
self.when == 'manual'
end
@@ -156,7 +152,6 @@ module Gitlab
{ name: name,
before_script: before_script_value,
script: script_value,
- commands: commands,
image: image_value,
services: services_value,
stage: stage_value,
diff --git a/lib/gitlab/ci/config/external/file/base.rb b/lib/gitlab/ci/config/external/file/base.rb
index 2ac6656a703..a747886093c 100644
--- a/lib/gitlab/ci/config/external/file/base.rb
+++ b/lib/gitlab/ci/config/external/file/base.rb
@@ -12,7 +12,7 @@ module Gitlab
YAML_WHITELIST_EXTENSION = /.+\.(yml|yaml)$/i.freeze
- Context = Struct.new(:project, :sha)
+ Context = Struct.new(:project, :sha, :user)
def initialize(params, context)
@params = params
diff --git a/lib/gitlab/ci/config/external/file/project.rb b/lib/gitlab/ci/config/external/file/project.rb
new file mode 100644
index 00000000000..e75540dbe5a
--- /dev/null
+++ b/lib/gitlab/ci/config/external/file/project.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Config
+ module External
+ module File
+ class Project < Base
+ include Gitlab::Utils::StrongMemoize
+
+ attr_reader :project_name, :ref_name
+
+ def initialize(params, context = {})
+ @location = params[:file]
+ @project_name = params[:project]
+ @ref_name = params[:ref] || 'HEAD'
+
+ super
+ end
+
+ def matching?
+ super && project_name.present?
+ end
+
+ def content
+ strong_memoize(:content) { fetch_local_content }
+ end
+
+ private
+
+ def validate_content!
+ if !can_access_local_content?
+ errors.push("Project `#{project_name}` not found or access denied!")
+ elsif sha.nil?
+ errors.push("Project `#{project_name}` reference `#{ref_name}` does not exist!")
+ elsif content.nil?
+ errors.push("Project `#{project_name}` file `#{location}` does not exist!")
+ elsif content.blank?
+ errors.push("Project `#{project_name}` file `#{location}` is empty!")
+ end
+ end
+
+ def project
+ strong_memoize(:project) do
+ ::Project.find_by_full_path(project_name)
+ end
+ end
+
+ def can_access_local_content?
+ Ability.allowed?(context.user, :download_code, project)
+ end
+
+ def fetch_local_content
+ return unless can_access_local_content?
+ return unless sha
+
+ project.repository.blob_data_at(sha, location)
+ rescue GRPC::NotFound, GRPC::Internal
+ nil
+ end
+
+ def sha
+ strong_memoize(:sha) do
+ project.commit(ref_name).try(:sha)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/config/external/mapper.rb b/lib/gitlab/ci/config/external/mapper.rb
index 74bd927da39..108bfd5eb43 100644
--- a/lib/gitlab/ci/config/external/mapper.rb
+++ b/lib/gitlab/ci/config/external/mapper.rb
@@ -10,15 +10,17 @@ module Gitlab
FILE_CLASSES = [
External::File::Remote,
External::File::Template,
- External::File::Local
+ External::File::Local,
+ External::File::Project
].freeze
AmbigiousSpecificationError = Class.new(StandardError)
- def initialize(values, project:, sha:)
+ def initialize(values, project:, sha:, user:)
@locations = Array.wrap(values.fetch(:include, []))
@project = project
@sha = sha
+ @user = user
end
def process
@@ -61,7 +63,7 @@ module Gitlab
def context
strong_memoize(:context) do
- External::File::Base::Context.new(project, sha)
+ External::File::Base::Context.new(project, sha, user)
end
end
end
diff --git a/lib/gitlab/ci/config/external/processor.rb b/lib/gitlab/ci/config/external/processor.rb
index 1d310b29dc8..69bc164a039 100644
--- a/lib/gitlab/ci/config/external/processor.rb
+++ b/lib/gitlab/ci/config/external/processor.rb
@@ -7,9 +7,9 @@ module Gitlab
class Processor
IncludeError = Class.new(StandardError)
- def initialize(values, project:, sha:)
+ def initialize(values, project:, sha:, user:)
@values = values
- @external_files = External::Mapper.new(values, project: project, sha: sha).process
+ @external_files = External::Mapper.new(values, project: project, sha: sha, user: user).process
@content = {}
rescue External::Mapper::AmbigiousSpecificationError => e
raise IncludeError, e.message
diff --git a/lib/gitlab/ci/yaml_processor.rb b/lib/gitlab/ci/yaml_processor.rb
index 172926b8ab0..0c48a6ab3ac 100644
--- a/lib/gitlab/ci/yaml_processor.rb
+++ b/lib/gitlab/ci/yaml_processor.rb
@@ -10,7 +10,7 @@ module Gitlab
attr_reader :cache, :stages, :jobs
def initialize(config, opts = {})
- @ci_config = Gitlab::Ci::Config.new(config, opts)
+ @ci_config = Gitlab::Ci::Config.new(config, **opts)
@config = @ci_config.to_hash
unless @ci_config.valid?
@@ -33,7 +33,6 @@ module Gitlab
{ stage_idx: @stages.index(job[:stage]),
stage: job[:stage],
- commands: job[:commands],
tag_list: job[:tags] || [],
name: job[:name].to_s,
allow_failure: job[:ignore],
diff --git a/lib/gitlab/email/attachment_uploader.rb b/lib/gitlab/email/attachment_uploader.rb
index a826519b2dd..3323ce60158 100644
--- a/lib/gitlab/email/attachment_uploader.rb
+++ b/lib/gitlab/email/attachment_uploader.rb
@@ -23,8 +23,8 @@ module Gitlab
content_type: attachment.content_type
}
- link = UploadService.new(project, file).execute
- attachments << link if link
+ uploader = UploadService.new(project, file).execute
+ attachments << uploader.to_h if uploader
ensure
tmp.close!
end
diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml
index 9fb1ae9f64b..7987533978c 100644
--- a/lib/gitlab/import_export/import_export.yml
+++ b/lib/gitlab/import_export/import_export.yml
@@ -74,6 +74,7 @@ project_tree:
- :prometheus_metrics
- :project_badges
- :ci_cd_settings
+ - :error_tracking_setting
# Only include the following attributes for the models specified.
included_attributes:
@@ -148,6 +149,7 @@ excluded_attributes:
- :when
- :artifacts_file
- :artifacts_metadata
+ - :commands
push_event_payload:
- :event_id
project_badges:
@@ -161,6 +163,9 @@ excluded_attributes:
- :token_encrypted
services:
- :template
+ error_tracking_setting:
+ - :encrypted_token
+ - :encrypted_token_iv
methods:
labels:
diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb
index a0f4dcfb772..099b488f68e 100644
--- a/lib/gitlab/import_export/relation_factory.rb
+++ b/lib/gitlab/import_export/relation_factory.rb
@@ -24,6 +24,7 @@ module Gitlab
project_badges: 'Badge',
metrics: 'MergeRequest::Metrics',
ci_cd_settings: 'ProjectCiCdSetting',
+ error_tracking_setting: 'ErrorTracking::ProjectErrorTrackingSetting',
links: 'Releases::Link' }.freeze
USER_REFERENCES = %w[author_id assignee_id updated_by_id merged_by_id latest_closed_by_id user_id created_by_id last_edited_by_id merge_user_id resolved_by_id closed_by_id].freeze
@@ -150,6 +151,7 @@ module Gitlab
if BUILD_MODELS.include?(@relation_name)
@relation_hash.delete('trace') # old export files have trace
@relation_hash.delete('token')
+ @relation_hash.delete('commands')
imported_object
elsif @relation_name == :merge_requests
diff --git a/lib/gitlab/import_export/uploads_manager.rb b/lib/gitlab/import_export/uploads_manager.rb
index 474e9d45566..e232198150a 100644
--- a/lib/gitlab/import_export/uploads_manager.rb
+++ b/lib/gitlab/import_export/uploads_manager.rb
@@ -40,7 +40,7 @@ module Gitlab
def add_upload(upload)
uploader_context = FileUploader.extract_dynamic_path(upload).named_captures.symbolize_keys
- UploadService.new(@project, File.open(upload, 'r'), FileUploader, uploader_context).execute
+ UploadService.new(@project, File.open(upload, 'r'), FileUploader, uploader_context).execute.to_h
end
def copy_project_uploads
diff --git a/lib/gitlab/middleware/multipart.rb b/lib/gitlab/middleware/multipart.rb
index 84c2f0d5720..433151b80e7 100644
--- a/lib/gitlab/middleware/multipart.rb
+++ b/lib/gitlab/middleware/multipart.rb
@@ -32,7 +32,7 @@ module Gitlab
class Handler
def initialize(env, message)
- @request = Rack::Request.new(env)
+ @request = ActionDispatch::Request.new(env)
@rewritten_fields = message['rewritten_fields']
@open_files = []
end
diff --git a/lib/gitlab/url_blocker.rb b/lib/gitlab/url_blocker.rb
index 44c71f8431d..9b7b0db9525 100644
--- a/lib/gitlab/url_blocker.rb
+++ b/lib/gitlab/url_blocker.rb
@@ -8,16 +8,18 @@ module Gitlab
BlockedUrlError = Class.new(StandardError)
class << self
- def validate!(url, ports: [], protocols: [], allow_localhost: false, allow_local_network: true, ascii_only: false, enforce_user: false)
+ def validate!(url, ports: [], protocols: [], allow_localhost: false, allow_local_network: true, ascii_only: false, enforce_user: false, enforce_sanitization: false)
return true if url.nil?
# Param url can be a string, URI or Addressable::URI
uri = parse_url(url)
+ validate_html_tags!(uri) if enforce_sanitization
+
# Allow imports from the GitLab instance itself but only from the configured ports
return true if internal?(uri)
- port = uri.port || uri.default_port
+ port = get_port(uri)
validate_protocol!(uri.scheme, protocols)
validate_port!(port, ports) if ports.any?
validate_user!(uri.user) if enforce_user
@@ -50,6 +52,18 @@ module Gitlab
private
+ def get_port(uri)
+ uri.port || uri.default_port
+ end
+
+ def validate_html_tags!(uri)
+ uri_str = uri.to_s
+ sanitized_uri = ActionController::Base.helpers.sanitize(uri_str, tags: [])
+ if sanitized_uri != uri_str
+ raise BlockedUrlError, 'HTML/CSS/JS tags are not allowed'
+ end
+ end
+
def parse_url(url)
raise Addressable::URI::InvalidURIError if multiline?(url)
diff --git a/lib/gitlab/utils.rb b/lib/gitlab/utils.rb
index a81cee0d6d2..99fa65e0e90 100644
--- a/lib/gitlab/utils.rb
+++ b/lib/gitlab/utils.rb
@@ -115,5 +115,15 @@ module Gitlab
string_or_array.split(',').map(&:strip)
end
+
+ def deep_indifferent_access(data)
+ if data.is_a?(Array)
+ data.map(&method(:deep_indifferent_access))
+ elsif data.is_a?(Hash)
+ data.with_indifferent_access
+ else
+ data
+ end
+ end
end
end
diff --git a/lib/serializers/json.rb b/lib/serializers/json.rb
new file mode 100644
index 00000000000..93cb192087a
--- /dev/null
+++ b/lib/serializers/json.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module Serializers
+ # This serializer exports data as JSON,
+ # it is designed to be used with interwork compatibility between MySQL and PostgreSQL
+ # implementations, as used version of MySQL does not support native json type
+ #
+ # Secondly, the loader makes the resulting hash to have deep indifferent access
+ class JSON
+ class << self
+ def dump(obj)
+ # MySQL stores data as text
+ # look at ./config/initializers/ar_mysql_jsonb_support.rb
+ if Gitlab::Database.mysql?
+ obj = ActiveSupport::JSON.encode(obj)
+ end
+
+ obj
+ end
+
+ def load(data)
+ return if data.nil?
+
+ # On MySQL we store data as text
+ # look at ./config/initializers/ar_mysql_jsonb_support.rb
+ if Gitlab::Database.mysql?
+ data = ActiveSupport::JSON.decode(data)
+ end
+
+ Gitlab::Utils.deep_indifferent_access(data)
+ end
+ end
+ end
+end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 7a43add9005..7db75b5cfef 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -106,6 +106,9 @@ msgstr ""
msgid "%{counter_storage} (%{counter_repositories} repositories, %{counter_build_artifacts} build artifacts, %{counter_lfs_objects} LFS)"
msgstr ""
+msgid "%{count} more"
+msgstr ""
+
msgid "%{count} more assignees"
msgstr ""
@@ -369,6 +372,9 @@ msgstr ""
msgid "Add README"
msgstr ""
+msgid "Add a general comment to this %{noteable_name}."
+msgstr ""
+
msgid "Add a homepage to your wiki that contains information about your project and GitLab will display it here instead of this message."
msgstr ""
@@ -702,6 +708,9 @@ msgstr ""
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
+msgid "Are you sure you want to remove the attachment?"
+msgstr ""
+
msgid "Are you sure you want to remove this identity?"
msgstr ""
@@ -756,6 +765,9 @@ msgstr ""
msgid "Assignee(s)"
msgstr ""
+msgid "Attach a file"
+msgstr ""
+
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr ""
@@ -765,6 +777,9 @@ msgstr ""
msgid "August"
msgstr ""
+msgid "Auth Token"
+msgstr ""
+
msgid "Authentication Log"
msgstr ""
@@ -1842,6 +1857,9 @@ msgstr ""
msgid "ClusterIntegration|You must first install Helm Tiller before installing the applications below"
msgstr ""
+msgid "ClusterIntegration|You must have an RBAC-enabled cluster to install Knative."
+msgstr ""
+
msgid "ClusterIntegration|Your account must have %{link_to_kubernetes_engine}"
msgstr ""
@@ -1884,6 +1902,12 @@ msgstr ""
msgid "Comment"
msgstr ""
+msgid "Comment & close %{noteable_name}"
+msgstr ""
+
+msgid "Comment & reopen %{noteable_name}"
+msgstr ""
+
msgid "Comment & resolve discussion"
msgstr ""
@@ -2381,6 +2405,9 @@ msgstr ""
msgid "Delete list"
msgstr ""
+msgid "Delete this attachment"
+msgstr ""
+
msgid "Deleted"
msgstr ""
@@ -2593,6 +2620,12 @@ msgstr ""
msgid "Discover projects, groups and snippets. Share your projects with others"
msgstr ""
+msgid "Discuss a specific suggestion or question"
+msgstr ""
+
+msgid "Discuss a specific suggestion or question that needs to be resolved"
+msgstr ""
+
msgid "Dismiss"
msgstr ""
@@ -2680,6 +2713,9 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit issues"
+msgstr ""
+
msgid "Email"
msgstr ""
@@ -2755,6 +2791,9 @@ msgstr ""
msgid "Enter the merge request title"
msgstr ""
+msgid "Enter your Sentry API URL"
+msgstr ""
+
msgid "Environment variables"
msgstr ""
@@ -2857,6 +2896,9 @@ msgstr ""
msgid "Error Reporting and Logging"
msgstr ""
+msgid "Error Tracking"
+msgstr ""
+
msgid "Error fetching contributors data."
msgstr ""
@@ -3064,6 +3106,9 @@ msgstr ""
msgid "File templates"
msgstr ""
+msgid "File upload error."
+msgstr ""
+
msgid "Files"
msgstr ""
@@ -3079,6 +3124,9 @@ msgstr ""
msgid "Filter..."
msgstr ""
+msgid "Find and manage Auth Tokens in your Sentry account settings page."
+msgstr ""
+
msgid "Find by path"
msgstr ""
@@ -3094,6 +3142,9 @@ msgstr ""
msgid "Fingerprints"
msgstr ""
+msgid "Finish editing this message first!"
+msgstr ""
+
msgid "Finished"
msgstr ""
@@ -3570,6 +3621,9 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import CSV"
+msgstr ""
+
msgid "Import Projects from Gitea"
msgstr ""
@@ -3588,6 +3642,9 @@ msgstr ""
msgid "Import in progress"
msgstr ""
+msgid "Import issues"
+msgstr ""
+
msgid "Import multiple repositories by uploading a manifest file."
msgstr ""
@@ -3726,6 +3783,9 @@ msgstr ""
msgid "Issues, merge requests, pushes and comments."
msgstr ""
+msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
+msgstr ""
+
msgid "It's you"
msgstr ""
@@ -4060,6 +4120,9 @@ msgstr ""
msgid "Mark todo as done"
msgstr ""
+msgid "Markdown"
+msgstr ""
+
msgid "Markdown enabled"
msgstr ""
@@ -4658,6 +4721,9 @@ msgstr ""
msgid "Open Documentation"
msgstr ""
+msgid "Open comment type dropdown"
+msgstr ""
+
msgid "Open in Xcode"
msgstr ""
@@ -4952,6 +5018,9 @@ msgstr ""
msgid "Play"
msgstr ""
+msgid "Please %{link_to_register} or %{link_to_sign_in} to comment"
+msgstr ""
+
msgid "Please accept the Terms of Service before continuing."
msgstr ""
@@ -5814,6 +5883,9 @@ msgstr ""
msgid "Save changes"
msgstr ""
+msgid "Save comment"
+msgstr ""
+
msgid "Save pipeline schedule"
msgstr ""
@@ -5967,6 +6039,9 @@ msgstr ""
msgid "Send usage data"
msgstr ""
+msgid "Sentry API URL"
+msgstr ""
+
msgid "Sep"
msgstr ""
@@ -6374,6 +6449,15 @@ msgstr ""
msgid "Start date"
msgstr ""
+msgid "Start discussion"
+msgstr ""
+
+msgid "Start discussion & close %{noteable_name}"
+msgstr ""
+
+msgid "Start discussion & reopen %{noteable_name}"
+msgstr ""
+
msgid "Start the Runner!"
msgstr ""
@@ -6437,6 +6521,12 @@ msgstr ""
msgid "Subscribe at project level"
msgstr ""
+msgid "Subscribe to RSS feed"
+msgstr ""
+
+msgid "Subscribe to calendar"
+msgstr ""
+
msgid "Subscribed"
msgstr ""
@@ -6596,7 +6686,7 @@ 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 ""
-msgid "The maximum file size allowed is %{max_attachment_size}mb"
+msgid "The maximum file size allowed is %{size}."
msgstr ""
msgid "The maximum file size allowed is 200KB."
@@ -6710,6 +6800,9 @@ msgstr ""
msgid "Third party offers"
msgstr ""
+msgid "This %{issuable} is locked. Only <strong>project members</strong> can comment."
+msgstr ""
+
msgid "This %{viewer} could not be displayed because %{reason}. You can %{options} instead."
msgstr ""
@@ -6836,6 +6929,9 @@ msgstr ""
msgid "This pipeline is run in a merge request context"
msgstr ""
+msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{strongStart}Auto DevOps.%{strongEnd}"
+msgstr ""
+
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by <b>Auto DevOps.</b>"
msgstr ""
@@ -7092,6 +7188,9 @@ msgstr ""
msgid "To import an SVN repository, check out %{svn_link}."
msgstr ""
+msgid "To link Sentry to GitLab, enter your Sentry URL and Auth Token."
+msgstr ""
+
msgid "To move or copy an entire GitLab project from another GitLab installation to this one, navigate to the original project's settings page, generate an export file, and upload it here."
msgstr ""
@@ -7131,6 +7230,9 @@ msgstr ""
msgid "Toggle commit description"
msgstr ""
+msgid "Toggle commit list"
+msgstr ""
+
msgid "Toggle discussion"
msgstr ""
@@ -7281,6 +7383,9 @@ msgstr ""
msgid "Upload <code>GoogleCodeProjectHosting.json</code> here:"
msgstr ""
+msgid "Upload CSV file"
+msgstr ""
+
msgid "Upload New File"
msgstr ""
@@ -7635,6 +7740,9 @@ msgstr ""
msgid "Withdraw Access Request"
msgstr ""
+msgid "Write a comment or drag your files here…"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -7815,6 +7923,9 @@ msgstr ""
msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
msgstr ""
+msgid "Your changes have been saved"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -7824,6 +7935,12 @@ msgstr ""
msgid "Your groups"
msgstr ""
+msgid "Your issues are being imported. Once finished, you'll get a confirmation email."
+msgstr ""
+
+msgid "Your issues will be imported in the background. Once finished, you'll get a confirmation email."
+msgstr ""
+
msgid "Your name"
msgstr ""
@@ -7842,6 +7959,9 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "attach a new file"
+msgstr ""
+
msgid "branch name"
msgstr ""
@@ -7885,6 +8005,9 @@ msgstr ""
msgid "enabled"
msgstr ""
+msgid "error"
+msgstr ""
+
msgid "error code:"
msgstr ""
@@ -7903,6 +8026,9 @@ msgstr ""
msgid "here"
msgstr ""
+msgid "http://<sentry-host>/api/0/projects/{organization_slug}/{project_slug}/issues/"
+msgstr ""
+
msgid "https://your-bitbucket-server"
msgstr ""
@@ -7930,6 +8056,9 @@ msgstr ""
msgid "it is too large"
msgstr ""
+msgid "latest"
+msgstr ""
+
msgid "latest deployment"
msgstr ""
@@ -8164,6 +8293,12 @@ msgstr ""
msgid "project"
msgstr ""
+msgid "quick actions"
+msgstr ""
+
+msgid "register"
+msgstr ""
+
msgid "remaining"
msgstr ""
@@ -8181,6 +8316,12 @@ msgstr[1] ""
msgid "should be higher than %{access} inherited membership from group %{group_name}"
msgstr ""
+msgid "show less"
+msgstr ""
+
+msgid "sign in"
+msgstr ""
+
msgid "source"
msgstr ""
@@ -8193,6 +8334,9 @@ msgstr ""
msgid "started"
msgstr ""
+msgid "stuck"
+msgstr ""
+
msgid "this document"
msgstr ""
@@ -8218,3 +8362,6 @@ msgid "within %d minute "
msgid_plural "within %d minutes "
msgstr[0] ""
msgstr[1] ""
+
+msgid "yaml invalid"
+msgstr ""
diff --git a/package.json b/package.json
index bc7bc0880de..ff1140128f8 100644
--- a/package.json
+++ b/package.json
@@ -27,7 +27,7 @@
"@babel/preset-env": "^7.1.0",
"@gitlab/csslab": "^1.8.0",
"@gitlab/svgs": "^1.47.0",
- "@gitlab/ui": "^1.18.0",
+ "@gitlab/ui": "^1.20.0",
"apollo-boost": "^0.1.20",
"apollo-client": "^2.4.5",
"autosize": "^4.0.0",
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 6cd5c06a088..5ee8df03d50 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
@@ -10,37 +10,35 @@ module QA
Page::Main::Login.act { sign_in_using_credentials }
end
- before(:all) do
- login
+ [true, false].each do |rbac|
+ context "when rbac is #{rbac ? 'enabled' : 'disabled'}" do
+ before(:all) do
+ login
- @project = Resource::Project.fabricate! do |p|
- p.name = Runtime::Env.auto_devops_project_name || 'project-with-autodevops'
- p.description = 'Project with Auto Devops'
- end
+ @project = Resource::Project.fabricate! do |p|
+ p.name = Runtime::Env.auto_devops_project_name || 'project-with-autodevops'
+ p.description = 'Project with Auto DevOps'
+ end
- # Disable code_quality check in Auto DevOps pipeline as it takes
- # too long and times out the test
- Resource::CiVariable.fabricate! do |resource|
- resource.project = @project
- resource.key = 'CODE_QUALITY_DISABLED'
- resource.value = '1'
- end
+ # Disable code_quality check in Auto DevOps pipeline as it takes
+ # too long and times out the test
+ Resource::CiVariable.fabricate! do |resource|
+ resource.project = @project
+ resource.key = 'CODE_QUALITY_DISABLED'
+ resource.value = '1'
+ end
- # Create Auto Devops compatible repo
- Resource::Repository::ProjectPush.fabricate! do |push|
- push.project = @project
- push.directory = Pathname
- .new(__dir__)
- .join('../../../../../fixtures/auto_devops_rack')
- push.commit_message = 'Create Auto DevOps compatible rack application'
- end
+ # Create Auto DevOps compatible repo
+ Resource::Repository::ProjectPush.fabricate! do |push|
+ push.project = @project
+ push.directory = Pathname
+ .new(__dir__)
+ .join('../../../../../fixtures/auto_devops_rack')
+ push.commit_message = 'Create Auto DevOps compatible rack application'
+ end
- Page::Project::Show.act { wait_for_push }
- end
+ Page::Project::Show.act { wait_for_push }
- [true, false].each do |rbac|
- context "when rbac is #{rbac ? 'enabled' : 'disabled'}" do
- before(:all) do
# Create and connect K8s cluster
@cluster = Service::KubernetesCluster.new(rbac: rbac).create!
kubernetes_cluster = Resource::KubernetesCluster.fabricate! do |cluster|
diff --git a/scripts/review_apps/review-apps.sh b/scripts/review_apps/review-apps.sh
index 9e52366f800..118a7c7f638 100755
--- a/scripts/review_apps/review-apps.sh
+++ b/scripts/review_apps/review-apps.sh
@@ -344,6 +344,7 @@ function wait_for_job_to_be_done() {
if [[ "${job_status}" == "failed" ]]; then
echo "The '${job_name}' failed."
+ exit 1
elif [[ "${job_status}" == "manual" ]]; then
echo "The '${job_name}' is manual."
else
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index a239ac16c0d..df21dc7bc85 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -1026,6 +1026,72 @@ describe Projects::IssuesController do
end
end
+ describe 'POST #import_csv' do
+ let(:project) { create(:project, :public) }
+ let(:file) { fixture_file_upload('spec/fixtures/csv_comma.csv') }
+
+ context 'feature disabled' do
+ it 'returns 404' do
+ sign_in(user)
+ project.add_maintainer(user)
+
+ stub_feature_flags(issues_import_csv: false)
+
+ import_csv
+
+ expect(response).to have_gitlab_http_status :not_found
+ end
+ end
+
+ context 'unauthorized' do
+ it 'returns 404 for guests' do
+ sign_out(:user)
+
+ import_csv
+
+ expect(response).to have_gitlab_http_status :not_found
+ end
+
+ it 'returns 404 for project members with reporter role' do
+ sign_in(user)
+ project.add_reporter(user)
+
+ import_csv
+
+ expect(response).to have_gitlab_http_status :not_found
+ end
+ end
+
+ context 'authorized' do
+ before do
+ sign_in(user)
+ project.add_developer(user)
+ end
+
+ it "returns 302 for project members with developer role" do
+ import_csv
+
+ expect(flash[:notice]).to include('Your issues are being imported')
+ expect(response).to redirect_to(project_issues_path(project))
+ end
+
+ it "shows error when upload fails" do
+ allow_any_instance_of(UploadService).to receive(:execute).and_return(nil)
+
+ import_csv
+
+ expect(flash[:alert]).to include('File upload error.')
+ expect(response).to redirect_to(project_issues_path(project))
+ end
+ end
+
+ def import_csv
+ post :import_csv, namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ file: file
+ end
+ end
+
describe 'GET #discussions' do
let!(:discussion) { create(:discussion_note_on_issue, noteable: issue, project: issue.project) }
context 'when authenticated' do
diff --git a/spec/controllers/projects/settings/operations_controller_spec.rb b/spec/controllers/projects/settings/operations_controller_spec.rb
new file mode 100644
index 00000000000..810f5bb64ba
--- /dev/null
+++ b/spec/controllers/projects/settings/operations_controller_spec.rb
@@ -0,0 +1,181 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Projects::Settings::OperationsController do
+ set(:user) { create(:user) }
+ set(:project) { create(:project) }
+
+ before do
+ sign_in(user)
+ project.add_maintainer(user)
+ end
+
+ context 'error tracking' do
+ describe 'GET #show' do
+ it 'renders show template' do
+ get :show, params: project_params(project)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template(:show)
+ end
+
+ context 'with existing setting' do
+ let!(:error_tracking_setting) do
+ create(:project_error_tracking_setting, project: project)
+ end
+
+ it 'loads existing setting' do
+ get :show, params: project_params(project)
+
+ expect(controller.helpers.error_tracking_setting)
+ .to eq(error_tracking_setting)
+ end
+ end
+
+ context 'without an existing setting' do
+ it 'builds a new setting' do
+ get :show, params: project_params(project)
+
+ expect(controller.helpers.error_tracking_setting).to be_new_record
+ end
+ end
+
+ context 'with feature flag disabled' do
+ before do
+ stub_feature_flags(error_tracking: false)
+ end
+
+ it 'renders 404' do
+ get :show, params: project_params(project)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'with insufficient permissions' do
+ before do
+ project.add_reporter(user)
+ end
+
+ it 'renders 404' do
+ get :show, params: project_params(project)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'as an anonymous user' do
+ before do
+ sign_out(user)
+ end
+
+ it 'redirects to signup page' do
+ get :show, params: project_params(project)
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+ end
+
+ describe 'PATCH #update' do
+ let(:operations_update_service) { spy(:operations_update_service) }
+ let(:operations_url) { project_settings_operations_url(project) }
+
+ let(:error_tracking_params) do
+ {
+ error_tracking_setting_attributes: {
+ enabled: '1',
+ api_url: 'http://url',
+ token: 'token'
+ }
+ }
+ end
+ let(:error_tracking_permitted) do
+ ActionController::Parameters.new(error_tracking_params).permit!
+ end
+
+ context 'when update succeeds' do
+ before do
+ stub_operations_update_service_returning(status: :success)
+ end
+
+ it 'shows a notice' do
+ patch :update, params: project_params(project, error_tracking_params)
+
+ expect(response).to redirect_to(operations_url)
+ expect(flash[:notice]).to eq _('Your changes have been saved')
+ end
+ end
+
+ context 'when update fails' do
+ before do
+ stub_operations_update_service_returning(status: :error)
+ end
+
+ it 'renders show page' do
+ patch :update, params: project_params(project, error_tracking_params)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template(:show)
+ end
+ end
+
+ context 'with feature flag disabled' do
+ before do
+ stub_feature_flags(error_tracking: false)
+ end
+
+ it 'renders 404' do
+ patch :update, params: project_params(project)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'with insufficient permissions' do
+ before do
+ project.add_reporter(user)
+ end
+
+ it 'renders 404' do
+ patch :update, params: project_params(project)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'as an anonymous user' do
+ before do
+ sign_out(user)
+ end
+
+ it 'redirects to signup page' do
+ patch :update, params: project_params(project)
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+ end
+
+ private
+
+ def stub_operations_update_service_returning(return_value = {})
+ expect(::Projects::Operations::UpdateService)
+ .to receive(:new).with(project, user, error_tracking_permitted)
+ .and_return(operations_update_service)
+ expect(operations_update_service).to receive(:execute)
+ .and_return(return_value)
+ end
+ end
+
+ private
+
+ def project_params(project, params = {})
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ project: params
+ }
+ end
+end
diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb
index 7c505ee0d43..897b4411055 100644
--- a/spec/db/schema_spec.rb
+++ b/spec/db/schema_spec.rb
@@ -64,6 +64,7 @@ describe 'Database schema' do
let(:indexes) { connection.indexes(table) }
let(:columns) { connection.columns(table) }
let(:foreign_keys) { connection.foreign_keys(table) }
+ let(:primary_key_column) { connection.primary_key(table) }
context 'all foreign keys' do
# for index to be effective, the FK constraint has to be at first place
@@ -71,6 +72,12 @@ describe 'Database schema' do
first_indexed_column = indexes.map(&:columns).map(&:first)
foreign_keys_columns = foreign_keys.map(&:column)
+ # Add the primary key column to the list of indexed columns because
+ # postgres and mysql both automatically create an index on the primary
+ # key. Also, the rails connection.indexes() method does not return
+ # automatically generated indexes (like the primary key index).
+ first_indexed_column = first_indexed_column.push(primary_key_column)
+
expect(first_indexed_column.uniq).to include(*foreign_keys_columns)
end
end
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index 07c1fc31152..bb3c0d6537d 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -7,7 +7,6 @@ FactoryBot.define do
stage_idx 0
ref 'master'
tag false
- commands 'ls -a'
protected false
created_at 'Di 29. Okt 09:50:00 CET 2013'
pending
@@ -15,7 +14,8 @@ FactoryBot.define do
options do
{
image: 'ruby:2.1',
- services: ['postgres']
+ services: ['postgres'],
+ script: ['ls -a']
}
end
@@ -28,7 +28,6 @@ FactoryBot.define do
pipeline factory: :ci_pipeline
trait :degenerated do
- commands nil
options nil
yaml_variables nil
end
@@ -95,33 +94,53 @@ FactoryBot.define do
trait :teardown_environment do
environment 'staging'
- options environment: { name: 'staging',
- action: 'stop',
- url: 'http://staging.example.com/$CI_JOB_NAME' }
+ options do
+ {
+ script: %w(ls),
+ environment: { name: 'staging',
+ action: 'stop',
+ url: 'http://staging.example.com/$CI_JOB_NAME' }
+ }
+ end
end
trait :deploy_to_production do
environment 'production'
- options environment: { name: 'production',
- url: 'http://prd.example.com/$CI_JOB_NAME' }
+ options do
+ {
+ script: %w(ls),
+ environment: { name: 'production',
+ url: 'http://prd.example.com/$CI_JOB_NAME' }
+ }
+ end
end
trait :start_review_app do
environment 'review/$CI_COMMIT_REF_NAME'
- options environment: { name: 'review/$CI_COMMIT_REF_NAME',
- url: 'http://staging.example.com/$CI_JOB_NAME',
- on_stop: 'stop_review_app' }
+ options do
+ {
+ script: %w(ls),
+ environment: { name: 'review/$CI_COMMIT_REF_NAME',
+ url: 'http://staging.example.com/$CI_JOB_NAME',
+ on_stop: 'stop_review_app' }
+ }
+ end
end
trait :stop_review_app do
name 'stop_review_app'
environment 'review/$CI_COMMIT_REF_NAME'
- options environment: { name: 'review/$CI_COMMIT_REF_NAME',
- url: 'http://staging.example.com/$CI_JOB_NAME',
- action: 'stop' }
+ options do
+ {
+ script: %w(ls),
+ environment: { name: 'review/$CI_COMMIT_REF_NAME',
+ url: 'http://staging.example.com/$CI_JOB_NAME',
+ action: 'stop' }
+ }
+ end
end
trait :allowed_to_fail do
@@ -142,7 +161,13 @@ FactoryBot.define do
trait :schedulable do
self.when 'delayed'
- options start_in: '1 minute'
+
+ options do
+ {
+ script: ['ls -a'],
+ start_in: '1 minute'
+ }
+ end
end
trait :actionable do
@@ -265,6 +290,7 @@ FactoryBot.define do
{
image: { name: 'ruby:2.1', entrypoint: '/bin/sh' },
services: ['postgres', { name: 'docker:stable-dind', entrypoint: '/bin/sh', command: 'sleep 30', alias: 'docker' }],
+ script: %w(echo),
after_script: %w(ls date),
artifacts: {
name: 'artifacts_file',
diff --git a/spec/factories/clusters/clusters.rb b/spec/factories/clusters/clusters.rb
index c9f5d0a813e..3e2c0df8afb 100644
--- a/spec/factories/clusters/clusters.rb
+++ b/spec/factories/clusters/clusters.rb
@@ -44,6 +44,10 @@ FactoryBot.define do
provider_gcp factory: [:cluster_provider_gcp, :creating]
end
+ trait :rbac_disabled do
+ platform_kubernetes factory: [:cluster_platform_kubernetes, :configured, :rbac_disabled]
+ end
+
trait :disabled do
enabled false
end
diff --git a/spec/factories/clusters/platforms/kubernetes.rb b/spec/factories/clusters/platforms/kubernetes.rb
index 8169c457ab7..bf30a9c3a61 100644
--- a/spec/factories/clusters/platforms/kubernetes.rb
+++ b/spec/factories/clusters/platforms/kubernetes.rb
@@ -16,8 +16,8 @@ FactoryBot.define do
end
end
- trait :rbac_enabled do
- authorization_type :rbac
+ trait :rbac_disabled do
+ authorization_type :abac
end
end
end
diff --git a/spec/factories/project_error_tracking_settings.rb b/spec/factories/project_error_tracking_settings.rb
new file mode 100644
index 00000000000..f044cbe8755
--- /dev/null
+++ b/spec/factories/project_error_tracking_settings.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :project_error_tracking_setting, class: ErrorTracking::ProjectErrorTrackingSetting do
+ project
+ api_url 'https://gitlab.com'
+ enabled true
+ token 'access_token_123'
+ end
+end
diff --git a/spec/features/boards/new_issue_spec.rb b/spec/features/boards/new_issue_spec.rb
index 164442a47f5..d0c4534e317 100644
--- a/spec/features/boards/new_issue_spec.rb
+++ b/spec/features/boards/new_issue_spec.rb
@@ -86,6 +86,27 @@ describe 'Issue Boards new issue', :js do
expect(page).to have_selector('.issue-boards-sidebar')
end
+
+ it 'successfuly loads labels to be added to newly created issue' do
+ page.within(first('.board')) do
+ find('.issue-count-badge-add-button').click
+ end
+
+ page.within(first('.board-new-issue-form')) do
+ find('.form-control').set('new issue')
+ click_button 'Submit issue'
+ end
+
+ wait_for_requests
+
+ page.within(first('.issue-boards-sidebar')) do
+ find('.labels .edit-link').click
+
+ wait_for_requests
+
+ expect(page).to have_selector('.labels .dropdown-content li a')
+ end
+ end
end
context 'unauthorized user' do
diff --git a/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb b/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb
index 0272d300e06..0959f1b12f3 100644
--- a/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb
+++ b/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb
@@ -5,7 +5,7 @@ describe 'Merge request < User sees mini pipeline graph', :js do
let(:user) { project.creator }
let(:merge_request) { create(:merge_request, source_project: project, head_pipeline: pipeline) }
let(:pipeline) { create(:ci_empty_pipeline, project: project, ref: 'master', status: 'running', sha: project.commit.id) }
- let(:build) { create(:ci_build, pipeline: pipeline, stage: 'test', commands: 'test') }
+ let(:build) { create(:ci_build, pipeline: pipeline, stage: 'test') }
before do
build.run
diff --git a/spec/features/projects/clusters/applications_spec.rb b/spec/features/projects/clusters/applications_spec.rb
index 8918a7b7b9c..fab9e035d53 100644
--- a/spec/features/projects/clusters/applications_spec.rb
+++ b/spec/features/projects/clusters/applications_spec.rb
@@ -70,6 +70,34 @@ describe 'Clusters Applications', :js do
end
end
+ context 'when user installs Knative' do
+ before do
+ create(:clusters_applications_helm, :installed, cluster: cluster)
+ end
+
+ context 'on an abac cluster' do
+ let(:cluster) { create(:cluster, :provided_by_gcp, :rbac_disabled, projects: [project])}
+
+ it 'should show info block and not be installable' do
+ page.within('.js-cluster-application-row-knative') do
+ expect(page).to have_css('.bs-callout-info')
+ expect(page.find(:css, '.js-cluster-application-install-button')['disabled']).to eq('true')
+ end
+ end
+ end
+
+ context 'on an rbac cluster' do
+ let(:cluster) { create(:cluster, :provided_by_gcp, projects: [project])}
+
+ it 'should not show callout block and be installable' do
+ page.within('.js-cluster-application-row-knative') do
+ expect(page).not_to have_css('.bs-callout-info')
+ expect(page).to have_css('.js-cluster-application-install-button:not([disabled])')
+ end
+ end
+ end
+ end
+
context 'when user installs Cert Manager' do
before do
allow(ClusterInstallAppWorker).to receive(:perform_async)
diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb
index 89954d35f91..0c517d5f490 100644
--- a/spec/features/projects/environments/environments_spec.rb
+++ b/spec/features/projects/environments/environments_spec.rb
@@ -272,8 +272,7 @@ describe 'Environments page', :js do
create(:ci_build, :scheduled,
pipeline: pipeline,
name: 'delayed job',
- stage: 'test',
- commands: 'test')
+ stage: 'test')
end
let!(:deployment) do
@@ -304,8 +303,7 @@ describe 'Environments page', :js do
create(:ci_build, :expired_scheduled,
pipeline: pipeline,
name: 'delayed job',
- stage: 'test',
- commands: 'test')
+ stage: 'test')
end
it "shows 00:00:00 as the remaining time" do
diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb
index a37ad9c3f43..4706c28bb3d 100644
--- a/spec/features/projects/pipelines/pipeline_spec.rb
+++ b/spec/features/projects/pipelines/pipeline_spec.rb
@@ -18,7 +18,7 @@ describe 'Pipeline', :js do
let!(:build_failed) do
create(:ci_build, :failed,
- pipeline: pipeline, stage: 'test', name: 'test', commands: 'test')
+ pipeline: pipeline, stage: 'test', name: 'test')
end
let!(:build_running) do
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index 17772a35779..b75dee66592 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -109,8 +109,7 @@ describe 'Pipelines', :js do
context 'when pipeline is cancelable' do
let!(:build) do
create(:ci_build, pipeline: pipeline,
- stage: 'test',
- commands: 'test')
+ stage: 'test')
end
before do
@@ -140,8 +139,7 @@ describe 'Pipelines', :js do
context 'when pipeline is retryable' do
let!(:build) do
create(:ci_build, pipeline: pipeline,
- stage: 'test',
- commands: 'test')
+ stage: 'test')
end
before do
@@ -202,8 +200,7 @@ describe 'Pipelines', :js do
create(:ci_build, :manual,
pipeline: pipeline,
name: 'manual build',
- stage: 'test',
- commands: 'test')
+ stage: 'test')
end
before do
@@ -237,8 +234,7 @@ describe 'Pipelines', :js do
create(:ci_build, :scheduled,
pipeline: pipeline,
name: 'delayed job',
- stage: 'test',
- commands: 'test')
+ stage: 'test')
end
before do
@@ -262,8 +258,7 @@ describe 'Pipelines', :js do
create(:ci_build, :expired_scheduled,
pipeline: pipeline,
name: 'delayed job',
- stage: 'test',
- commands: 'test')
+ stage: 'test')
end
it "shows 00:00:00 as the remaining time" do
diff --git a/spec/features/projects/settings/operations_settings_spec.rb b/spec/features/projects/settings/operations_settings_spec.rb
new file mode 100644
index 00000000000..1f2328a6dd8
--- /dev/null
+++ b/spec/features/projects/settings/operations_settings_spec.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Projects > Settings > For a forked project', :js do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :repository) }
+ let(:role) { :maintainer }
+
+ before do
+ stub_feature_flags(error_tracking: true)
+ sign_in(user)
+ project.add_role(user, role)
+ end
+
+ describe 'Sidebar > Operations' do
+ context 'when sidebar feature flag enabled' do
+ it 'renders the settings link in the sidebar' do
+ visit project_path(project)
+ wait_for_requests
+
+ expect(page).to have_selector('a[title="Operations"]', visible: false)
+ end
+ end
+
+ context 'when sidebar feature flag disabled' do
+ before do
+ stub_feature_flags(error_tracking: false)
+ end
+
+ it 'does not render the settings link in the sidebar' do
+ visit project_path(project)
+ wait_for_requests
+
+ expect(page).not_to have_selector('a[title="Operations"]', visible: false)
+ end
+ end
+ end
+end
diff --git a/spec/fixtures/api/schemas/release.json b/spec/fixtures/api/schemas/release.json
index 45fa8b074d4..86f0f27606c 100644
--- a/spec/fixtures/api/schemas/release.json
+++ b/spec/fixtures/api/schemas/release.json
@@ -15,15 +15,7 @@
},
"assets": {
"count": { "type": "integer" },
- "links": {
- "type": "array",
- "items": {
- "id": "integer",
- "name": "string",
- "url": "string",
- "external": "boolean"
- }
- },
+ "links": { "$ref": "release/links.json" },
"sources": {
"type": "array",
"items": {
diff --git a/spec/fixtures/api/schemas/release/link.json b/spec/fixtures/api/schemas/release/link.json
new file mode 100644
index 00000000000..97347cb91cc
--- /dev/null
+++ b/spec/fixtures/api/schemas/release/link.json
@@ -0,0 +1,11 @@
+{
+ "type": "object",
+ "required": ["name", "url"],
+ "properties": {
+ "id": { "type": "integer" },
+ "name": { "type": "string" },
+ "url": { "type": "string" },
+ "external": { "type": "boolean" }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/release/links.json b/spec/fixtures/api/schemas/release/links.json
new file mode 100644
index 00000000000..766bc7ce20a
--- /dev/null
+++ b/spec/fixtures/api/schemas/release/links.json
@@ -0,0 +1,4 @@
+{
+ "type": "array",
+ "items": { "$ref": "link.json" }
+}
diff --git a/spec/fixtures/csv_comma.csv b/spec/fixtures/csv_comma.csv
new file mode 100644
index 00000000000..e477a27d243
--- /dev/null
+++ b/spec/fixtures/csv_comma.csv
@@ -0,0 +1,4 @@
+title,description
+Issue in 中文,Test description
+"Hello","World"
+"Title with quote""",Description
diff --git a/spec/fixtures/csv_semicolon.csv b/spec/fixtures/csv_semicolon.csv
new file mode 100644
index 00000000000..679797489e2
--- /dev/null
+++ b/spec/fixtures/csv_semicolon.csv
@@ -0,0 +1,5 @@
+title;description
+Issue in 中文;Test description
+Title with, comma;"Description"
+
+"Hello";"World"
diff --git a/spec/fixtures/csv_tab.csv b/spec/fixtures/csv_tab.csv
new file mode 100644
index 00000000000..f801794ea9c
--- /dev/null
+++ b/spec/fixtures/csv_tab.csv
@@ -0,0 +1,4 @@
+title description
+Issue in 中文 Test description
+ "Error Row"
+"Hello" "World"
diff --git a/spec/fixtures/security-reports/master/gl-container-scanning-report.json b/spec/fixtures/security-reports/master/gl-container-scanning-report.json
index 500c19e3abb..c087352a122 100644
--- a/spec/fixtures/security-reports/master/gl-container-scanning-report.json
+++ b/spec/fixtures/security-reports/master/gl-container-scanning-report.json
@@ -1,18 +1,92 @@
{
- "image": "registry.gitlab.com/bikebilly/auto-devops-10-6/feature-branch:e7315ba964febb11bac8f5cd6ec433db8a3a1583",
+ "image": "registry.gitlab.com/groulot/container-scanning-test/master:5f21de6956aee99ddb68ae49498662d9872f50ff",
"unapproved": [
- "CVE-2017-15651"
+ "CVE-2017-18018",
+ "CVE-2016-2781",
+ "CVE-2017-12424",
+ "CVE-2007-5686",
+ "CVE-2013-4235"
],
"vulnerabilities": [
{
- "featurename": "musl",
- "featureversion": "1.1.14-r15",
- "vulnerability": "CVE-2017-15651",
- "namespace": "alpine:v3.4",
- "description": "",
- "link": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-15651",
+ "featurename": "glibc",
+ "featureversion": "2.24-11+deb9u3",
+ "vulnerability": "CVE-2017-18269",
+ "namespace": "debian:9",
+ "description": "SSE2-optimized memmove implementation problem.",
+ "link": "https://security-tracker.debian.org/tracker/CVE-2017-18269",
+ "severity": "Defcon1",
+ "fixedby": "2.24-11+deb9u4"
+ },
+ {
+ "featurename": "glibc",
+ "featureversion": "2.24-11+deb9u3",
+ "vulnerability": "CVE-2017-16997",
+ "namespace": "debian:9",
+ "description": "elf/dl-load.c in the GNU C Library (aka glibc or libc6) 2.19 through 2.26 mishandles RPATH and RUNPATH containing $ORIGIN for a privileged (setuid or AT_SECURE) program, which allows local users to gain privileges via a Trojan horse library in the current working directory, related to the fillin_rpath and decompose_rpath functions. This is associated with misinterpretion of an empty RPATH/RUNPATH token as the \"./\" directory. NOTE: this configuration of RPATH/RUNPATH for a privileged program is apparently very uncommon; most likely, no such program is shipped with any common Linux distribution.",
+ "link": "https://security-tracker.debian.org/tracker/CVE-2017-16997",
+ "severity": "Critical",
+ "fixedby": ""
+ },
+ {
+ "featurename": "glibc",
+ "featureversion": "2.24-11+deb9u3",
+ "vulnerability": "CVE-2018-1000001",
+ "namespace": "debian:9",
+ "description": "In glibc 2.26 and earlier there is confusion in the usage of getcwd() by realpath() which can be used to write before the destination buffer leading to a buffer underflow and potential code execution.",
+ "link": "https://security-tracker.debian.org/tracker/CVE-2018-1000001",
+ "severity": "High",
+ "fixedby": ""
+ },
+ {
+ "featurename": "glibc",
+ "featureversion": "2.24-11+deb9u3",
+ "vulnerability": "CVE-2016-10228",
+ "namespace": "debian:9",
+ "description": "The iconv program in the GNU C Library (aka glibc or libc6) 2.25 and earlier, when invoked with the -c option, enters an infinite loop when processing invalid multi-byte input sequences, leading to a denial of service.",
+ "link": "https://security-tracker.debian.org/tracker/CVE-2016-10228",
"severity": "Medium",
- "fixedby": "1.1.14-r16"
+ "fixedby": ""
+ },
+ {
+ "featurename": "elfutils",
+ "featureversion": "0.168-1",
+ "vulnerability": "CVE-2018-18520",
+ "namespace": "debian:9",
+ "description": "An Invalid Memory Address Dereference exists in the function elf_end in libelf in elfutils through v0.174. Although eu-size is intended to support ar files inside ar files, handle_ar in size.c closes the outer ar file before handling all inner entries. The vulnerability allows attackers to cause a denial of service (application crash) with a crafted ELF file.",
+ "link": "https://security-tracker.debian.org/tracker/CVE-2018-18520",
+ "severity": "Low",
+ "fixedby": ""
+ },
+ {
+ "featurename": "glibc",
+ "featureversion": "2.24-11+deb9u3",
+ "vulnerability": "CVE-2010-4052",
+ "namespace": "debian:9",
+ "description": "Stack consumption vulnerability in the regcomp implementation in the GNU C Library (aka glibc or libc6) through 2.11.3, and 2.12.x through 2.12.2, allows context-dependent attackers to cause a denial of service (resource exhaustion) via a regular expression containing adjacent repetition operators, as demonstrated by a {10,}{10,}{10,}{10,} sequence in the proftpd.gnu.c exploit for ProFTPD.",
+ "link": "https://security-tracker.debian.org/tracker/CVE-2010-4052",
+ "severity": "Negligible",
+ "fixedby": ""
+ },
+ {
+ "featurename": "nettle",
+ "featureversion": "3.3-1",
+ "vulnerability": "CVE-2018-16869",
+ "namespace": "debian:9",
+ "description": "A Bleichenbacher type side-channel based padding oracle attack was found in the way nettle handles endian conversion of RSA decrypted PKCS#1 v1.5 data. An attacker who is able to run a process on the same physical core as the victim process, could use this flaw extract plaintext or in some cases downgrade any TLS connections to a vulnerable server.",
+ "link": "https://security-tracker.debian.org/tracker/CVE-2018-16869",
+ "severity": "Unknown",
+ "fixedby": ""
+ },
+ {
+ "featurename": "perl",
+ "featureversion": "5.24.1-3+deb9u4",
+ "vulnerability": "CVE-2018-18311",
+ "namespace": "debian:9",
+ "description": "Perl before 5.26.3 and 5.28.x before 5.28.1 has a buffer overflow via a crafted regular expression that triggers invalid write operations.",
+ "link": "https://security-tracker.debian.org/tracker/CVE-2018-18311",
+ "severity": "Unknown",
+ "fixedby": "5.24.1-3+deb9u5"
}
]
-}
+} \ No newline at end of file
diff --git a/spec/helpers/commits_helper_spec.rb b/spec/helpers/commits_helper_spec.rb
index 9c0e55739d6..824b3ab4fc1 100644
--- a/spec/helpers/commits_helper_spec.rb
+++ b/spec/helpers/commits_helper_spec.rb
@@ -21,7 +21,7 @@ describe CommitsHelper do
expect(helper.commit_author_link(commit))
.to include('Foo &lt;script&gt;')
expect(helper.commit_author_link(commit, avatar: true))
- .to include('commit-author-name', 'Foo &lt;script&gt;')
+ .to include('commit-author-name', 'js-user-link', 'Foo &lt;script&gt;')
end
end
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index edd680ee1d1..88b5d87f087 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -629,4 +629,103 @@ describe ProjectsHelper do
end
end
end
+
+ describe '#show_auto_devops_implicitly_enabled_banner?' do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:user) { create(:user) }
+
+ let(:feature_visibilities) do
+ {
+ enabled: ProjectFeature::ENABLED,
+ disabled: ProjectFeature::DISABLED
+ }
+ end
+
+ where(:global_setting, :project_setting, :builds_visibility, :gitlab_ci_yml, :user_access, :result) do
+ # With ADO implicitly enabled scenarios
+ true | nil | :disabled | true | :developer | false
+ true | nil | :disabled | true | :maintainer | false
+ true | nil | :disabled | true | :owner | false
+
+ true | nil | :disabled | false | :developer | false
+ true | nil | :disabled | false | :maintainer | false
+ true | nil | :disabled | false | :owner | false
+
+ true | nil | :enabled | true | :developer | false
+ true | nil | :enabled | true | :maintainer | false
+ true | nil | :enabled | true | :owner | false
+
+ true | nil | :enabled | false | :developer | false
+ true | nil | :enabled | false | :maintainer | true
+ true | nil | :enabled | false | :owner | true
+
+ # With ADO enabled scenarios
+ true | true | :disabled | true | :developer | false
+ true | true | :disabled | true | :maintainer | false
+ true | true | :disabled | true | :owner | false
+
+ true | true | :disabled | false | :developer | false
+ true | true | :disabled | false | :maintainer | false
+ true | true | :disabled | false | :owner | false
+
+ true | true | :enabled | true | :developer | false
+ true | true | :enabled | true | :maintainer | false
+ true | true | :enabled | true | :owner | false
+
+ true | true | :enabled | false | :developer | false
+ true | true | :enabled | false | :maintainer | false
+ true | true | :enabled | false | :owner | false
+
+ # With ADO disabled scenarios
+ true | false | :disabled | true | :developer | false
+ true | false | :disabled | true | :maintainer | false
+ true | false | :disabled | true | :owner | false
+
+ true | false | :disabled | false | :developer | false
+ true | false | :disabled | false | :maintainer | false
+ true | false | :disabled | false | :owner | false
+
+ true | false | :enabled | true | :developer | false
+ true | false | :enabled | true | :maintainer | false
+ true | false | :enabled | true | :owner | false
+
+ true | false | :enabled | false | :developer | false
+ true | false | :enabled | false | :maintainer | false
+ true | false | :enabled | false | :owner | false
+ end
+
+ def grant_user_access(project, user, access)
+ case access
+ when :developer, :maintainer
+ project.add_user(user, access)
+ when :owner
+ project.namespace.update(owner: user)
+ end
+ end
+
+ with_them do
+ let(:project) do
+ if project_setting.nil?
+ create(:project, :repository)
+ else
+ create(:project, :repository, :auto_devops)
+ end
+ end
+
+ before do
+ stub_application_setting(auto_devops_enabled: global_setting)
+
+ allow_any_instance_of(Repository).to receive(:gitlab_ci_yml).and_return(gitlab_ci_yml)
+
+ grant_user_access(project, user, user_access)
+ project.project_feature.update_attribute(:builds_access_level, feature_visibilities[builds_visibility])
+ project.auto_devops.update_attribute(:enabled, project_setting) unless project_setting.nil?
+ end
+
+ subject { helper.show_auto_devops_implicitly_enabled_banner?(project, user) }
+
+ it { is_expected.to eq(result) }
+ end
+ end
end
diff --git a/spec/helpers/user_callouts_helper_spec.rb b/spec/helpers/user_callouts_helper_spec.rb
index 27455705d23..8fa479a4474 100644
--- a/spec/helpers/user_callouts_helper_spec.rb
+++ b/spec/helpers/user_callouts_helper_spec.rb
@@ -44,4 +44,13 @@ describe UserCalloutsHelper do
it { is_expected.to be false }
end
end
+
+ describe '.render_flash_user_callout' do
+ it 'renders the flash_user_callout partial' do
+ expect(helper).to receive(:render)
+ .with(/flash_user_callout/, flash_type: :warning, message: 'foo', feature_name: 'bar')
+
+ helper.render_flash_user_callout(:warning, 'foo', 'bar')
+ end
+ end
end
diff --git a/spec/javascripts/clusters/stores/clusters_store_spec.js b/spec/javascripts/clusters/stores/clusters_store_spec.js
index 1ca55549094..dfce2656e4c 100644
--- a/spec/javascripts/clusters/stores/clusters_store_spec.js
+++ b/spec/javascripts/clusters/stores/clusters_store_spec.js
@@ -62,6 +62,7 @@ describe('Clusters Store', () => {
ingressHelpPath: null,
status: mockResponseData.status,
statusReason: mockResponseData.status_reason,
+ rbac: false,
applications: {
helm: {
title: 'Helm Tiller',
diff --git a/spec/javascripts/diffs/components/commit_item_spec.js b/spec/javascripts/diffs/components/commit_item_spec.js
index 8b2ca6506c4..50e45f48af3 100644
--- a/spec/javascripts/diffs/components/commit_item_spec.js
+++ b/spec/javascripts/diffs/components/commit_item_spec.js
@@ -80,6 +80,8 @@ describe('diffs/components/commit_item', () => {
expect(trimText(committerElement.textContent)).toEqual(expectedText);
expect(nameElement).toHaveAttr('href', commit.author.web_url);
expect(nameElement).toHaveText(commit.author.name);
+ expect(nameElement).toHaveClass('js-user-link');
+ expect(nameElement.dataset.userId).toEqual(commit.author.id.toString());
});
describe('without commit description', () => {
diff --git a/spec/javascripts/fixtures/jobs.rb b/spec/javascripts/fixtures/jobs.rb
index d6b5349594d..433bb690a1c 100644
--- a/spec/javascripts/fixtures/jobs.rb
+++ b/spec/javascripts/fixtures/jobs.rb
@@ -14,8 +14,7 @@ describe Projects::JobsController, '(JavaScript fixtures)', type: :controller do
create(:ci_build, :scheduled,
pipeline: pipeline,
name: 'delayed job',
- stage: 'test',
- commands: 'test')
+ stage: 'test')
end
render_views
diff --git a/spec/javascripts/ide/components/file_finder/index_spec.js b/spec/javascripts/ide/components/file_finder/index_spec.js
index 4d934f92f72..15ef8c31f91 100644
--- a/spec/javascripts/ide/components/file_finder/index_spec.js
+++ b/spec/javascripts/ide/components/file_finder/index_spec.js
@@ -56,7 +56,6 @@ describe('IDE File finder item spec', () => {
it('renders list of blobs', () => {
expect(vm.$el.textContent).toContain('index.js');
- expect(vm.$el.textContent).toContain('component.js');
expect(vm.$el.textContent).not.toContain('folder');
});
diff --git a/spec/javascripts/notes/components/comment_form_spec.js b/spec/javascripts/notes/components/comment_form_spec.js
index 3c57fe51352..362963ddaf4 100644
--- a/spec/javascripts/notes/components/comment_form_spec.js
+++ b/spec/javascripts/notes/components/comment_form_spec.js
@@ -223,7 +223,6 @@ describe('issue_comment_form component', () => {
'Comment & close issue',
);
- expect(vm.$el.querySelector('.js-note-discard')).toBeDefined();
done();
});
});
diff --git a/spec/javascripts/releases/components/release_block_spec.js b/spec/javascripts/releases/components/release_block_spec.js
index 29420216bc4..1268cdad08d 100644
--- a/spec/javascripts/releases/components/release_block_spec.js
+++ b/spec/javascripts/releases/components/release_block_spec.js
@@ -133,4 +133,8 @@ describe('Release block', () => {
release.assets.links[0].name,
);
});
+
+ it('renders author avatar', () => {
+ expect(vm.$el.querySelector('.user-avatar-link')).not.toBeNull();
+ });
});
diff --git a/spec/javascripts/vue_shared/components/markdown/suggestions_spec.js b/spec/javascripts/vue_shared/components/markdown/suggestions_spec.js
index ab1b747c360..423cd6dee0f 100644
--- a/spec/javascripts/vue_shared/components/markdown/suggestions_spec.js
+++ b/spec/javascripts/vue_shared/components/markdown/suggestions_spec.js
@@ -29,7 +29,7 @@ const generateLine = content => {
const generateMockLines = () => {
const line1 = generateLine('Line 1');
const line2 = generateLine('Line 2');
- const line3 = generateLine('Line 3');
+ const line3 = generateLine('- Line 3');
const container = document.createElement('div');
container.appendChild(line1);
@@ -80,7 +80,7 @@ describe('Suggestion component', () => {
const expectedReturn = [
{ content: 'Line 1\n', lineNumber: 1 },
{ content: 'Line 2\n', lineNumber: 2 },
- { content: 'Line 3\n', lineNumber: 3 },
+ { content: '- Line 3\n', lineNumber: 3 },
];
expect(vm.extractNewLines(generateMockLines())).toEqual(expectedReturn);
diff --git a/spec/javascripts/vue_shared/components/user_avatar/user_avatar_list_spec.js b/spec/javascripts/vue_shared/components/user_avatar/user_avatar_list_spec.js
new file mode 100644
index 00000000000..64aa7e29718
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/user_avatar/user_avatar_list_spec.js
@@ -0,0 +1,130 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import { GlButton } from '@gitlab/ui';
+import { TEST_HOST } from 'spec/test_constants';
+import UserAvatarList from '~/vue_shared/components/user_avatar/user_avatar_list.vue';
+import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
+
+const TEST_IMAGE_SIZE = 7;
+const TEST_BREAKPOINT = 5;
+
+const createUser = id => ({
+ id,
+ name: 'Lorem',
+ web_url: `${TEST_HOST}/${id}`,
+ avatar_url: `${TEST_HOST}/${id}/avatar`,
+});
+const createList = n =>
+ Array(n)
+ .fill(1)
+ .map((x, id) => createUser(id));
+
+const localVue = createLocalVue();
+
+describe('UserAvatarList', () => {
+ let propsData;
+ let wrapper;
+
+ const factory = options => {
+ wrapper = shallowMount(localVue.extend(UserAvatarList), {
+ localVue,
+ propsData,
+ ...options,
+ });
+ };
+
+ const clickButton = () => {
+ const button = wrapper.find(GlButton);
+ button.vm.$emit('click');
+ };
+
+ beforeEach(() => {
+ propsData = { imgSize: TEST_IMAGE_SIZE };
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('with no breakpoint', () => {
+ beforeEach(() => {
+ propsData.breakpoint = 0;
+ });
+
+ it('renders avatars', () => {
+ const items = createList(20);
+ propsData.items = items;
+ factory();
+
+ const links = wrapper.findAll(UserAvatarLink);
+ const linkProps = links.wrappers.map(x => x.props());
+
+ expect(linkProps).toEqual(
+ propsData.items.map(x =>
+ jasmine.objectContaining({
+ linkHref: x.web_url,
+ imgSrc: x.avatar_url,
+ imgAlt: x.name,
+ tooltipText: x.name,
+ imgSize: TEST_IMAGE_SIZE,
+ }),
+ ),
+ );
+ });
+ });
+
+ describe('with breakpoint and length equal to breakpoint', () => {
+ beforeEach(() => {
+ propsData.breakpoint = TEST_BREAKPOINT;
+ propsData.items = createList(TEST_BREAKPOINT);
+ });
+
+ it('renders all avatars if length is <= breakpoint', () => {
+ factory();
+
+ const links = wrapper.findAll(UserAvatarLink);
+
+ expect(links.length).toEqual(propsData.items.length);
+ });
+
+ it('does not show button', () => {
+ factory();
+
+ expect(wrapper.find(GlButton).exists()).toBe(false);
+ });
+ });
+
+ describe('with breakpoint and length greater than breakpoint', () => {
+ beforeEach(() => {
+ propsData.breakpoint = TEST_BREAKPOINT;
+ propsData.items = createList(TEST_BREAKPOINT + 1);
+ });
+
+ it('renders avatars up to breakpoint', () => {
+ factory();
+
+ const links = wrapper.findAll(UserAvatarLink);
+
+ expect(links.length).toEqual(TEST_BREAKPOINT);
+ });
+
+ describe('with expand clicked', () => {
+ beforeEach(() => {
+ factory();
+ clickButton();
+ });
+
+ it('renders all avatars', () => {
+ const links = wrapper.findAll(UserAvatarLink);
+
+ expect(links.length).toEqual(propsData.items.length);
+ });
+
+ it('with collapse clicked, it renders avatars up to breakpoint', () => {
+ clickButton();
+ const links = wrapper.findAll(UserAvatarLink);
+
+ expect(links.length).toEqual(TEST_BREAKPOINT);
+ });
+ });
+ });
+});
diff --git a/spec/lib/bitbucket_server/paginator_spec.rb b/spec/lib/bitbucket_server/paginator_spec.rb
index d268d4f23cf..eadd7f68bfb 100644
--- a/spec/lib/bitbucket_server/paginator_spec.rb
+++ b/spec/lib/bitbucket_server/paginator_spec.rb
@@ -30,6 +30,17 @@ describe BitbucketServer::Paginator do
expect { limited.items }.to raise_error(StopIteration)
end
+ it 'does not stop if limit is unspecified' do
+ stub_const("BitbucketServer::Paginator::PAGE_LENGTH", 1)
+ paginator = described_class.new(connection, 'http://more-data', :pull_request, page_offset: 0, limit: nil)
+ allow(paginator).to receive(:fetch_next_page).and_return(first_page, last_page)
+
+ expect(paginator.has_next_page?).to be_truthy
+ expect(paginator.items).to match(['item_1'])
+ expect(paginator.has_next_page?).to be_truthy
+ expect(paginator.items).to match(['item_2'])
+ end
+
it 'calls the connection with different offsets' do
expect(connection).to receive(:get).with('http://more-data', start: 0, limit: BitbucketServer::Paginator::PAGE_LENGTH).and_return(page_attrs)
diff --git a/spec/lib/gitlab/background_migration/populate_external_pipeline_source_spec.rb b/spec/lib/gitlab/background_migration/populate_external_pipeline_source_spec.rb
index c7b272cd6ca..6ab126ad39a 100644
--- a/spec/lib/gitlab/background_migration/populate_external_pipeline_source_spec.rb
+++ b/spec/lib/gitlab/background_migration/populate_external_pipeline_source_spec.rb
@@ -5,6 +5,11 @@ require 'spec_helper'
describe Gitlab::BackgroundMigration::PopulateExternalPipelineSource, :migration, schema: 20180916011959 do
let(:migration) { described_class.new }
+ before do
+ # This migration was created before we introduced metadata configs
+ stub_feature_flags(ci_build_metadata_config: false)
+ end
+
let!(:internal_pipeline) { create(:ci_pipeline, source: :web) }
let(:pipelines) { [internal_pipeline, unknown_pipeline].map(&:id) }
diff --git a/spec/lib/gitlab/ci/build/step_spec.rb b/spec/lib/gitlab/ci/build/step_spec.rb
index cce4efaa069..e3136fc925e 100644
--- a/spec/lib/gitlab/ci/build/step_spec.rb
+++ b/spec/lib/gitlab/ci/build/step_spec.rb
@@ -18,13 +18,6 @@ describe Gitlab::Ci::Build::Step do
end
end
- context 'when commands are specified' do
- it_behaves_like 'has correct script' do
- let(:job) { create(:ci_build, :no_options, commands: "ls -la\ndate") }
- let(:script) { ['ls -la', 'date'] }
- end
- end
-
context 'when script option is specified' do
it_behaves_like 'has correct script' do
let(:job) { create(:ci_build, :no_options, options: { script: ["ls -la\necho aaa", "date"] }) }
@@ -62,7 +55,7 @@ describe Gitlab::Ci::Build::Step do
end
context 'when after_script is not empty' do
- let(:job) { create(:ci_build, options: { after_script: ['ls -la', 'date'] }) }
+ let(:job) { create(:ci_build, options: { script: ['bash'], after_script: ['ls -la', 'date'] }) }
it 'fabricates an object' do
expect(subject.name).to eq(:after_script)
diff --git a/spec/lib/gitlab/ci/config/entry/global_spec.rb b/spec/lib/gitlab/ci/config/entry/global_spec.rb
index 61d78f86b51..941ef33c8a4 100644
--- a/spec/lib/gitlab/ci/config/entry/global_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/global_spec.rb
@@ -153,7 +153,6 @@ describe Gitlab::Ci::Config::Entry::Global do
rspec: { name: :rspec,
script: %w[rspec ls],
before_script: %w(ls pwd),
- commands: "ls\npwd\nrspec\nls",
image: { name: 'ruby:2.2' },
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
@@ -166,7 +165,6 @@ describe Gitlab::Ci::Config::Entry::Global do
spinach: { name: :spinach,
before_script: [],
script: %w[spinach],
- commands: 'spinach',
image: { name: 'ruby:2.2' },
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb
index 8e32cede3b5..3d0b98eb238 100644
--- a/spec/lib/gitlab/ci/config/entry/job_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb
@@ -255,7 +255,6 @@ describe Gitlab::Ci::Config::Entry::Job do
.to eq(name: :rspec,
before_script: %w[ls pwd],
script: %w[rspec],
- commands: "ls\npwd\nrspec",
stage: 'test',
ignore: false,
after_script: %w[cleanup],
@@ -264,16 +263,6 @@ describe Gitlab::Ci::Config::Entry::Job do
end
end
end
-
- describe '#commands' do
- let(:config) do
- { before_script: %w[ls pwd], script: 'rspec' }
- end
-
- it 'returns a string of commands concatenated with new line character' do
- expect(entry.commands).to eq "ls\npwd\nrspec"
- end
- end
end
describe '#manual_action?' do
diff --git a/spec/lib/gitlab/ci/config/entry/jobs_spec.rb b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
index 1a2c30d3571..d97be76f0e0 100644
--- a/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
@@ -65,14 +65,12 @@ describe Gitlab::Ci::Config::Entry::Jobs do
expect(entry.value).to eq(
rspec: { name: :rspec,
script: %w[rspec],
- commands: 'rspec',
ignore: false,
stage: 'test',
only: { refs: %w[branches tags] },
except: {} },
spinach: { name: :spinach,
script: %w[spinach],
- commands: 'spinach',
ignore: false,
stage: 'test',
only: { refs: %w[branches tags] },
diff --git a/spec/lib/gitlab/ci/config/external/file/base_spec.rb b/spec/lib/gitlab/ci/config/external/file/base_spec.rb
index ada8775c489..1a6b3587599 100644
--- a/spec/lib/gitlab/ci/config/external/file/base_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/base_spec.rb
@@ -3,7 +3,7 @@
require 'fast_spec_helper'
describe Gitlab::Ci::Config::External::File::Base do
- let(:context) { described_class::Context.new(nil, 'HEAD') }
+ let(:context) { described_class::Context.new(nil, 'HEAD', nil) }
let(:test_class) do
Class.new(described_class) do
diff --git a/spec/lib/gitlab/ci/config/external/file/local_spec.rb b/spec/lib/gitlab/ci/config/external/file/local_spec.rb
index 83be43e240b..ff67a765da0 100644
--- a/spec/lib/gitlab/ci/config/external/file/local_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/local_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
describe Gitlab::Ci::Config::External::File::Local do
set(:project) { create(:project, :repository) }
- let(:context) { described_class::Context.new(project, '12345') }
+ let(:context) { described_class::Context.new(project, '12345', nil) }
let(:params) { { local: location } }
let(:local_file) { described_class.new(params, context) }
diff --git a/spec/lib/gitlab/ci/config/external/file/project_spec.rb b/spec/lib/gitlab/ci/config/external/file/project_spec.rb
new file mode 100644
index 00000000000..11809adcaf6
--- /dev/null
+++ b/spec/lib/gitlab/ci/config/external/file/project_spec.rb
@@ -0,0 +1,151 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Ci::Config::External::File::Project do
+ set(:project) { create(:project, :repository) }
+ set(:user) { create(:user) }
+
+ let(:context_user) { user }
+ let(:context) { described_class::Context.new(nil, '12345', context_user) }
+ let(:subject) { described_class.new(params, context) }
+
+ before do
+ project.add_developer(user)
+ end
+
+ describe '#matching?' do
+ context 'when a file and project is specified' do
+ let(:params) { { file: 'file.yml', project: 'project' } }
+
+ it 'should return true' do
+ expect(subject).to be_matching
+ end
+ end
+
+ context 'with only file is specified' do
+ let(:params) { { file: 'file.yml' } }
+
+ it 'should return false' do
+ expect(subject).not_to be_matching
+ end
+ end
+
+ context 'with only project is specified' do
+ let(:params) { { project: 'project' } }
+
+ it 'should return false' do
+ expect(subject).not_to be_matching
+ end
+ end
+
+ context 'with a missing local key' do
+ let(:params) { {} }
+
+ it 'should return false' do
+ expect(subject).not_to be_matching
+ end
+ end
+ end
+
+ describe '#valid?' do
+ context 'when a valid path is used' do
+ let(:params) do
+ { project: project.full_path, file: '/file.yml' }
+ end
+
+ let(:root_ref_sha) { project.repository.root_ref_sha }
+
+ before do
+ stub_project_blob(root_ref_sha, '/file.yml') { 'image: ruby:2.1' }
+ end
+
+ it 'should return true' do
+ expect(subject).to be_valid
+ end
+
+ context 'when user does not have permission to access file' do
+ let(:context_user) { create(:user) }
+
+ it 'should return false' do
+ expect(subject).not_to be_valid
+ expect(subject.error_message).to include("Project `#{project.full_path}` not found or access denied!")
+ end
+ end
+ end
+
+ context 'when a valid path with custom ref is used' do
+ let(:params) do
+ { project: project.full_path, ref: 'master', file: '/file.yml' }
+ end
+
+ let(:ref_sha) { project.commit('master').sha }
+
+ before do
+ stub_project_blob(ref_sha, '/file.yml') { 'image: ruby:2.1' }
+ end
+
+ it 'should return true' do
+ expect(subject).to be_valid
+ end
+ end
+
+ context 'when an empty file is used' do
+ let(:params) do
+ { project: project.full_path, file: '/file.yml' }
+ end
+
+ let(:root_ref_sha) { project.repository.root_ref_sha }
+
+ before do
+ stub_project_blob(root_ref_sha, '/file.yml') { '' }
+ end
+
+ it 'should return false' do
+ expect(subject).not_to be_valid
+ expect(subject.error_message).to include("Project `#{project.full_path}` file `/file.yml` is empty!")
+ end
+ end
+
+ context 'when non-existing ref is used' do
+ let(:params) do
+ { project: project.full_path, ref: 'I-Do-Not-Exist', file: '/file.yml' }
+ end
+
+ it 'should return false' do
+ expect(subject).not_to be_valid
+ expect(subject.error_message).to include("Project `#{project.full_path}` reference `I-Do-Not-Exist` does not exist!")
+ end
+ end
+
+ context 'when non-existing file is requested' do
+ let(:params) do
+ { project: project.full_path, file: '/invalid-file.yml' }
+ end
+
+ it 'should return false' do
+ expect(subject).not_to be_valid
+ expect(subject.error_message).to include("Project `#{project.full_path}` file `/invalid-file.yml` does not exist!")
+ end
+ end
+
+ context 'when file is not a yaml file' do
+ let(:params) do
+ { project: project.full_path, file: '/invalid-file' }
+ end
+
+ it 'should return false' do
+ expect(subject).not_to be_valid
+ expect(subject.error_message).to include('Included file `/invalid-file` does not have YAML extension!')
+ end
+ end
+ end
+
+ private
+
+ def stub_project_blob(ref, path)
+ allow_any_instance_of(Repository)
+ .to receive(:blob_data_at)
+ .with(ref, path) { yield }
+ end
+end
diff --git a/spec/lib/gitlab/ci/config/external/file/remote_spec.rb b/spec/lib/gitlab/ci/config/external/file/remote_spec.rb
index 319e7137f9f..3e0fda9c308 100644
--- a/spec/lib/gitlab/ci/config/external/file/remote_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/remote_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
describe Gitlab::Ci::Config::External::File::Remote do
- let(:context) { described_class::Context.new(nil, '12345') }
+ let(:context) { described_class::Context.new(nil, '12345', nil) }
let(:params) { { remote: location } }
let(:remote_file) { described_class.new(params, context) }
let(:location) { 'https://gitlab.com/gitlab-org/gitlab-ce/blob/1234/.gitlab-ci-1.yml' }
diff --git a/spec/lib/gitlab/ci/config/external/mapper_spec.rb b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
index e27d2cd9422..4cab4961b0f 100644
--- a/spec/lib/gitlab/ci/config/external/mapper_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
describe Gitlab::Ci::Config::External::Mapper do
set(:project) { create(:project, :repository) }
+ set(:user) { create(:user) }
let(:local_file) { '/lib/gitlab/ci/templates/non-existent-file.yml' }
let(:remote_url) { 'https://gitlab.com/gitlab-org/gitlab-ce/blob/1234/.gitlab-ci-1.yml' }
@@ -20,7 +21,7 @@ describe Gitlab::Ci::Config::External::Mapper do
end
describe '#process' do
- subject { described_class.new(values, project: project, sha: '123456').process }
+ subject { described_class.new(values, project: project, sha: '123456', user: user).process }
context "when single 'include' keyword is defined" do
context 'when the string is a local file' do
diff --git a/spec/lib/gitlab/ci/config/external/processor_spec.rb b/spec/lib/gitlab/ci/config/external/processor_spec.rb
index d2d4fbc5115..1ac58139b25 100644
--- a/spec/lib/gitlab/ci/config/external/processor_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/processor_spec.rb
@@ -4,8 +4,13 @@ require 'spec_helper'
describe Gitlab::Ci::Config::External::Processor do
set(:project) { create(:project, :repository) }
+ set(:user) { create(:user) }
- let(:processor) { described_class.new(values, project: project, sha: '12345') }
+ let(:processor) { described_class.new(values, project: project, sha: '12345', user: user) }
+
+ before do
+ project.add_developer(user)
+ end
describe "#perform" do
context 'when no external files defined' do
diff --git a/spec/lib/gitlab/ci/config_spec.rb b/spec/lib/gitlab/ci/config_spec.rb
index 49988468d1a..cd6d2a2f343 100644
--- a/spec/lib/gitlab/ci/config_spec.rb
+++ b/spec/lib/gitlab/ci/config_spec.rb
@@ -1,8 +1,10 @@
require 'spec_helper'
describe Gitlab::Ci::Config do
+ set(:user) { create(:user) }
+
let(:config) do
- described_class.new(yml)
+ described_class.new(yml, project: nil, sha: nil, user: nil)
end
context 'when config is valid' do
@@ -154,7 +156,7 @@ describe Gitlab::Ci::Config do
end
let(:config) do
- described_class.new(gitlab_ci_yml, project: project, sha: '12345')
+ described_class.new(gitlab_ci_yml, project: project, sha: '12345', user: user)
end
before do
@@ -228,7 +230,7 @@ describe Gitlab::Ci::Config do
expect(project.repository).to receive(:blob_data_at)
.with('eeff1122', local_location)
- described_class.new(gitlab_ci_yml, project: project, sha: 'eeff1122')
+ described_class.new(gitlab_ci_yml, project: project, sha: 'eeff1122', user: user)
end
end
@@ -236,7 +238,7 @@ describe Gitlab::Ci::Config do
it 'is using latest SHA on the default branch' do
expect(project.repository).to receive(:root_ref_sha)
- described_class.new(gitlab_ci_yml, project: project)
+ described_class.new(gitlab_ci_yml, project: project, sha: nil, user: user)
end
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
index 2cf812b26dc..a700cfd4546 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
@@ -6,8 +6,7 @@ describe Gitlab::Ci::Pipeline::Seed::Build do
let(:attributes) do
{ name: 'rspec',
- ref: 'master',
- commands: 'rspec' }
+ ref: 'master' }
end
subject do
@@ -18,7 +17,7 @@ describe Gitlab::Ci::Pipeline::Seed::Build do
it 'returns hash attributes of a build' do
expect(subject.attributes).to be_a Hash
expect(subject.attributes)
- .to include(:name, :project, :ref, :commands)
+ .to include(:name, :project, :ref)
end
end
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index 441e8214181..b6c3431728c 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -3,10 +3,10 @@ require 'spec_helper'
module Gitlab
module Ci
describe YamlProcessor do
- subject { described_class.new(config) }
+ subject { described_class.new(config, user: nil) }
describe '#build_attributes' do
- subject { described_class.new(config).build_attributes(:rspec) }
+ subject { described_class.new(config, user: nil).build_attributes(:rspec) }
describe 'attributes list' do
let(:config) do
@@ -21,7 +21,6 @@ module Gitlab
stage: "test",
stage_idx: 1,
name: "rspec",
- commands: "pwd\nrspec",
coverage_regex: nil,
tag_list: [],
options: {
@@ -155,7 +154,6 @@ module Gitlab
builds:
[{ stage_idx: 1,
stage: "test",
- commands: "rspec",
tag_list: [],
name: "rspec",
allow_failure: false,
@@ -171,7 +169,6 @@ module Gitlab
builds:
[{ stage_idx: 2,
stage: "deploy",
- commands: "cap prod",
tag_list: [],
name: "prod",
allow_failure: false,
@@ -271,7 +268,7 @@ module Gitlab
end
it "return commands with scripts concencaced" do
- expect(subject[:commands]).to eq("global script\nscript")
+ expect(subject[:options][:before_script]).to eq(["global script"])
end
end
@@ -284,7 +281,7 @@ module Gitlab
end
it "return commands with scripts concencaced" do
- expect(subject[:commands]).to eq("local script\nscript")
+ expect(subject[:options][:before_script]).to eq(["local script"])
end
end
end
@@ -297,7 +294,7 @@ module Gitlab
end
it "return commands with scripts concencaced" do
- expect(subject[:commands]).to eq("script")
+ expect(subject[:options][:script]).to eq(["script"])
end
end
@@ -347,7 +344,6 @@ module Gitlab
stage: "test",
stage_idx: 1,
name: "rspec",
- commands: "pwd\nrspec",
coverage_regex: nil,
tag_list: [],
options: {
@@ -382,7 +378,6 @@ module Gitlab
stage: "test",
stage_idx: 1,
name: "rspec",
- commands: "pwd\nrspec",
coverage_regex: nil,
tag_list: [],
options: {
@@ -415,7 +410,6 @@ module Gitlab
stage: "test",
stage_idx: 1,
name: "rspec",
- commands: "pwd\nrspec",
coverage_regex: nil,
tag_list: [],
options: {
@@ -444,7 +438,6 @@ module Gitlab
stage: "test",
stage_idx: 1,
name: "rspec",
- commands: "pwd\nrspec",
coverage_regex: nil,
tag_list: [],
options: {
@@ -596,7 +589,7 @@ module Gitlab
it 'correctly extends rspec job' do
expect(config_processor.builds).to be_one
- expect(subject.dig(:commands)).to eq 'test'
+ expect(subject.dig(:options, :script)).to eq %w(test)
expect(subject.dig(:options, :image, :name)).to eq 'ruby:alpine'
end
end
@@ -622,7 +615,8 @@ module Gitlab
it 'correctly extends rspec job' do
expect(config_processor.builds).to be_one
- expect(subject.dig(:commands)).to eq "bundle install\nrspec"
+ expect(subject.dig(:options, :before_script)).to eq ["bundle install"]
+ expect(subject.dig(:options, :script)).to eq %w(rspec)
expect(subject.dig(:options, :image, :name)).to eq 'image:test'
expect(subject.dig(:when)).to eq 'always'
end
@@ -769,7 +763,6 @@ module Gitlab
stage: "test",
stage_idx: 1,
name: "rspec",
- commands: "pwd\nrspec",
coverage_regex: nil,
tag_list: [],
options: {
@@ -983,7 +976,6 @@ module Gitlab
stage: "test",
stage_idx: 1,
name: "normal_job",
- commands: "test",
coverage_regex: nil,
tag_list: [],
options: {
@@ -1031,7 +1023,6 @@ module Gitlab
stage: "build",
stage_idx: 0,
name: "job1",
- commands: "execute-script-for-job",
coverage_regex: nil,
tag_list: [],
options: {
@@ -1046,7 +1037,6 @@ module Gitlab
stage: "build",
stage_idx: 0,
name: "job2",
- commands: "execute-script-for-job",
coverage_regex: nil,
tag_list: [],
options: {
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index d3cae137c3c..5afa9669b1a 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -314,6 +314,7 @@ project:
- repository_languages
- pool_repository
- kubernetes_namespaces
+- error_tracking_setting
award_emoji:
- awardable
- user
@@ -345,3 +346,5 @@ resource_label_events:
- merge_request
- epic
- label
+error_tracking_setting:
+- project
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index 2422868474e..fe2087e8fc3 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -600,3 +600,8 @@ ResourceLabelEvent:
- label_id
- user_id
- created_at
+ErrorTracking::ProjectErrorTrackingSetting:
+- id
+- api_url
+- enabled
+- project_id
diff --git a/spec/lib/gitlab/middleware/multipart_spec.rb b/spec/lib/gitlab/middleware/multipart_spec.rb
index daf454665b0..3f6ada6832a 100644
--- a/spec/lib/gitlab/middleware/multipart_spec.rb
+++ b/spec/lib/gitlab/middleware/multipart_spec.rb
@@ -10,7 +10,9 @@ describe Gitlab::Middleware::Multipart do
shared_examples_for 'multipart upload files' do
it 'opens top-level files' do
Tempfile.open('top-level') do |tempfile|
- env = post_env({ 'file' => tempfile.path }, { 'file.name' => original_filename, 'file.path' => tempfile.path, 'file.remote_id' => remote_id }, Gitlab::Workhorse.secret, 'gitlab-workhorse')
+ rewritten = { 'file' => tempfile.path }
+ in_params = { 'file.name' => original_filename, 'file.path' => tempfile.path, 'file.remote_id' => remote_id }
+ env = post_env(rewritten, in_params, Gitlab::Workhorse.secret, 'gitlab-workhorse')
expect_uploaded_file(tempfile, %w(file))
@@ -21,7 +23,8 @@ describe Gitlab::Middleware::Multipart do
it 'opens files one level deep' do
Tempfile.open('one-level') do |tempfile|
in_params = { 'user' => { 'avatar' => { '.name' => original_filename, '.path' => tempfile.path, '.remote_id' => remote_id } } }
- env = post_env({ 'user[avatar]' => tempfile.path }, in_params, Gitlab::Workhorse.secret, 'gitlab-workhorse')
+ rewritten = { 'user[avatar]' => tempfile.path }
+ env = post_env(rewritten, in_params, Gitlab::Workhorse.secret, 'gitlab-workhorse')
expect_uploaded_file(tempfile, %w(user avatar))
@@ -32,7 +35,8 @@ describe Gitlab::Middleware::Multipart do
it 'opens files two levels deep' do
Tempfile.open('two-levels') do |tempfile|
in_params = { 'project' => { 'milestone' => { 'themesong' => { '.name' => original_filename, '.path' => tempfile.path, '.remote_id' => remote_id } } } }
- env = post_env({ 'project[milestone][themesong]' => tempfile.path }, in_params, Gitlab::Workhorse.secret, 'gitlab-workhorse')
+ rewritten = { 'project[milestone][themesong]' => tempfile.path }
+ env = post_env(rewritten, in_params, Gitlab::Workhorse.secret, 'gitlab-workhorse')
expect_uploaded_file(tempfile, %w(project milestone themesong))
@@ -42,7 +46,7 @@ describe Gitlab::Middleware::Multipart do
def expect_uploaded_file(tempfile, path, remote: false)
expect(app).to receive(:call) do |env|
- file = Rack::Request.new(env).params.dig(*path)
+ file = get_params(env).dig(*path)
expect(file).to be_a(::UploadedFile)
expect(file.path).to eq(tempfile.path)
expect(file.original_filename).to eq(original_filename)
@@ -87,7 +91,7 @@ describe Gitlab::Middleware::Multipart do
env = post_env({ 'file' => tempfile.path }, { 'file.name' => original_filename, 'file.path' => tempfile.path }, Gitlab::Workhorse.secret, 'gitlab-workhorse')
expect(app).to receive(:call) do |env|
- expect(Rack::Request.new(env).params['file']).to be_a(::UploadedFile)
+ expect(get_params(env)['file']).to be_a(::UploadedFile)
end
middleware.call(env)
@@ -115,13 +119,21 @@ describe Gitlab::Middleware::Multipart do
allow(Dir).to receive(:tmpdir).and_return(File.join(Dir.tmpdir, 'tmpsubdir'))
expect(app).to receive(:call) do |env|
- expect(Rack::Request.new(env).params['file']).to be_a(::UploadedFile)
+ expect(get_params(env)['file']).to be_a(::UploadedFile)
end
middleware.call(env)
end
end
+ # Rails 5 doesn't combine the GET/POST parameters in
+ # ActionDispatch::HTTP::Parameters if action_dispatch.request.parameters is set:
+ # https://github.com/rails/rails/blob/aea6423f013ca48f7704c70deadf2cd6ac7d70a1/actionpack/lib/action_dispatch/http/parameters.rb#L41
+ def get_params(env)
+ req = ActionDispatch::Request.new(env)
+ req.GET.merge(req.POST)
+ end
+
def post_env(rewritten_fields, params, secret, issuer)
token = JWT.encode({ 'iss' => issuer, 'rewritten_fields' => rewritten_fields }, secret, 'HS256')
Rack::MockRequest.env_for(
diff --git a/spec/lib/gitlab/utils_spec.rb b/spec/lib/gitlab/utils_spec.rb
index f5a4b7e2ebf..8f5029b3565 100644
--- a/spec/lib/gitlab/utils_spec.rb
+++ b/spec/lib/gitlab/utils_spec.rb
@@ -197,4 +197,20 @@ describe Gitlab::Utils do
end
end
end
+
+ describe '.deep_indifferent_access' do
+ let(:hash) do
+ { "variables" => [{ "key" => "VAR1", "value" => "VALUE2" }] }
+ end
+
+ subject { described_class.deep_indifferent_access(hash) }
+
+ it 'allows to access hash keys with symbols' do
+ expect(subject[:variables]).to be_a(Array)
+ end
+
+ it 'allows to access array keys with symbols' do
+ expect(subject[:variables].first[:key]).to eq('VAR1')
+ end
+ end
end
diff --git a/spec/lib/serializers/json_spec.rb b/spec/lib/serializers/json_spec.rb
new file mode 100644
index 00000000000..5d59d66e8b8
--- /dev/null
+++ b/spec/lib/serializers/json_spec.rb
@@ -0,0 +1,102 @@
+require 'fast_spec_helper'
+
+describe Serializers::JSON do
+ describe '.dump' do
+ let(:obj) { { key: "value" } }
+
+ subject { described_class.dump(obj) }
+
+ context 'when MySQL is used' do
+ before do
+ allow(Gitlab::Database).to receive(:adapter_name) { 'mysql2' }
+ end
+
+ it 'encodes as string' do
+ is_expected.to eq('{"key":"value"}')
+ end
+ end
+
+ context 'when PostgreSQL is used' do
+ before do
+ allow(Gitlab::Database).to receive(:adapter_name) { 'postgresql' }
+ end
+
+ it 'returns a hash' do
+ is_expected.to eq(obj)
+ end
+ end
+ end
+
+ describe '.load' do
+ let(:data_string) { '{"key":"value","variables":[{"key":"VAR1","value":"VALUE1"}]}' }
+ let(:data_hash) { JSON.parse(data_string) }
+
+ shared_examples 'having consistent accessor' do
+ it 'allows to access with symbols' do
+ expect(subject[:key]).to eq('value')
+ expect(subject[:variables].first[:key]).to eq('VAR1')
+ end
+
+ it 'allows to access with strings' do
+ expect(subject["key"]).to eq('value')
+ expect(subject["variables"].first["key"]).to eq('VAR1')
+ end
+ end
+
+ context 'when MySQL is used' do
+ before do
+ allow(Gitlab::Database).to receive(:adapter_name) { 'mysql2' }
+ end
+
+ context 'when loading a string' do
+ subject { described_class.load(data_string) }
+
+ it 'decodes a string' do
+ is_expected.to be_a(Hash)
+ end
+
+ it_behaves_like 'having consistent accessor'
+ end
+
+ context 'when loading a different type' do
+ subject { described_class.load({ key: 'hash' }) }
+
+ it 'raises an exception' do
+ expect { subject }.to raise_error(TypeError)
+ end
+ end
+
+ context 'when loading a nil' do
+ subject { described_class.load(nil) }
+
+ it 'returns nil' do
+ is_expected.to be_nil
+ end
+ end
+ end
+
+ context 'when PostgreSQL is used' do
+ before do
+ allow(Gitlab::Database).to receive(:adapter_name) { 'postgresql' }
+ end
+
+ context 'when loading a hash' do
+ subject { described_class.load(data_hash) }
+
+ it 'decodes a string' do
+ is_expected.to be_a(Hash)
+ end
+
+ it_behaves_like 'having consistent accessor'
+ end
+
+ context 'when loading a nil' do
+ subject { described_class.load(nil) }
+
+ it 'returns nil' do
+ is_expected.to be_nil
+ end
+ end
+ end
+ end
+end
diff --git a/spec/mailers/emails/issues_spec.rb b/spec/mailers/emails/issues_spec.rb
new file mode 100644
index 00000000000..09253cf8003
--- /dev/null
+++ b/spec/mailers/emails/issues_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require 'email_spec'
+
+describe Emails::Issues do
+ include EmailSpec::Matchers
+
+ describe "#import_issues_csv_email" do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+
+ subject { Notify.import_issues_csv_email(user.id, project.id, @results) }
+
+ it "shows number of successful issues imported" do
+ @results = { success: 165, error_lines: [], parse_error: false }
+
+ expect(subject).to have_body_text "165 issues imported"
+ end
+
+ it "shows error when file is invalid" do
+ @results = { success: 0, error_lines: [], parse_error: true }
+
+ expect(subject).to have_body_text "Error parsing CSV"
+ end
+
+ it "shows line numbers with errors" do
+ @results = { success: 0, error_lines: [23, 34, 58], parse_error: false }
+
+ expect(subject).to have_body_text "23, 34, 58"
+ end
+ end
+end
diff --git a/spec/migrations/delete_inconsistent_internal_id_records_spec.rb b/spec/migrations/delete_inconsistent_internal_id_records_spec.rb
index 8c55daf0d37..51291cb362a 100644
--- a/spec/migrations/delete_inconsistent_internal_id_records_spec.rb
+++ b/spec/migrations/delete_inconsistent_internal_id_records_spec.rb
@@ -90,6 +90,13 @@ describe DeleteInconsistentInternalIdRecords, :migration do
context 'for ci_pipelines' do
let(:scope) { :ci_pipeline }
+
+ let(:create_models) do
+ create_list(:ci_empty_pipeline, 3, project: project1)
+ create_list(:ci_empty_pipeline, 3, project: project2)
+ create_list(:ci_empty_pipeline, 3, project: project3)
+ end
+
it_behaves_like 'deleting inconsistent internal_id records'
end
diff --git a/spec/models/blob_viewer/gitlab_ci_yml_spec.rb b/spec/models/blob_viewer/gitlab_ci_yml_spec.rb
index 01c555a7a90..16bf947b493 100644
--- a/spec/models/blob_viewer/gitlab_ci_yml_spec.rb
+++ b/spec/models/blob_viewer/gitlab_ci_yml_spec.rb
@@ -4,7 +4,9 @@ describe BlobViewer::GitlabCiYml do
include FakeBlobHelpers
include RepoHelpers
- let(:project) { create(:project, :repository) }
+ set(:project) { create(:project, :repository) }
+ set(:user) { create(:user) }
+
let(:data) { File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) }
let(:blob) { fake_blob(path: '.gitlab-ci.yml', data: data) }
let(:sha) { sample_commit.id }
@@ -14,12 +16,12 @@ describe BlobViewer::GitlabCiYml do
it 'calls prepare! on the viewer' do
expect(subject).to receive(:prepare!)
- subject.validation_message(project, sha)
+ subject.validation_message(project: project, sha: sha, user: user)
end
context 'when the configuration is valid' do
it 'returns nil' do
- expect(subject.validation_message(project, sha)).to be_nil
+ expect(subject.validation_message(project: project, sha: sha, user: user)).to be_nil
end
end
@@ -27,7 +29,7 @@ describe BlobViewer::GitlabCiYml do
let(:data) { 'oof' }
it 'returns the error message' do
- expect(subject.validation_message(project, sha)).to eq('Invalid configuration format')
+ expect(subject.validation_message(project: project, sha: sha, user: user)).to eq('Invalid configuration format')
end
end
end
diff --git a/spec/models/ci/build_metadata_spec.rb b/spec/models/ci/build_metadata_spec.rb
index 519968b9e48..016a5899eef 100644
--- a/spec/models/ci/build_metadata_spec.rb
+++ b/spec/models/ci/build_metadata_spec.rb
@@ -13,12 +13,12 @@ describe Ci::BuildMetadata do
end
let(:build) { create(:ci_build, pipeline: pipeline) }
- let(:build_metadata) { build.metadata }
+ let(:metadata) { build.metadata }
it_behaves_like 'having unique enum values'
describe '#update_timeout_state' do
- subject { build_metadata }
+ subject { metadata }
context 'when runner is not assigned to the job' do
it "doesn't change timeout value" do
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 28b1a1e37e5..1afc2436bb5 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -1457,8 +1457,24 @@ describe Ci::Build do
context 'with retries max config option' do
subject { create(:ci_build, options: { retry: { max: 1 } }) }
- it 'returns the number of configured max retries' do
- expect(subject.retries_max).to eq 1
+ context 'when build_metadata_config is set' do
+ before do
+ stub_feature_flags(ci_build_metadata_config: true)
+ end
+
+ it 'returns the number of configured max retries' do
+ expect(subject.retries_max).to eq 1
+ end
+ end
+
+ context 'when build_metadata_config is not set' do
+ before do
+ stub_feature_flags(ci_build_metadata_config: false)
+ end
+
+ it 'returns the number of configured max retries' do
+ expect(subject.retries_max).to eq 1
+ end
end
end
@@ -1679,14 +1695,49 @@ describe Ci::Build do
let(:options) do
{
image: "ruby:2.1",
- services: [
- "postgres"
- ]
+ services: ["postgres"],
+ script: ["ls -a"]
}
end
it 'contains options' do
- expect(build.options).to eq(options)
+ expect(build.options).to eq(options.stringify_keys)
+ end
+
+ it 'allows to access with keys' do
+ expect(build.options[:image]).to eq('ruby:2.1')
+ end
+
+ it 'allows to access with strings' do
+ expect(build.options['image']).to eq('ruby:2.1')
+ end
+
+ context 'when ci_build_metadata_config is set' do
+ before do
+ stub_feature_flags(ci_build_metadata_config: true)
+ end
+
+ it 'persist data in build metadata' do
+ expect(build.metadata.read_attribute(:config_options)).to eq(options.stringify_keys)
+ end
+
+ it 'does not persist data in build' do
+ expect(build.read_attribute(:options)).to be_nil
+ end
+ end
+
+ context 'when ci_build_metadata_config is disabled' do
+ before do
+ stub_feature_flags(ci_build_metadata_config: false)
+ end
+
+ it 'persist data in build' do
+ expect(build.read_attribute(:options)).to eq(options.symbolize_keys)
+ end
+
+ it 'does not persist data in build metadata' do
+ expect(build.metadata.read_attribute(:config_options)).to be_nil
+ end
end
end
@@ -2030,56 +2081,6 @@ describe Ci::Build do
end
end
- describe '#when' do
- subject { build.when }
-
- context 'when `when` is undefined' do
- before do
- build.when = nil
- end
-
- context 'use from gitlab-ci.yml' do
- let(:project) { create(:project, :repository) }
- let(:pipeline) { create(:ci_pipeline, project: project) }
-
- before do
- stub_ci_pipeline_yaml_file(config)
- end
-
- context 'when config is not found' do
- let(:config) { nil }
-
- it { is_expected.to eq('on_success') }
- end
-
- context 'when config does not have a questioned job' do
- let(:config) do
- YAML.dump({
- test_other: {
- script: 'Hello World'
- }
- })
- end
-
- it { is_expected.to eq('on_success') }
- end
-
- context 'when config has `when`' do
- let(:config) do
- YAML.dump({
- test: {
- script: 'Hello World',
- when: 'always'
- }
- })
- end
-
- it { is_expected.to eq('always') }
- end
- end
- end
- end
-
describe '#variables' do
let(:container_registry_enabled) { false }
@@ -2149,62 +2150,6 @@ describe Ci::Build do
it { is_expected.to include(*predefined_variables) }
- context 'when yaml variables are undefined' do
- let(:pipeline) do
- create(:ci_pipeline, project: project,
- sha: project.commit.id,
- ref: project.default_branch)
- end
-
- before do
- build.yaml_variables = nil
- end
-
- context 'use from gitlab-ci.yml' do
- before do
- stub_ci_pipeline_yaml_file(config)
- end
-
- context 'when config is not found' do
- let(:config) { nil }
-
- it { is_expected.to include(*predefined_variables) }
- end
-
- context 'when config does not have a questioned job' do
- let(:config) do
- YAML.dump({
- test_other: {
- script: 'Hello World'
- }
- })
- end
-
- it { is_expected.to include(*predefined_variables) }
- end
-
- context 'when config has variables' do
- let(:config) do
- YAML.dump({
- test: {
- script: 'Hello World',
- variables: {
- KEY: 'value'
- }
- }
- })
- end
-
- let(:variables) do
- [{ key: 'KEY', value: 'value', public: true }]
- end
-
- it { is_expected.to include(*predefined_variables) }
- it { is_expected.to include(*variables) }
- end
- end
- end
-
describe 'variables ordering' do
context 'when variables hierarchy is stubbed' do
let(:build_pre_var) { { key: 'build', value: 'value', public: true } }
@@ -2793,29 +2738,53 @@ describe Ci::Build do
end
describe '#yaml_variables' do
- before do
- build.update_attribute(:yaml_variables, variables)
+ let(:build) { create(:ci_build, pipeline: pipeline, yaml_variables: variables) }
+
+ let(:variables) do
+ [
+ { 'key' => :VARIABLE, 'value' => 'my value' },
+ { 'key' => 'VARIABLE2', 'value' => 'my value 2' }
+ ]
end
- context 'when serialized valu is a symbolized hash' do
- let(:variables) do
- [{ key: :VARIABLE, value: 'my value 1' }]
+ shared_examples 'having consistent representation' do
+ it 'allows to access using symbols' do
+ expect(build.reload.yaml_variables.first[:key]).to eq('VARIABLE')
+ expect(build.reload.yaml_variables.first[:value]).to eq('my value')
+ expect(build.reload.yaml_variables.second[:key]).to eq('VARIABLE2')
+ expect(build.reload.yaml_variables.second[:value]).to eq('my value 2')
end
+ end
+
+ context 'when ci_build_metadata_config is set' do
+ before do
+ stub_feature_flags(ci_build_metadata_config: true)
+ end
+
+ it_behaves_like 'having consistent representation'
- it 'keeps symbolizes keys and stringifies variables names' do
- expect(build.yaml_variables)
- .to eq [{ key: 'VARIABLE', value: 'my value 1' }]
+ it 'persist data in build metadata' do
+ expect(build.metadata.read_attribute(:config_variables)).not_to be_nil
+ end
+
+ it 'does not persist data in build' do
+ expect(build.read_attribute(:yaml_variables)).to be_nil
end
end
- context 'when serialized value is a hash with string keys' do
- let(:variables) do
- [{ 'key' => :VARIABLE, 'value' => 'my value 2' }]
+ context 'when ci_build_metadata_config is disabled' do
+ before do
+ stub_feature_flags(ci_build_metadata_config: false)
end
- it 'symblizes variables hash' do
- expect(build.yaml_variables)
- .to eq [{ key: 'VARIABLE', value: 'my value 2' }]
+ it_behaves_like 'having consistent representation'
+
+ it 'persist data in build' do
+ expect(build.read_attribute(:yaml_variables)).not_to be_nil
+ end
+
+ it 'does not persist data in build metadata' do
+ expect(build.metadata.read_attribute(:config_variables)).to be_nil
end
end
end
@@ -2987,7 +2956,7 @@ describe Ci::Build do
end
context 'when build is configured to be retried' do
- subject { create(:ci_build, :running, options: { retry: { max: 3 } }, project: project, user: user) }
+ subject { create(:ci_build, :running, options: { script: ["ls -al"], retry: 3 }, project: project, user: user) }
it 'retries build and assigns the same user to it' do
expect(described_class).to receive(:retry)
@@ -3476,6 +3445,23 @@ describe Ci::Build do
end
end
+ describe 'degenerate!' do
+ let(:build) { create(:ci_build) }
+
+ subject { build.degenerate! }
+
+ before do
+ build.ensure_metadata
+ end
+
+ it 'drops metadata' do
+ subject
+
+ expect(build.reload).to be_degenerated
+ expect(build.metadata).to be_nil
+ end
+ end
+
describe '#archived?' do
context 'when build is degenerated' do
subject { create(:ci_build, :degenerated) }
@@ -3503,4 +3489,97 @@ describe Ci::Build do
end
end
end
+
+ describe '#read_metadata_attribute' do
+ let(:build) { create(:ci_build, :degenerated) }
+ let(:build_options) { { "key" => "build" } }
+ let(:metadata_options) { { "key" => "metadata" } }
+ let(:default_options) { { "key" => "default" } }
+
+ subject { build.send(:read_metadata_attribute, :options, :config_options, default_options) }
+
+ context 'when build and metadata options is set' do
+ before do
+ build.write_attribute(:options, build_options)
+ build.ensure_metadata.write_attribute(:config_options, metadata_options)
+ end
+
+ it 'prefers build options' do
+ is_expected.to eq(build_options)
+ end
+ end
+
+ context 'when only metadata options is set' do
+ before do
+ build.write_attribute(:options, nil)
+ build.ensure_metadata.write_attribute(:config_options, metadata_options)
+ end
+
+ it 'returns metadata options' do
+ is_expected.to eq(metadata_options)
+ end
+ end
+
+ context 'when none is set' do
+ it 'returns default value' do
+ is_expected.to eq(default_options)
+ end
+ end
+ end
+
+ describe '#write_metadata_attribute' do
+ let(:build) { create(:ci_build, :degenerated) }
+ let(:options) { { "key" => "new options" } }
+ let(:existing_options) { { "key" => "existing options" } }
+
+ subject { build.send(:write_metadata_attribute, :options, :config_options, options) }
+
+ context 'when ci_build_metadata_config is set' do
+ before do
+ stub_feature_flags(ci_build_metadata_config: true)
+ end
+
+ context 'when data in build is already set' do
+ before do
+ build.write_attribute(:options, existing_options)
+ end
+
+ it 'does set metadata options' do
+ subject
+
+ expect(build.metadata.read_attribute(:config_options)).to eq(options)
+ end
+
+ it 'does reset build options' do
+ subject
+
+ expect(build.read_attribute(:options)).to be_nil
+ end
+ end
+ end
+
+ context 'when ci_build_metadata_config is disabled' do
+ before do
+ stub_feature_flags(ci_build_metadata_config: false)
+ end
+
+ context 'when data in build metadata is already set' do
+ before do
+ build.ensure_metadata.write_attribute(:config_options, existing_options)
+ end
+
+ it 'does set metadata options' do
+ subject
+
+ expect(build.read_attribute(:options)).to eq(options)
+ end
+
+ it 'does reset build options' do
+ subject
+
+ expect(build.metadata.read_attribute(:config_options)).to be_nil
+ end
+ end
+ end
+ end
end
diff --git a/spec/models/clusters/applications/knative_spec.rb b/spec/models/clusters/applications/knative_spec.rb
index 8fc755d2a26..0cf9e10ce04 100644
--- a/spec/models/clusters/applications/knative_spec.rb
+++ b/spec/models/clusters/applications/knative_spec.rb
@@ -15,6 +15,13 @@ describe Clusters::Applications::Knative do
allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_async)
end
+ describe 'when rbac is not enabled' do
+ let(:cluster) { create(:cluster, :provided_by_gcp, :rbac_disabled) }
+ let(:knative_no_rbac) { create(:clusters_applications_knative, cluster: cluster) }
+
+ it { expect(knative_no_rbac).to be_not_installable }
+ end
+
describe '.installed' do
subject { described_class.installed }
diff --git a/spec/models/error_tracking/project_error_tracking_setting_spec.rb b/spec/models/error_tracking/project_error_tracking_setting_spec.rb
new file mode 100644
index 00000000000..83f29718eda
--- /dev/null
+++ b/spec/models/error_tracking/project_error_tracking_setting_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe ErrorTracking::ProjectErrorTrackingSetting do
+ set(:project) { create(:project) }
+
+ describe 'Associations' do
+ it { is_expected.to belong_to(:project) }
+ end
+
+ describe 'Validations' do
+ subject { create(:project_error_tracking_setting, project: project) }
+
+ context 'when api_url is over 255 chars' do
+ before do
+ subject.api_url = 'https://' + 'a' * 250
+ end
+
+ it 'fails validation' do
+ expect(subject).not_to be_valid
+ expect(subject.errors.messages[:api_url]).to include('is too long (maximum is 255 characters)')
+ end
+ end
+
+ context 'With unsafe url' do
+ let(:project_error_tracking_setting) { create(:project_error_tracking_setting, project: project) }
+
+ it 'fails validation' do
+ project_error_tracking_setting.api_url = "https://replaceme.com/'><script>alert(document.cookie)</script>"
+
+ expect(project_error_tracking_setting).not_to be_valid
+ end
+ end
+ end
+end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 4cc3a6a3644..96d49e86dab 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -1372,6 +1372,34 @@ describe MergeRequest do
end
end
+ describe '#update_head_pipeline' do
+ subject { merge_request.update_head_pipeline }
+
+ let(:merge_request) { create(:merge_request) }
+
+ context 'when there is a pipeline with the diff head sha' do
+ let!(:pipeline) do
+ create(:ci_empty_pipeline,
+ project: merge_request.project,
+ sha: merge_request.diff_head_sha,
+ ref: merge_request.source_branch)
+ end
+
+ it 'updates the head pipeline' do
+ expect { subject }
+ .to change { merge_request.reload.head_pipeline }
+ .from(nil).to(pipeline)
+ end
+ end
+
+ context 'when there are no pipelines with the diff head sha' do
+ it 'does not update the head pipeline' do
+ expect { subject }
+ .not_to change { merge_request.reload.head_pipeline }
+ end
+ end
+ end
+
describe '#has_test_reports?' do
subject { merge_request.has_test_reports? }
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index bcdfe3cf1eb..385b8a7959f 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -890,4 +890,19 @@ describe Note do
end
end
end
+
+ describe '#parent' do
+ it 'returns project for project notes' do
+ project = create(:project)
+ note = create(:note_on_issue, project: project)
+
+ expect(note.parent).to eq(project)
+ end
+
+ it 'returns nil for personal snippet note' do
+ note = create(:note_on_personal_snippet)
+
+ expect(note.parent).to be_nil
+ end
+ end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 7bf60083d10..d1ab0bdba29 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -62,6 +62,7 @@ describe Project do
it { is_expected.to have_one(:last_event).class_name('Event') }
it { is_expected.to have_one(:forked_from_project).through(:fork_network_member) }
it { is_expected.to have_one(:auto_devops).class_name('ProjectAutoDevops') }
+ it { is_expected.to have_one(:error_tracking_setting).class_name('ErrorTracking::ProjectErrorTrackingSetting') }
it { is_expected.to have_many(:commit_statuses) }
it { is_expected.to have_many(:ci_pipelines) }
it { is_expected.to have_many(:builds) }
@@ -3571,7 +3572,9 @@ describe Project do
end
it 'contains a URL variable for every supported API version' do
- supported_versions = API::API.versions.select do |version|
+ # Ensure future API versions have proper variables defined. We're not doing this for v3.
+ supported_versions = API::API.versions - ['v3']
+ supported_versions = supported_versions.select do |version|
API::API.routes.select { |route| route.version == version }.many?
end
diff --git a/spec/requests/api/project_clusters_spec.rb b/spec/requests/api/project_clusters_spec.rb
new file mode 100644
index 00000000000..e34164aa66a
--- /dev/null
+++ b/spec/requests/api/project_clusters_spec.rb
@@ -0,0 +1,450 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe API::ProjectClusters do
+ include KubernetesHelpers
+
+ let(:current_user) { create(:user) }
+ let(:non_member) { create(:user) }
+ let(:project) { create(:project, :repository) }
+
+ before do
+ project.add_maintainer(current_user)
+ end
+
+ describe 'GET /projects/:id/clusters' do
+ let!(:extra_cluster) { create(:cluster, :provided_by_gcp, :project) }
+
+ let!(:clusters) do
+ create_list(:cluster, 5, :provided_by_gcp, :project, :production_environment,
+ projects: [project])
+ end
+
+ context 'non-authorized user' do
+ it 'should respond with 404' do
+ get api("/projects/#{project.id}/clusters", non_member)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ context 'authorized user' do
+ before do
+ get api("/projects/#{project.id}/clusters", current_user)
+ end
+
+ it 'should respond with 200' do
+ expect(response).to have_gitlab_http_status(200)
+ end
+
+ it 'should include pagination headers' do
+ expect(response).to include_pagination_headers
+ end
+
+ it 'should only include authorized clusters' do
+ cluster_ids = json_response.map { |cluster| cluster['id'] }
+
+ expect(cluster_ids).to match_array(clusters.pluck(:id))
+ expect(cluster_ids).not_to include(extra_cluster.id)
+ end
+ end
+ end
+
+ describe 'GET /projects/:id/clusters/:cluster_id' do
+ let(:cluster_id) { cluster.id }
+
+ let(:platform_kubernetes) do
+ create(:cluster_platform_kubernetes, :configured,
+ namespace: 'project-namespace')
+ end
+
+ let(:cluster) do
+ create(:cluster, :project, :provided_by_gcp,
+ platform_kubernetes: platform_kubernetes,
+ user: current_user,
+ projects: [project])
+ end
+
+ context 'non-authorized user' do
+ it 'should respond with 404' do
+ get api("/projects/#{project.id}/clusters/#{cluster_id}", non_member)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ context 'authorized user' do
+ before do
+ get api("/projects/#{project.id}/clusters/#{cluster_id}", current_user)
+ end
+
+ it 'returns specific cluster' do
+ expect(json_response['id']).to eq(cluster.id)
+ end
+
+ it 'returns cluster information' do
+ expect(json_response['provider_type']).to eq('gcp')
+ expect(json_response['platform_type']).to eq('kubernetes')
+ expect(json_response['environment_scope']).to eq('*')
+ expect(json_response['cluster_type']).to eq('project_type')
+ end
+
+ it 'returns project information' do
+ cluster_project = json_response['project']
+
+ expect(cluster_project['id']).to eq(project.id)
+ expect(cluster_project['name']).to eq(project.name)
+ expect(cluster_project['path']).to eq(project.path)
+ end
+
+ it 'returns kubernetes platform information' do
+ platform = json_response['platform_kubernetes']
+
+ expect(platform['api_url']).to eq('https://kubernetes.example.com')
+ expect(platform['namespace']).to eq('project-namespace')
+ expect(platform['ca_cert']).to be_present
+ end
+
+ it 'returns user information' do
+ user = json_response['user']
+
+ expect(user['id']).to eq(current_user.id)
+ expect(user['username']).to eq(current_user.username)
+ end
+
+ it 'returns GCP provider information' do
+ gcp_provider = json_response['provider_gcp']
+
+ expect(gcp_provider['cluster_id']).to eq(cluster.id)
+ expect(gcp_provider['status_name']).to eq('created')
+ expect(gcp_provider['gcp_project_id']).to eq('test-gcp-project')
+ expect(gcp_provider['zone']).to eq('us-central1-a')
+ expect(gcp_provider['machine_type']).to eq('n1-standard-2')
+ expect(gcp_provider['num_nodes']).to eq(3)
+ expect(gcp_provider['endpoint']).to eq('111.111.111.111')
+ end
+
+ context 'when cluster has no provider' do
+ let(:cluster) do
+ create(:cluster, :project, :provided_by_user,
+ projects: [project])
+ end
+
+ it 'should not include GCP provider info' do
+ expect(json_response['provider_gcp']).not_to be_present
+ end
+ end
+
+ context 'with non-existing cluster' do
+ let(:cluster_id) { 123 }
+
+ it 'returns 404' do
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+ end
+ end
+
+ shared_context 'kubernetes calls stubbed' do
+ before do
+ stub_kubeclient_discover(api_url)
+ stub_kubeclient_get_namespace(api_url, namespace: namespace)
+ stub_kubeclient_get_service_account(api_url, "#{namespace}-service-account", namespace: namespace)
+ stub_kubeclient_put_service_account(api_url, "#{namespace}-service-account", namespace: namespace)
+
+ stub_kubeclient_get_secret(
+ api_url,
+ {
+ metadata_name: "#{namespace}-token",
+ token: Base64.encode64('sample-token'),
+ namespace: namespace
+ }
+ )
+
+ stub_kubeclient_put_secret(api_url, "#{namespace}-token", namespace: namespace)
+ stub_kubeclient_get_role_binding(api_url, "gitlab-#{namespace}", namespace: namespace)
+ stub_kubeclient_put_role_binding(api_url, "gitlab-#{namespace}", namespace: namespace)
+ end
+ end
+
+ describe 'POST /projects/:id/clusters/user' do
+ include_context 'kubernetes calls stubbed'
+
+ let(:api_url) { 'https://kubernetes.example.com' }
+ let(:namespace) { project.path }
+ let(:authorization_type) { 'rbac' }
+
+ let(:platform_kubernetes_attributes) do
+ {
+ api_url: api_url,
+ token: 'sample-token',
+ namespace: namespace,
+ authorization_type: authorization_type
+ }
+ end
+
+ let(:cluster_params) do
+ {
+ name: 'test-cluster',
+ platform_kubernetes_attributes: platform_kubernetes_attributes
+ }
+ end
+
+ context 'non-authorized user' do
+ it 'should respond with 404' do
+ post api("/projects/#{project.id}/clusters/user", non_member), params: cluster_params
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ context 'authorized user' do
+ before do
+ post api("/projects/#{project.id}/clusters/user", current_user), params: cluster_params
+ end
+
+ context 'with valid params' do
+ it 'should respond with 201' do
+ expect(response).to have_gitlab_http_status(201)
+ end
+
+ it 'should create a new Cluster::Cluster' do
+ cluster_result = Clusters::Cluster.find(json_response["id"])
+ platform_kubernetes = cluster_result.platform
+
+ expect(cluster_result).to be_user
+ expect(cluster_result).to be_kubernetes
+ expect(cluster_result.project).to eq(project)
+ expect(cluster_result.name).to eq('test-cluster')
+ expect(platform_kubernetes.rbac?).to be_truthy
+ expect(platform_kubernetes.api_url).to eq(api_url)
+ expect(platform_kubernetes.namespace).to eq(namespace)
+ expect(platform_kubernetes.token).to eq('sample-token')
+ end
+ end
+
+ context 'when user does not indicate authorization type' do
+ let(:platform_kubernetes_attributes) do
+ {
+ api_url: api_url,
+ token: 'sample-token',
+ namespace: namespace
+ }
+ end
+
+ it 'defaults to RBAC' do
+ cluster_result = Clusters::Cluster.find(json_response['id'])
+
+ expect(cluster_result.platform_kubernetes.rbac?).to be_truthy
+ end
+ end
+
+ context 'when user sets authorization type as ABAC' do
+ let(:authorization_type) { 'abac' }
+
+ it 'should create an ABAC cluster' do
+ cluster_result = Clusters::Cluster.find(json_response['id'])
+
+ expect(cluster_result.platform.abac?).to be_truthy
+ end
+ end
+
+ context 'with invalid params' do
+ let(:namespace) { 'invalid_namespace' }
+
+ it 'should respond with 400' do
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it 'should not create a new Clusters::Cluster' do
+ expect(project.reload.clusters).to be_empty
+ end
+
+ it 'should return validation errors' do
+ expect(json_response['message']['platform_kubernetes.namespace'].first).to be_present
+ end
+ end
+ end
+ end
+
+ describe 'PUT /projects/:id/clusters/:cluster_id' do
+ include_context 'kubernetes calls stubbed'
+
+ let(:api_url) { 'https://kubernetes.example.com' }
+ let(:namespace) { 'new-namespace' }
+ let(:platform_kubernetes_attributes) { { namespace: namespace } }
+
+ let(:update_params) do
+ {
+ platform_kubernetes_attributes: platform_kubernetes_attributes
+ }
+ end
+
+ let!(:kubernetes_namespace) do
+ create(:cluster_kubernetes_namespace,
+ cluster: cluster,
+ project: project)
+ end
+
+ let(:cluster) do
+ create(:cluster, :project, :provided_by_gcp,
+ projects: [project])
+ end
+
+ context 'non-authorized user' do
+ it 'should respond with 404' do
+ put api("/projects/#{project.id}/clusters/#{cluster.id}", non_member), params: update_params
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ context 'authorized user' do
+ before do
+ put api("/projects/#{project.id}/clusters/#{cluster.id}", current_user), params: update_params
+
+ cluster.reload
+ end
+
+ context 'with valid params' do
+ it 'should respond with 200' do
+ expect(response).to have_gitlab_http_status(200)
+ end
+
+ it 'should update cluster attributes' do
+ expect(cluster.platform_kubernetes.namespace).to eq('new-namespace')
+ expect(cluster.kubernetes_namespace.namespace).to eq('new-namespace')
+ end
+ end
+
+ context 'with invalid params' do
+ let(:namespace) { 'invalid_namespace' }
+
+ it 'should respond with 400' do
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it 'should not update cluster attributes' do
+ expect(cluster.platform_kubernetes.namespace).not_to eq('invalid_namespace')
+ expect(cluster.kubernetes_namespace.namespace).not_to eq('invalid_namespace')
+ end
+
+ it 'should return validation errors' do
+ expect(json_response['message']['platform_kubernetes.namespace'].first).to match('can contain only lowercase letters')
+ end
+ end
+
+ context 'with a GCP cluster' do
+ context 'when user tries to change GCP specific fields' do
+ let(:platform_kubernetes_attributes) do
+ {
+ api_url: 'https://new-api-url.com',
+ token: 'new-sample-token'
+ }
+ end
+
+ it 'should respond with 400' do
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it 'should return validation error' do
+ expect(json_response['message']['platform_kubernetes.base'].first).to eq('Cannot modify managed Kubernetes cluster')
+ end
+ end
+
+ context 'when user tries to change namespace' do
+ let(:namespace) { 'new-namespace' }
+
+ it 'should respond with 200' do
+ expect(response).to have_gitlab_http_status(200)
+ end
+ end
+ end
+
+ context 'with an user cluster' do
+ let(:api_url) { 'https://new-api-url.com' }
+
+ let(:cluster) do
+ create(:cluster, :project, :provided_by_user,
+ projects: [project])
+ end
+
+ let(:platform_kubernetes_attributes) do
+ {
+ api_url: api_url,
+ namespace: 'new-namespace',
+ token: 'new-sample-token'
+ }
+ end
+
+ let(:update_params) do
+ {
+ name: 'new-name',
+ platform_kubernetes_attributes: platform_kubernetes_attributes
+ }
+ end
+
+ it 'should respond with 200' do
+ expect(response).to have_gitlab_http_status(200)
+ end
+
+ it 'should update platform kubernetes attributes' do
+ platform_kubernetes = cluster.platform_kubernetes
+
+ expect(cluster.name).to eq('new-name')
+ expect(platform_kubernetes.namespace).to eq('new-namespace')
+ expect(platform_kubernetes.api_url).to eq('https://new-api-url.com')
+ expect(platform_kubernetes.token).to eq('new-sample-token')
+ end
+ end
+
+ context 'with a cluster that does not belong to user' do
+ let(:cluster) { create(:cluster, :project, :provided_by_user) }
+
+ it 'should respond with 404' do
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+ end
+ end
+
+ describe 'DELETE /projects/:id/clusters/:cluster_id' do
+ let(:cluster_params) { { cluster_id: cluster.id } }
+
+ let(:cluster) do
+ create(:cluster, :project, :provided_by_gcp,
+ projects: [project])
+ end
+
+ context 'non-authorized user' do
+ it 'should respond with 404' do
+ delete api("/projects/#{project.id}/clusters/#{cluster.id}", non_member), params: cluster_params
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ context 'authorized user' do
+ before do
+ delete api("/projects/#{project.id}/clusters/#{cluster.id}", current_user), params: cluster_params
+ end
+
+ it 'should respond with 204' do
+ expect(response).to have_gitlab_http_status(204)
+ end
+
+ it 'should delete the cluster' do
+ expect(Clusters::Cluster.exists?(id: cluster.id)).to be_falsy
+ end
+
+ context 'with a cluster that does not belong to user' do
+ let(:cluster) { create(:cluster, :project, :provided_by_user) }
+
+ it 'should respond with 404' do
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/release/links_spec.rb b/spec/requests/api/release/links_spec.rb
new file mode 100644
index 00000000000..9d62257d470
--- /dev/null
+++ b/spec/requests/api/release/links_spec.rb
@@ -0,0 +1,417 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe API::Release::Links do
+ let(:project) { create(:project, :repository, :private) }
+ let(:maintainer) { create(:user) }
+ let(:reporter) { create(:user) }
+ let(:non_project_member) { create(:user) }
+ let(:commit) { create(:commit, project: project) }
+
+ let!(:release) do
+ create(:release,
+ project: project,
+ tag: 'v0.1',
+ author: maintainer)
+ end
+
+ before do
+ project.add_maintainer(maintainer)
+ project.add_reporter(reporter)
+
+ project.repository.add_tag(maintainer, 'v0.1', commit.id)
+ end
+
+ describe 'GET /projects/:id/releases/:tag_name/assets/links' do
+ context 'when there are two release links' do
+ let!(:release_link_1) { create(:release_link, release: release, created_at: 2.days.ago) }
+ let!(:release_link_2) { create(:release_link, release: release, created_at: 1.day.ago) }
+
+ it 'returns 200 HTTP status' do
+ get api("/projects/#{project.id}/releases/v0.1/assets/links", maintainer)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'returns release links ordered by created_at' do
+ get api("/projects/#{project.id}/releases/v0.1/assets/links", maintainer)
+
+ expect(json_response.count).to eq(2)
+ expect(json_response.first['name']).to eq(release_link_2.name)
+ expect(json_response.second['name']).to eq(release_link_1.name)
+ end
+
+ it 'matches response schema' do
+ get api("/projects/#{project.id}/releases/v0.1/assets/links", maintainer)
+
+ expect(response).to match_response_schema('release/links')
+ end
+ end
+
+ context 'when release does not exist' do
+ let!(:release) { }
+
+ it_behaves_like '404 response' do
+ let(:request) { get api("/projects/#{project.id}/releases/v0.1/assets/links", maintainer) }
+ let(:message) { '404 Not found' }
+ end
+ end
+
+ context 'when user is not a project member' do
+ it_behaves_like '404 response' do
+ let(:request) { get api("/projects/#{project.id}/releases/v0.1/assets/links", non_project_member) }
+ let(:message) { '404 Project Not Found' }
+ end
+
+ context 'when project is public' do
+ let(:project) { create(:project, :repository, :public) }
+
+ it 'allows the request' do
+ get api("/projects/#{project.id}/releases/v0.1/assets/links", non_project_member)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(releases_page: false)
+ end
+
+ it_behaves_like '404 response' do
+ let(:request) { get api("/projects/#{project.id}/releases/v0.1/assets/links", maintainer) }
+ end
+ end
+ end
+
+ describe 'GET /projects/:id/releases/:tag_name/assets/links/:link_id' do
+ let!(:release_link) { create(:release_link, release: release) }
+
+ it 'returns 200 HTTP status' do
+ get api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", maintainer)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'returns a link entry' do
+ get api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", maintainer)
+
+ expect(json_response['name']).to eq(release_link.name)
+ expect(json_response['url']).to eq(release_link.url)
+ end
+
+ it 'matches response schema' do
+ get api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", maintainer)
+
+ expect(response).to match_response_schema('release/link')
+ end
+
+ context 'when specified tag is not found in the project' do
+ it_behaves_like '404 response' do
+ let(:request) { get api("/projects/#{project.id}/releases/non_existing_tag/assets/links/#{release_link.id}", maintainer) }
+ end
+ end
+
+ context 'when user is not a project member' do
+ it_behaves_like '404 response' do
+ let(:request) { get api("/projects/#{project.id}/releases/non_existing_tag/assets/links/#{release_link.id}", non_project_member) }
+ end
+
+ context 'when project is public' do
+ let(:project) { create(:project, :repository, :public) }
+
+ it 'allows the request' do
+ get api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", non_project_member)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(releases_page: false)
+ end
+
+ it_behaves_like '404 response' do
+ let(:request) { get api("/projects/#{project.id}/releases/non_existing_tag/assets/links/#{release_link.id}", maintainer) }
+ end
+ end
+ end
+
+ describe 'POST /projects/:id/releases/:tag_name/assets/links' do
+ let(:params) do
+ {
+ name: 'awesome-app.dmg',
+ url: 'https://example.com/download/awesome-app.dmg'
+ }
+ end
+
+ it 'accepts the request' do
+ post api("/projects/#{project.id}/releases/v0.1/assets/links", maintainer), params: params
+
+ expect(response).to have_gitlab_http_status(:created)
+ end
+
+ it 'creates a new release' do
+ expect do
+ post api("/projects/#{project.id}/releases/v0.1/assets/links", maintainer), params: params
+ end.to change { Releases::Link.count }.by(1)
+
+ release.reload
+ expect(release.links.last.name).to eq('awesome-app.dmg')
+ expect(release.links.last.url).to eq('https://example.com/download/awesome-app.dmg')
+ end
+
+ it 'matches response schema' do
+ post api("/projects/#{project.id}/releases/v0.1/assets/links", maintainer), params: params
+
+ expect(response).to match_response_schema('release/link')
+ end
+
+ context 'when name is empty' do
+ let(:params) do
+ {
+ name: '',
+ url: 'https://example.com/download/awesome-app.dmg'
+ }
+ end
+
+ it_behaves_like '400 response' do
+ let(:request) do
+ post api("/projects/#{project.id}/releases/v0.1/assets/links", maintainer),
+ params: params
+ end
+ end
+ end
+
+ context 'when user is a reporter' do
+ it_behaves_like '403 response' do
+ let(:request) do
+ post api("/projects/#{project.id}/releases/v0.1/assets/links", reporter),
+ params: params
+ end
+ end
+ end
+
+ context 'when user is not a project member' do
+ it 'forbids the request' do
+ post api("/projects/#{project.id}/releases/v0.1/assets/links", non_project_member),
+ params: params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ context 'when project is public' do
+ let(:project) { create(:project, :repository, :public) }
+
+ it 'forbids the request' do
+ post api("/projects/#{project.id}/releases/v0.1/assets/links", non_project_member),
+ params: params
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+ end
+
+ context 'when the same link already exists' do
+ before do
+ create(:release_link,
+ release: release,
+ name: 'awesome-app.dmg',
+ url: 'https://example.com/download/awesome-app.dmg')
+ end
+
+ it_behaves_like '400 response' do
+ let(:request) do
+ post api("/projects/#{project.id}/releases/v0.1/assets/links", maintainer),
+ params: params
+ end
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(releases_page: false)
+ end
+
+ it_behaves_like '404 response' do
+ let(:request) do
+ post api("/projects/#{project.id}/releases/v0.1/assets/links", maintainer),
+ params: params
+ end
+ end
+ end
+ end
+
+ describe 'PUT /projects/:id/releases/:tag_name/assets/links/:link_id' do
+ let(:params) { { name: 'awesome-app.msi' } }
+ let!(:release_link) { create(:release_link, release: release) }
+
+ it 'accepts the request' do
+ put api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", maintainer),
+ params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'updates the name' do
+ put api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", maintainer),
+ params: params
+
+ expect(json_response['name']).to eq('awesome-app.msi')
+ end
+
+ it 'does not update the url' do
+ put api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", maintainer),
+ params: params
+
+ expect(json_response['url']).to eq(release_link.url)
+ end
+
+ it 'matches response schema' do
+ put api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", maintainer),
+ params: params
+
+ expect(response).to match_response_schema('release/link')
+ end
+
+ context 'when params is empty' do
+ let(:params) { {} }
+
+ it 'does not allow the request' do
+ put api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", maintainer),
+ params: params
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
+
+ context 'when there are no corresponding release link' do
+ let!(:release_link) { }
+
+ it_behaves_like '404 response' do
+ let(:request) do
+ put api("/projects/#{project.id}/releases/v0.1/assets/links/1", maintainer),
+ params: params
+ end
+ end
+ end
+
+ context 'when user is a reporter' do
+ it_behaves_like '403 response' do
+ let(:request) do
+ put api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", reporter),
+ params: params
+ end
+ end
+ end
+
+ context 'when user is not a project member' do
+ it_behaves_like '404 response' do
+ let(:request) do
+ put api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", non_project_member),
+ params: params
+ end
+ end
+
+ context 'when project is public' do
+ let(:project) { create(:project, :repository, :public) }
+
+ it_behaves_like '403 response' do
+ let(:request) do
+ put api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", non_project_member),
+ params: params
+ end
+ end
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(releases_page: false)
+ end
+
+ it_behaves_like '404 response' do
+ let(:request) do
+ put api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", maintainer),
+ params: params
+ end
+ end
+ end
+ end
+
+ describe 'DELETE /projects/:id/releases/:tag_name/assets/links/:link_id' do
+ let!(:release_link) do
+ create(:release_link, release: release)
+ end
+
+ it 'accepts the request' do
+ delete api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", maintainer)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'destroys the release link' do
+ expect do
+ delete api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", maintainer)
+ end.to change { Releases::Link.count }.by(-1)
+ end
+
+ it 'matches response schema' do
+ delete api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", maintainer)
+
+ expect(response).to match_response_schema('release/link')
+ end
+
+ context 'when there are no corresponding release link' do
+ let!(:release_link) { }
+
+ it_behaves_like '404 response' do
+ let(:request) do
+ delete api("/projects/#{project.id}/releases/v0.1/assets/links/1", maintainer)
+ end
+ end
+ end
+
+ context 'when user is a reporter' do
+ it_behaves_like '403 response' do
+ let(:request) do
+ delete api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", reporter)
+ end
+ end
+ end
+
+ context 'when user is not a project member' do
+ it_behaves_like '404 response' do
+ let(:request) do
+ delete api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", non_project_member)
+ end
+ end
+
+ context 'when project is public' do
+ let(:project) { create(:project, :repository, :public) }
+
+ it_behaves_like '403 response' do
+ let(:request) do
+ delete api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", non_project_member)
+ end
+ end
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(releases_page: false)
+ end
+
+ it_behaves_like '404 response' do
+ let(:request) do
+ delete api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", maintainer)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb
index 2f322cc7054..ec48bf60426 100644
--- a/spec/requests/api/runner_spec.rb
+++ b/spec/requests/api/runner_spec.rb
@@ -287,7 +287,7 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
let(:runner) { create(:ci_runner, :project, projects: [project]) }
let(:job) do
create(:ci_build, :artifacts, :extended_options,
- pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0, commands: "ls\ndate")
+ pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0)
end
describe 'POST /api/v4/jobs/request' do
@@ -422,7 +422,7 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
let(:expected_steps) do
[{ 'name' => 'script',
- 'script' => %w(ls date),
+ 'script' => %w(echo),
'timeout' => job.metadata_timeout,
'when' => 'on_success',
'allow_failure' => false },
@@ -588,7 +588,7 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
let!(:test_job) do
create(:ci_build, pipeline: pipeline, token: 'test-job-token', name: 'deploy',
stage: 'deploy', stage_idx: 1,
- options: { dependencies: [job2.name] })
+ options: { script: ['bash'], dependencies: [job2.name] })
end
before do
@@ -612,7 +612,7 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
let!(:empty_dependencies_job) do
create(:ci_build, pipeline: pipeline, token: 'test-job-token', name: 'empty_dependencies_job',
stage: 'deploy', stage_idx: 1,
- options: { dependencies: [] })
+ options: { script: ['bash'], dependencies: [] })
end
before do
diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb
index 87b60387c52..8497e90bd8b 100644
--- a/spec/services/ci/create_pipeline_service_spec.rb
+++ b/spec/services/ci/create_pipeline_service_spec.rb
@@ -143,7 +143,8 @@ describe Ci::CreatePipelineService do
target_branch: "branch_1",
source_project: project)
- allow_any_instance_of(Ci::Pipeline).to receive(:latest?).and_return(false)
+ allow_any_instance_of(MergeRequest)
+ .to receive(:find_actual_head_pipeline) { }
execute_service
diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb
index 538992b621e..7ce7d2d882a 100644
--- a/spec/services/ci/process_pipeline_service_spec.rb
+++ b/spec/services/ci/process_pipeline_service_spec.rb
@@ -671,9 +671,9 @@ describe Ci::ProcessPipelineService, '#execute' do
context 'when builds with auto-retries are configured' do
before do
- create_build('build:1', stage_idx: 0, user: user, options: { retry: { max: 2 } })
+ create_build('build:1', stage_idx: 0, user: user, options: { script: 'aa', retry: 2 })
create_build('test:1', stage_idx: 1, user: user, when: :on_failure)
- create_build('test:2', stage_idx: 1, user: user, options: { retry: { max: 1 } })
+ create_build('test:2', stage_idx: 1, user: user, options: { script: 'aa', retry: 1 })
end
it 'automatically retries builds in a valid order' do
@@ -770,7 +770,7 @@ describe Ci::ProcessPipelineService, '#execute' do
end
def delayed_options
- { when: 'delayed', options: { start_in: '1 minute' } }
+ { when: 'delayed', options: { script: %w(echo), start_in: '1 minute' } }
end
def unschedule
diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb
index 9d65ac15213..20181387612 100644
--- a/spec/services/ci/register_job_service_spec.rb
+++ b/spec/services/ci/register_job_service_spec.rb
@@ -460,7 +460,12 @@ module Ci
end
let!(:pre_stage_job) { create(:ci_build, :success, pipeline: pipeline, name: 'test', stage_idx: 0) }
- let!(:pending_job) { create(:ci_build, :pending, pipeline: pipeline, stage_idx: 1, options: { dependencies: ['test'] } ) }
+
+ let!(:pending_job) do
+ create(:ci_build, :pending,
+ pipeline: pipeline, stage_idx: 1,
+ options: { script: ["bash"], dependencies: ['test'] })
+ end
subject { execute(specific_runner) }
diff --git a/spec/services/issues/import_csv_service_spec.rb b/spec/services/issues/import_csv_service_spec.rb
new file mode 100644
index 00000000000..516a1137319
--- /dev/null
+++ b/spec/services/issues/import_csv_service_spec.rb
@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Issues::ImportCsvService do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+
+ subject do
+ uploader = FileUploader.new(project)
+ uploader.store!(file)
+
+ described_class.new(user, project, uploader).execute
+ end
+
+ describe '#execute' do
+ context 'invalid file' do
+ let(:file) { fixture_file_upload('spec/fixtures/banana_sample.gif') }
+
+ it 'returns invalid file error' do
+ expect_any_instance_of(Notify).to receive(:import_issues_csv_email)
+
+ expect(subject[:success]).to eq(0)
+ expect(subject[:parse_error]).to eq(true)
+ end
+ end
+
+ context 'comma delimited file' do
+ let(:file) { fixture_file_upload('spec/fixtures/csv_comma.csv') }
+
+ it 'imports CSV without errors' do
+ expect_any_instance_of(Notify).to receive(:import_issues_csv_email)
+
+ expect(subject[:success]).to eq(3)
+ expect(subject[:error_lines]).to eq([])
+ expect(subject[:parse_error]).to eq(false)
+ end
+ end
+
+ context 'tab delimited file with error row' do
+ let(:file) { fixture_file_upload('spec/fixtures/csv_tab.csv') }
+
+ it 'imports CSV with some error rows' do
+ expect_any_instance_of(Notify).to receive(:import_issues_csv_email)
+
+ expect(subject[:success]).to eq(2)
+ expect(subject[:error_lines]).to eq([3])
+ expect(subject[:parse_error]).to eq(false)
+ end
+ end
+
+ context 'semicolon delimited file with CRLF' do
+ let(:file) { fixture_file_upload('spec/fixtures/csv_semicolon.csv') }
+
+ it 'imports CSV with a blank row' do
+ expect_any_instance_of(Notify).to receive(:import_issues_csv_email)
+
+ expect(subject[:success]).to eq(3)
+ expect(subject[:error_lines]).to eq([4])
+ expect(subject[:parse_error]).to eq(false)
+ end
+ end
+ end
+end
diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb
index 5a3ecb1019b..308f99dc0da 100644
--- a/spec/services/merge_requests/create_service_spec.rb
+++ b/spec/services/merge_requests/create_service_spec.rb
@@ -128,9 +128,9 @@ describe MergeRequests::CreateService do
end
context 'when head pipelines already exist for merge request source branch' do
- let(:sha) { project.commit(opts[:source_branch]).id }
- let!(:pipeline_1) { create(:ci_pipeline, project: project, ref: opts[:source_branch], project_id: project.id, sha: sha) }
- let!(:pipeline_2) { create(:ci_pipeline, project: project, ref: opts[:source_branch], project_id: project.id, sha: sha) }
+ let(:shas) { project.repository.commits(opts[:source_branch], limit: 2).map(&:id) }
+ let!(:pipeline_1) { create(:ci_pipeline, project: project, ref: opts[:source_branch], project_id: project.id, sha: shas[1]) }
+ let!(:pipeline_2) { create(:ci_pipeline, project: project, ref: opts[:source_branch], project_id: project.id, sha: shas[0]) }
let!(:pipeline_3) { create(:ci_pipeline, project: project, ref: "other_branch", project_id: project.id) }
before do
@@ -144,17 +144,30 @@ describe MergeRequests::CreateService do
it 'sets head pipeline' do
merge_request = service.execute
- expect(merge_request.head_pipeline).to eq(pipeline_2)
+ expect(merge_request.reload.head_pipeline).to eq(pipeline_2)
expect(merge_request).to be_persisted
end
- context 'when merge request head commit sha does not match pipeline sha' do
- it 'sets the head pipeline correctly' do
- pipeline_2.update(sha: 1234)
+ context 'when the new pipeline is associated with an old sha' do
+ let!(:pipeline_1) { create(:ci_pipeline, project: project, ref: opts[:source_branch], project_id: project.id, sha: shas[0]) }
+ let!(:pipeline_2) { create(:ci_pipeline, project: project, ref: opts[:source_branch], project_id: project.id, sha: shas[1]) }
+ it 'sets an old pipeline with associated with the latest sha as the head pipeline' do
merge_request = service.execute
- expect(merge_request.head_pipeline).to eq(pipeline_1)
+ expect(merge_request.reload.head_pipeline).to eq(pipeline_1)
+ expect(merge_request).to be_persisted
+ end
+ end
+
+ context 'when there are no pipelines with the diff head sha' do
+ let!(:pipeline_1) { create(:ci_pipeline, project: project, ref: opts[:source_branch], project_id: project.id, sha: shas[1]) }
+ let!(:pipeline_2) { create(:ci_pipeline, project: project, ref: opts[:source_branch], project_id: project.id, sha: shas[1]) }
+
+ it 'does not set the head pipeline' do
+ merge_request = service.execute
+
+ expect(merge_request.reload.head_pipeline).to be_nil
expect(merge_request).to be_persisted
end
end
diff --git a/spec/services/projects/operations/update_service_spec.rb b/spec/services/projects/operations/update_service_spec.rb
new file mode 100644
index 00000000000..731be907453
--- /dev/null
+++ b/spec/services/projects/operations/update_service_spec.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Projects::Operations::UpdateService do
+ set(:user) { create(:user) }
+ set(:project) { create(:project) }
+
+ let(:result) { subject.execute }
+
+ subject { described_class.new(project, user, params) }
+
+ describe '#execute' do
+ context 'error tracking' do
+ context 'with existing error tracking setting' do
+ let(:params) do
+ {
+ error_tracking_setting_attributes: {
+ enabled: false,
+ api_url: 'http://url',
+ token: 'token'
+ }
+ }
+ end
+
+ before do
+ create(:project_error_tracking_setting, project: project)
+ end
+
+ it 'updates the settings' do
+ expect(result[:status]).to eq(:success)
+
+ project.reload
+ expect(project.error_tracking_setting).not_to be_enabled
+ expect(project.error_tracking_setting.api_url).to eq('http://url')
+ expect(project.error_tracking_setting.token).to eq('token')
+ end
+ end
+
+ context 'without an existing error tracking setting' do
+ let(:params) do
+ {
+ error_tracking_setting_attributes: {
+ enabled: true,
+ api_url: 'http://url',
+ token: 'token'
+ }
+ }
+ end
+
+ it 'creates a setting' do
+ expect(result[:status]).to eq(:success)
+
+ expect(project.error_tracking_setting).to be_enabled
+ expect(project.error_tracking_setting.api_url).to eq('http://url')
+ expect(project.error_tracking_setting.token).to eq('token')
+ end
+ end
+
+ context 'with invalid parameters' do
+ let(:params) { {} }
+
+ let!(:error_tracking_setting) do
+ create(:project_error_tracking_setting, project: project)
+ end
+
+ it 'does nothing' do
+ expect(result[:status]).to eq(:success)
+ expect(project.reload.error_tracking_setting)
+ .to eq(error_tracking_setting)
+ end
+ end
+ end
+
+ context 'with inappropriate params' do
+ let(:params) { { name: '' } }
+
+ let!(:original_name) { project.name }
+
+ it 'ignores params' do
+ expect(result[:status]).to eq(:success)
+ expect(project.reload.name).to eq(original_name)
+ end
+ end
+ end
+end
diff --git a/spec/services/upload_service_spec.rb b/spec/services/upload_service_spec.rb
index 9b232a52efa..4a809d5bf18 100644
--- a/spec/services/upload_service_spec.rb
+++ b/spec/services/upload_service_spec.rb
@@ -63,11 +63,11 @@ describe UploadService do
@link_to_file = upload_file(@project, txt)
end
- it { expect(@link_to_file).to eq(nil) }
+ it { expect(@link_to_file).to eq({}) }
end
end
def upload_file(project, file)
- described_class.new(project, file, FileUploader).execute
+ described_class.new(project, file, FileUploader).execute.to_h
end
end
diff --git a/spec/validators/url_validator_spec.rb b/spec/validators/url_validator_spec.rb
index f3f3386382f..1bb42382e8a 100644
--- a/spec/validators/url_validator_spec.rb
+++ b/spec/validators/url_validator_spec.rb
@@ -172,4 +172,55 @@ describe UrlValidator do
end
end
end
+
+ context 'when enforce_sanitization is' do
+ let(:validator) { described_class.new(attributes: [:link_url], enforce_sanitization: enforce_sanitization) }
+ let(:unsafe_url) { "https://replaceme.com/'><script>alert(document.cookie)</script>" }
+ let(:safe_url) { 'https://replaceme.com/path/to/somewhere' }
+
+ let(:unsafe_internal_url) do
+ Gitlab.config.gitlab.protocol + '://' + Gitlab.config.gitlab.host +
+ "/'><script>alert(document.cookie)</script>"
+ end
+
+ context 'true' do
+ let(:enforce_sanitization) { true }
+
+ it 'prevents unsafe urls' do
+ badge.link_url = unsafe_url
+
+ subject
+
+ expect(badge.errors.empty?).to be false
+ end
+
+ it 'prevents unsafe internal urls' do
+ badge.link_url = unsafe_internal_url
+
+ subject
+
+ expect(badge.errors.empty?).to be false
+ end
+
+ it 'allows safe urls' do
+ badge.link_url = safe_url
+
+ subject
+
+ expect(badge.errors.empty?).to be true
+ end
+ end
+
+ context 'false' do
+ let(:enforce_sanitization) { false }
+
+ it 'allows unsafe urls' do
+ badge.link_url = unsafe_url
+
+ subject
+
+ expect(badge.errors.empty?).to be true
+ end
+ end
+ end
end
diff --git a/spec/views/projects/settings/operations/show.html.haml_spec.rb b/spec/views/projects/settings/operations/show.html.haml_spec.rb
new file mode 100644
index 00000000000..752fd82c5e8
--- /dev/null
+++ b/spec/views/projects/settings/operations/show.html.haml_spec.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require 'rails_helper'
+
+describe 'projects/settings/operations/show' do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+
+ before do
+ assign :project, project
+ end
+
+ describe 'Operations > Error Tracking' do
+ before do
+ stub_feature_flags(error_tracking: true)
+
+ project.add_reporter(user)
+
+ allow(view).to receive(:error_tracking_setting)
+ .and_return(error_tracking_setting)
+ allow(view).to receive(:current_user).and_return(user)
+ end
+
+ let!(:error_tracking_setting) do
+ create(:project_error_tracking_setting, project: project)
+ end
+
+ context 'Settings page ' do
+ it 'renders the Operations Settings page' do
+ render
+
+ expect(rendered).to have_content _('Error Tracking')
+ expect(rendered).to have_content _('To link Sentry to GitLab, enter your Sentry URL and Auth Token')
+ expect(rendered).to have_content _('Active')
+ end
+ end
+ end
+end
diff --git a/spec/workers/import_issues_csv_worker_spec.rb b/spec/workers/import_issues_csv_worker_spec.rb
new file mode 100644
index 00000000000..89370c4890d
--- /dev/null
+++ b/spec/workers/import_issues_csv_worker_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe ImportIssuesCsvWorker do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+ let(:upload) { create(:upload) }
+
+ let(:worker) { described_class.new }
+
+ describe '#perform' do
+ it 'calls #execute on Issues::ImportCsvService and destroys upload' do
+ expect_any_instance_of(Issues::ImportCsvService).to receive(:execute).and_return({ success: 5, errors: [], valid_file: true })
+
+ worker.perform(user.id, project.id, upload.id)
+
+ expect { upload.reload }.to raise_error ActiveRecord::RecordNotFound
+ end
+ end
+end
diff --git a/spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb b/spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb
index a2bc264b0f6..963237ceadf 100644
--- a/spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb
+++ b/spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb
@@ -21,17 +21,17 @@ describe UpdateHeadPipelineForMergeRequestWorker do
merge_request.merge_request_diff.update(head_commit_sha: 'different_sha')
end
- it 'does not update head_pipeline_id' do
- expect { subject.perform(merge_request.id) }.not_to raise_error
-
- expect(merge_request.reload.head_pipeline_id).to eq(nil)
+ it 'does not update head pipeline' do
+ expect { subject.perform(merge_request.id) }
+ .not_to change { merge_request.reload.head_pipeline_id }
end
end
end
context 'when pipeline does not exist for the source project and branch' do
it 'does not update the head_pipeline_id of the merge_request' do
- expect { subject.perform(merge_request.id) }.not_to change { merge_request.reload.head_pipeline_id }
+ expect { subject.perform(merge_request.id) }
+ .not_to change { merge_request.reload.head_pipeline_id }
end
end
diff --git a/yarn.lock b/yarn.lock
index 755a14e00e0..fb1854265b5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -641,10 +641,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.47.0.tgz#c03dda41aefd3889cbfed95a391836106ae2ac4d"
integrity sha512-0Bx/HxqR8xpqqaLnZiFAHIh1jTAFQPFToVZ6Wi3QyhsAwmXRAbgw1SlkRMZ7w3e6l+G71Wnw+GnI4rx1gK8JLQ==
-"@gitlab/ui@^1.18.0":
- version "1.18.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-1.18.0.tgz#5cc591b2c7958e59fa7b1b443d4235e0e8f956c9"
- integrity sha512-JqmiRSGYmK0DbGBQJBpjeRrcgjK25rCqG6QW6/GPTVLtRjbPPZYGvVg5PyA6nJUGAnwFoeApUZVML6X3OpnV1Q==
+"@gitlab/ui@^1.20.0":
+ version "1.20.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-1.20.0.tgz#50bd4b092646a2c6337f0f462779af8e702dda05"
+ integrity sha512-EJgrqon/tYCUPoOgnNNAXbrDXOEAajJwKHr4aR2R6vkJI3kVZiq66RNIe5ftGIUoNqYCDnRIkpLyo7MqzJPgcw==
dependencies:
babel-standalone "^6.26.0"
bootstrap-vue "^2.0.0-rc.11"
@@ -9887,9 +9887,9 @@ vue-style-loader@^4.1.0:
loader-utils "^1.0.2"
vue-template-compiler@^2.5.0, vue-template-compiler@^2.5.17:
- version "2.5.17"
- resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.5.17.tgz#52a4a078c327deb937482a509ae85c06f346c3cb"
- integrity sha512-63uI4syCwtGR5IJvZM0LN5tVsahrelomHtCxvRkZPJ/Tf3ADm1U1wG6KWycK3qCfqR+ygM5vewUvmJ0REAYksg==
+ version "2.5.21"
+ resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.5.21.tgz#a57ceb903177e8f643560a8d639a0f8db647054a"
+ integrity sha512-Vmk5Cv7UcmI99B9nXJEkaK262IQNnHp5rJYo+EwYpe2epTAXqcVyExhV6pk8jTkxQK2vRc8v8KmZBAwdmUZvvw==
dependencies:
de-indent "^1.0.2"
he "^1.1.0"
@@ -9904,12 +9904,7 @@ vue-virtual-scroll-list@^1.2.5:
resolved "https://registry.yarnpkg.com/vue-virtual-scroll-list/-/vue-virtual-scroll-list-1.2.5.tgz#bcbd010f7cdb035eba8958ebf807c6214d9a167a"
integrity sha1-vL0BD3zbA166iVjr+AfGIU2aFno=
-vue@^2.5.17:
- version "2.5.17"
- resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.17.tgz#0f8789ad718be68ca1872629832ed533589c6ada"
- integrity sha512-mFbcWoDIJi0w0Za4emyLiW72Jae0yjANHbCVquMKijcavBGypqlF7zHRgMa5k4sesdv7hv2rB4JPdZfR+TPfhQ==
-
-vue@^2.5.21:
+vue@^2.5.17, vue@^2.5.21:
version "2.5.21"
resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.21.tgz#3d33dcd03bb813912ce894a8303ab553699c4a85"
integrity sha512-Aejvyyfhn0zjVeLvXd70h4hrE4zZDx1wfZqia6ekkobLmUZ+vNFQer53B4fu0EjWBSiqApxPejzkO1Znt3joxQ==