summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/static_site_editor/components/edit_header.vue23
-rw-r--r--app/assets/javascripts/static_site_editor/components/publish_toolbar.vue24
-rw-r--r--app/assets/javascripts/static_site_editor/components/static_site_editor.vue15
-rw-r--r--app/assets/javascripts/static_site_editor/constants.js2
-rw-r--r--app/assets/javascripts/static_site_editor/index.js4
-rw-r--r--app/assets/javascripts/static_site_editor/store/state.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue8
-rw-r--r--app/controllers/groups/registry/repositories_controller.rb2
-rw-r--r--app/controllers/projects/static_site_editor_controller.rb3
-rw-r--r--app/finders/users_finder.rb8
-rw-r--r--changelogs/unreleased/210543-update-deploy-ecs.yml5
-rw-r--r--changelogs/unreleased/212971-group-level-container-registry-show-subgroups-repos.yml5
-rw-r--r--changelogs/unreleased/29426-add-api-endpoint-to-get-users-without-projects.yml5
-rw-r--r--changelogs/unreleased/add-user-agent-to-container-registry-client.yml5
-rw-r--r--db/structure.sql4
-rw-r--r--doc/administration/job_artifacts.md2
-rw-r--r--doc/administration/job_logs.md2
-rw-r--r--doc/administration/troubleshooting/navigating_gitlab_via_rails_console.md2
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql5
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json18
-rw-r--r--doc/api/graphql/reference/index.md1
-rw-r--r--doc/api/users.md3
-rw-r--r--doc/ci/cloud_deployment/index.md16
-rw-r--r--doc/development/database_debugging.md4
-rw-r--r--doc/development/import_project.md2
-rw-r--r--doc/development/testing_guide/review_apps.md26
-rw-r--r--doc/integration/sourcegraph.md2
-rw-r--r--doc/raketasks/backup_restore.md6
-rw-r--r--doc/security/unlock_user.md2
-rw-r--r--doc/user/project/merge_requests/merge_request_approvals.md2
-rw-r--r--lib/api/users.rb3
-rw-r--r--lib/container_registry/client.rb10
-rw-r--r--lib/gitlab/ci/templates/Deploy-ECS.gitlab-ci.yml2
-rw-r--r--lib/gitlab/static_site_editor/config.rb26
-rw-r--r--locale/gitlab.pot15
-rw-r--r--spec/controllers/groups/registry/repositories_controller_spec.rb119
-rw-r--r--spec/controllers/projects/static_site_editor_controller_spec.rb16
-rw-r--r--spec/frontend/static_site_editor/components/edit_header_spec.js38
-rw-r--r--spec/frontend/static_site_editor/components/publish_toolbar_spec.js14
-rw-r--r--spec/frontend/static_site_editor/components/static_site_editor_spec.js21
-rw-r--r--spec/frontend/static_site_editor/mock_data.js2
-rw-r--r--spec/lib/container_registry/client_spec.rb67
-rw-r--r--spec/lib/gitlab/static_site_editor/config_spec.rb35
-rw-r--r--spec/requests/api/users_spec.rb12
-rw-r--r--spec/support/shared_examples/requests/response_status_shared_examples.rb9
-rw-r--r--spec/uploaders/object_storage_spec.rb24
46 files changed, 483 insertions, 137 deletions
diff --git a/app/assets/javascripts/static_site_editor/components/edit_header.vue b/app/assets/javascripts/static_site_editor/components/edit_header.vue
new file mode 100644
index 00000000000..5660bfbe5ae
--- /dev/null
+++ b/app/assets/javascripts/static_site_editor/components/edit_header.vue
@@ -0,0 +1,23 @@
+<script>
+import { DEFAULT_HEADING } from '../constants';
+
+export default {
+ props: {
+ title: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ computed: {
+ heading() {
+ return this.title || DEFAULT_HEADING;
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <h3 ref="sseHeading">{{ heading }}</h3>
+ </div>
+</template>
diff --git a/app/assets/javascripts/static_site_editor/components/publish_toolbar.vue b/app/assets/javascripts/static_site_editor/components/publish_toolbar.vue
index 7f00fb71b04..efb442d4d09 100644
--- a/app/assets/javascripts/static_site_editor/components/publish_toolbar.vue
+++ b/app/assets/javascripts/static_site_editor/components/publish_toolbar.vue
@@ -7,6 +7,11 @@ export default {
GlLoadingIcon,
},
props: {
+ returnUrl: {
+ type: String,
+ required: false,
+ default: '',
+ },
saveable: {
type: Boolean,
required: false,
@@ -23,12 +28,17 @@ export default {
<template>
<div class="d-flex bg-light border-top justify-content-between align-items-center py-3 px-4">
<gl-loading-icon :class="{ invisible: !savingChanges }" size="md" />
- <gl-new-button
- variant="success"
- :disabled="!saveable || savingChanges"
- @click="$emit('submit')"
- >
- {{ __('Submit Changes') }}
- </gl-new-button>
+ <div>
+ <gl-new-button v-if="returnUrl" ref="returnUrlLink" :href="returnUrl">{{
+ s__('StaticSiteEditor|Return to site')
+ }}</gl-new-button>
+ <gl-new-button
+ variant="success"
+ :disabled="!saveable || savingChanges"
+ @click="$emit('submit')"
+ >
+ {{ __('Submit Changes') }}
+ </gl-new-button>
+ </div>
</div>
</template>
diff --git a/app/assets/javascripts/static_site_editor/components/static_site_editor.vue b/app/assets/javascripts/static_site_editor/components/static_site_editor.vue
index 8deae2f2c8a..4d912f5c0b5 100644
--- a/app/assets/javascripts/static_site_editor/components/static_site_editor.vue
+++ b/app/assets/javascripts/static_site_editor/components/static_site_editor.vue
@@ -3,16 +3,25 @@ import { mapState, mapGetters, mapActions } from 'vuex';
import { GlSkeletonLoader } from '@gitlab/ui';
import EditArea from './edit_area.vue';
+import EditHeader from './edit_header.vue';
import Toolbar from './publish_toolbar.vue';
export default {
components: {
EditArea,
+ EditHeader,
GlSkeletonLoader,
Toolbar,
},
computed: {
- ...mapState(['content', 'isLoadingContent', 'isSavingChanges', 'isContentLoaded']),
+ ...mapState([
+ 'content',
+ 'isLoadingContent',
+ 'isSavingChanges',
+ 'isContentLoaded',
+ 'returnUrl',
+ 'title',
+ ]),
...mapGetters(['contentChanged']),
},
mounted() {
@@ -24,7 +33,7 @@ export default {
};
</script>
<template>
- <div class="d-flex justify-content-center h-100 pt-2">
+ <div class="d-flex justify-content-center h-100 pt-2">
<div v-if="isLoadingContent" class="w-50 h-50">
<gl-skeleton-loader :width="500" :height="102">
<rect width="500" height="16" rx="4" />
@@ -36,12 +45,14 @@ export default {
</gl-skeleton-loader>
</div>
<div v-if="isContentLoaded" class="d-flex flex-grow-1 flex-column">
+ <edit-header class="w-75 align-self-center py-2" :title="title" />
<edit-area
class="w-75 h-100 shadow-none align-self-center"
:value="content"
@input="setContent"
/>
<toolbar
+ :return-url="returnUrl"
:saveable="contentChanged"
:saving-changes="isSavingChanges"
@submit="submitChanges"
diff --git a/app/assets/javascripts/static_site_editor/constants.js b/app/assets/javascripts/static_site_editor/constants.js
index 5081d467016..d7ce2a93a56 100644
--- a/app/assets/javascripts/static_site_editor/constants.js
+++ b/app/assets/javascripts/static_site_editor/constants.js
@@ -10,3 +10,5 @@ export const SUBMIT_CHANGES_COMMIT_ERROR = s__(
export const SUBMIT_CHANGES_MERGE_REQUEST_ERROR = s__(
'StaticSiteEditor|Could not create merge request.',
);
+
+export const DEFAULT_HEADING = s__('StaticSiteEditor|Static site editor');
diff --git a/app/assets/javascripts/static_site_editor/index.js b/app/assets/javascripts/static_site_editor/index.js
index 3d40f3918a4..c6a883c659a 100644
--- a/app/assets/javascripts/static_site_editor/index.js
+++ b/app/assets/javascripts/static_site_editor/index.js
@@ -3,10 +3,10 @@ import StaticSiteEditor from './components/static_site_editor.vue';
import createStore from './store';
const initStaticSiteEditor = el => {
- const { projectId, path: sourcePath } = el.dataset;
+ const { projectId, returnUrl, path: sourcePath } = el.dataset;
const store = createStore({
- initialState: { projectId, sourcePath, username: window.gon.current_username },
+ initialState: { projectId, returnUrl, sourcePath, username: window.gon.current_username },
});
return new Vue({
diff --git a/app/assets/javascripts/static_site_editor/store/state.js b/app/assets/javascripts/static_site_editor/store/state.js
index d48cc8ed1a4..98a84d9f75d 100644
--- a/app/assets/javascripts/static_site_editor/store/state.js
+++ b/app/assets/javascripts/static_site_editor/store/state.js
@@ -1,6 +1,7 @@
const createState = (initialState = {}) => ({
username: null,
projectId: null,
+ returnUrl: null,
sourcePath: null,
isLoadingContent: false,
diff --git a/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue b/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue
index 82b3c784f96..a0c161a335a 100644
--- a/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue
+++ b/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue
@@ -1,4 +1,5 @@
<script>
+import { __ } from '~/locale';
import { roundOffFloat } from '~/lib/utils/common_utils';
import tooltip from '~/vue_shared/directives/tooltip';
@@ -27,6 +28,11 @@ export default {
required: false,
default: 'neutral',
},
+ unavailableLabel: {
+ type: String,
+ required: false,
+ default: __('Not available'),
+ },
successCount: {
type: Number,
required: true,
@@ -103,7 +109,7 @@ export default {
<template>
<div :class="cssClass" class="stacked-progress-bar">
- <span v-if="!totalCount" class="status-unavailable"> {{ __('Not available') }} </span>
+ <span v-if="!totalCount" class="status-unavailable">{{ unavailableLabel }}</span>
<span
v-if="successPercent"
v-tooltip
diff --git a/app/controllers/groups/registry/repositories_controller.rb b/app/controllers/groups/registry/repositories_controller.rb
index 0240c87e699..16aa6e50320 100644
--- a/app/controllers/groups/registry/repositories_controller.rb
+++ b/app/controllers/groups/registry/repositories_controller.rb
@@ -9,7 +9,7 @@ module Groups
respond_to do |format|
format.html
format.json do
- @images = group.container_repositories.with_api_entity_associations
+ @images = ContainerRepositoriesFinder.new(user: current_user, subject: group).execute.with_api_entity_associations
track_event(:list_repositories)
diff --git a/app/controllers/projects/static_site_editor_controller.rb b/app/controllers/projects/static_site_editor_controller.rb
index 98ec2335899..74f28c3da67 100644
--- a/app/controllers/projects/static_site_editor_controller.rb
+++ b/app/controllers/projects/static_site_editor_controller.rb
@@ -2,10 +2,13 @@
class Projects::StaticSiteEditorController < Projects::ApplicationController
include ExtractsPath
+ include CreatesCommit
+
layout 'fullscreen'
prepend_before_action :authenticate_user!, only: [:show]
before_action :assign_ref_and_path, only: [:show]
+ before_action :authorize_edit_tree!, only: [:show]
def show
@config = Gitlab::StaticSiteEditor::Config.new(@repository, @ref, @path, params[:return_url])
diff --git a/app/finders/users_finder.rb b/app/finders/users_finder.rb
index d5650c6828d..ebb686c2aa7 100644
--- a/app/finders/users_finder.rb
+++ b/app/finders/users_finder.rb
@@ -14,6 +14,7 @@
# active: boolean
# blocked: boolean
# external: boolean
+# without_projects: boolean
#
class UsersFinder
include CreatedAtFilter
@@ -36,6 +37,7 @@ class UsersFinder
users = by_external(users)
users = by_2fa(users)
users = by_created_at(users)
+ users = by_without_projects(users)
users = by_custom_attributes(users)
users
@@ -94,6 +96,12 @@ class UsersFinder
users
end
end
+
+ def by_without_projects(users)
+ return users unless params[:without_projects]
+
+ users.without_projects
+ end
end
UsersFinder.prepend_if_ee('EE::UsersFinder')
diff --git a/changelogs/unreleased/210543-update-deploy-ecs.yml b/changelogs/unreleased/210543-update-deploy-ecs.yml
new file mode 100644
index 00000000000..47df9039a17
--- /dev/null
+++ b/changelogs/unreleased/210543-update-deploy-ecs.yml
@@ -0,0 +1,5 @@
+---
+title: Update aws-ecs image location in CI template
+merge_request: 27382
+author:
+type: changed
diff --git a/changelogs/unreleased/212971-group-level-container-registry-show-subgroups-repos.yml b/changelogs/unreleased/212971-group-level-container-registry-show-subgroups-repos.yml
new file mode 100644
index 00000000000..73eeb9923ea
--- /dev/null
+++ b/changelogs/unreleased/212971-group-level-container-registry-show-subgroups-repos.yml
@@ -0,0 +1,5 @@
+---
+title: Group level container registry show subgroups repos
+merge_request: 29263
+author:
+type: fixed
diff --git a/changelogs/unreleased/29426-add-api-endpoint-to-get-users-without-projects.yml b/changelogs/unreleased/29426-add-api-endpoint-to-get-users-without-projects.yml
new file mode 100644
index 00000000000..ccf3533e96f
--- /dev/null
+++ b/changelogs/unreleased/29426-add-api-endpoint-to-get-users-without-projects.yml
@@ -0,0 +1,5 @@
+---
+title: Add API endpoint to get users without projects
+merge_request: 29347
+author:
+type: added
diff --git a/changelogs/unreleased/add-user-agent-to-container-registry-client.yml b/changelogs/unreleased/add-user-agent-to-container-registry-client.yml
new file mode 100644
index 00000000000..2c3db36f981
--- /dev/null
+++ b/changelogs/unreleased/add-user-agent-to-container-registry-client.yml
@@ -0,0 +1,5 @@
+---
+title: Add Gitlab User-Agent to ContainerRegistry::Client
+merge_request: 29294
+author: Sashi Kumar
+type: other
diff --git a/db/structure.sql b/db/structure.sql
index f478fc3d709..d1fdcc9e465 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -397,9 +397,9 @@ CREATE TABLE public.application_settings (
email_restrictions text,
npm_package_requests_forwarding boolean DEFAULT true NOT NULL,
namespace_storage_size_limit bigint DEFAULT 0 NOT NULL,
- issues_create_limit integer DEFAULT 300 NOT NULL,
seat_link_enabled boolean DEFAULT true NOT NULL,
- container_expiration_policies_enable_historic_entries boolean DEFAULT false NOT NULL
+ container_expiration_policies_enable_historic_entries boolean DEFAULT false NOT NULL,
+ issues_create_limit integer DEFAULT 300 NOT NULL
);
CREATE SEQUENCE public.application_settings_id_seq
diff --git a/doc/administration/job_artifacts.md b/doc/administration/job_artifacts.md
index a9a13062a25..3777f551996 100644
--- a/doc/administration/job_artifacts.md
+++ b/doc/administration/job_artifacts.md
@@ -353,7 +353,7 @@ you can flip the feature flag from a Rails console.
```shell
cd /home/git/gitlab
- RAILS_ENV=production sudo -u git -H bundle exec rails console
+ sudo -u git -H bundle exec rails console -e production
```
1. Flip the switch and disable it:
diff --git a/doc/administration/job_logs.md b/doc/administration/job_logs.md
index 439320279fe..6020d1d2850 100644
--- a/doc/administration/job_logs.md
+++ b/doc/administration/job_logs.md
@@ -106,7 +106,7 @@ gitlab-rails console
# Installation from source
cd /home/git/gitlab
-sudo -u git -H bin/rails console RAILS_ENV=production
+sudo -u git -H bin/rails console -e production
```
**To check if incremental logging (trace) is enabled:**
diff --git a/doc/administration/troubleshooting/navigating_gitlab_via_rails_console.md b/doc/administration/troubleshooting/navigating_gitlab_via_rails_console.md
index b78d5490cd2..69af7ea6801 100644
--- a/doc/administration/troubleshooting/navigating_gitlab_via_rails_console.md
+++ b/doc/administration/troubleshooting/navigating_gitlab_via_rails_console.md
@@ -30,7 +30,7 @@ sudo gitlab-rails console
For source installations, you'll have to instead run:
```shell
-sudo -u git -H bundle exec rails console RAILS_ENV=production
+sudo -u git -H bundle exec rails console -e production
```
Further code examples will all take place inside the Rails console and also
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
index eb9b285803d..91d6717de7e 100644
--- a/doc/api/graphql/reference/gitlab_schema.graphql
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -2160,6 +2160,11 @@ type Epic implements Noteable {
hasIssues: Boolean!
"""
+ Indicates if the epic has a parent epic
+ """
+ hasParent: Boolean!
+
+ """
Current health status of the epic
"""
healthStatus: EpicHealthStatus
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
index f6c3510d6dc..fb642b1222f 100644
--- a/doc/api/graphql/reference/gitlab_schema.json
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -6337,6 +6337,24 @@
"deprecationReason": null
},
{
+ "name": "hasParent",
+ "description": "Indicates if the epic has a parent epic",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "healthStatus",
"description": "Current health status of the epic",
"args": [
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 082d7decbf9..d1ea825bef3 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -359,6 +359,7 @@ Represents an epic.
| `group` | Group! | Group to which the epic belongs |
| `hasChildren` | Boolean! | Indicates if the epic has children |
| `hasIssues` | Boolean! | Indicates if the epic has direct issues |
+| `hasParent` | Boolean! | Indicates if the epic has a parent epic |
| `healthStatus` | EpicHealthStatus | Current health status of the epic |
| `id` | ID! | ID of the epic |
| `iid` | ID! | Internal ID of the epic |
diff --git a/doc/api/users.md b/doc/api/users.md
index 8d7dad7ae35..90aafcef035 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -75,6 +75,7 @@ GET /users
| `order_by` | string | no | Return users ordered by `id`, `name`, `username`, `created_at`, or `updated_at` fields. Default is `id` |
| `sort` | string | no | Return users sorted in `asc` or `desc` order. Default is `desc` |
| `two_factor` | string | no | Filter users by Two-factor authentication. Filter values are `enabled` or `disabled`. By default it returns all users |
+| `without_projects` | boolean | no | Filter users without projects. Default is `false` |
```json
[
@@ -207,6 +208,8 @@ You can search users by creation date time range with:
GET /users?created_before=2001-01-02T00:00:00.060Z&created_after=1999-01-02T00:00:00.060
```
+You can search for users without projects with: `/users?without_projects=true`
+
You can filter by [custom attributes](custom_attributes.md) with:
```plaintext
diff --git a/doc/ci/cloud_deployment/index.md b/doc/ci/cloud_deployment/index.md
index ccff302750c..f70998a5f49 100644
--- a/doc/ci/cloud_deployment/index.md
+++ b/doc/ci/cloud_deployment/index.md
@@ -39,7 +39,7 @@ Some credentials are required to be able to run `aws` commands:
```yml
deploy:
stage: deploy
- image: registry.gitlab.com/gitlab-org/cloud-deploy:latest # see the note below
+ image: registry.gitlab.com/gitlab-org/cloud-deploy/aws-base:latest # see the note below
script:
- aws s3 ...
- aws create-deployment ...
@@ -47,7 +47,7 @@ Some credentials are required to be able to run `aws` commands:
NOTE: **Note:**
Please note that the image used in the example above
- (`registry.gitlab.com/gitlab-org/cloud-deploy:latest`) is hosted on the [GitLab
+ (`registry.gitlab.com/gitlab-org/cloud-deploy/aws-base:latest`) is hosted on the [GitLab
Container Registry](../../user/packages/container_registry/index.md) and is
ready to use. Alternatively, replace the image with another one hosted on [AWS ECR](#aws-ecr).
@@ -119,3 +119,15 @@ After you're all set up on AWS ECS, follow these steps:
Finally, your AWS ECS service will be updated with the new revision of the
task definition, making the cluster pull the newest version of your
application.
+
+Alternatively, if you don't wish to use the `Deploy-ECS.gitlab-ci.yml` template
+to deploy to AWS ECS, you can always use our
+`aws-base` Docker image to run your own [AWS CLI commands for ECS](https://docs.aws.amazon.com/cli/latest/reference/ecs/index.html#cli-aws-ecs).
+
+```yaml
+deploy:
+ stage: deploy
+ image: registry.gitlab.com/gitlab-org/cloud-deploy/aws-base:latest
+ script:
+ - aws ecs register-task-definition ...
+```
diff --git a/doc/development/database_debugging.md b/doc/development/database_debugging.md
index e577ba6ec8f..46cb869fea3 100644
--- a/doc/development/database_debugging.md
+++ b/doc/development/database_debugging.md
@@ -41,8 +41,8 @@ Access the database via one of these commands (they all get you to the same plac
```ruby
gdk psql -d gitlabhq_development
-bundle exec rails dbconsole RAILS_ENV=development
-bundle exec rails db RAILS_ENV=development
+bundle exec rails dbconsole -e development
+bundle exec rails db -e development
```
- `\q`: Quit/exit
diff --git a/doc/development/import_project.md b/doc/development/import_project.md
index 0701279ddea..78efc6ce2ab 100644
--- a/doc/development/import_project.md
+++ b/doc/development/import_project.md
@@ -78,7 +78,7 @@ The last option is to import a project using a Rails console:
gitlab-rails console
# For installations from source
- sudo -u git -H bundle exec rails console RAILS_ENV=production
+ sudo -u git -H bundle exec rails console -e production
```
1. Create a project and run `Project::TreeRestorer`:
diff --git a/doc/development/testing_guide/review_apps.md b/doc/development/testing_guide/review_apps.md
index efa58cbeae3..9eb5d5add8a 100644
--- a/doc/development/testing_guide/review_apps.md
+++ b/doc/development/testing_guide/review_apps.md
@@ -136,28 +136,18 @@ browser performance testing using a
### Node pools
-Both `review-apps-ce` and `review-apps-ee` clusters are currently set up with
-two node pools:
+The `review-apps-ee` and `review-apps-ce` clusters are currently set up with
+the following node pools:
-- a node pool of non-preemptible `n1-standard-2` (2 vCPU, 7.5 GB memory) nodes
- dedicated to the `tiller` deployment (see below) with a single node.
-- a node pool of preemptible `n1-standard-2` (2 vCPU, 7.5 GB memory) nodes,
- with a minimum of 1 node and a maximum of 250 nodes.
+- `review-apps-ee` of preemptible `e2-highcpu-16` (16 vCPU, 16 GB memory) nodes with autoscaling
+- `review-apps-ce` of preemptible `n1-standard-8` (8 vCPU, 16 GB memory) nodes with autoscaling
-### Helm/Tiller
+### Helm
-The Helm/Tiller version used is defined in the
-[`registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-charts-build-base` image](https://gitlab.com/gitlab-org/gitlab-build-images/blob/master/Dockerfile.gitlab-charts-build-base#L4)
+The Helm version used is defined in the
+[`registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-helm3-kubectl1.14` image](https://gitlab.com/gitlab-org/gitlab-build-images/-/blob/master/Dockerfile.gitlab-helm3-kubectl1.14#L7)
used by the `review-deploy` and `review-stop` jobs.
-The `tiller` deployment (the Helm server) is deployed to a dedicated node pool
-that has the `app=helm` label and a specific
-[taint](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/)
-to prevent other pods from being scheduled on this node pool.
-
-This is to ensure Tiller isn't affected by "noisy" neighbors that could put
-their node under pressure.
-
## How to
### Get access to the GCP Review Apps cluster
@@ -241,7 +231,7 @@ due to Helm or Kubernetes trying to recreate the components.
**Where to look for further debugging:**
-Look at a recent `review-deploy` job log, and at the Tiller logs.
+Look at a recent `review-deploy` job log.
**Useful commands:**
diff --git a/doc/integration/sourcegraph.md b/doc/integration/sourcegraph.md
index c0ce3c30ca6..5da9dd1fbc9 100644
--- a/doc/integration/sourcegraph.md
+++ b/doc/integration/sourcegraph.md
@@ -42,7 +42,7 @@ gitlab-rails console
# Installation from source
cd /home/git/gitlab
-sudo -u git -H bin/rails console RAILS_ENV=production
+sudo -u git -H bin/rails console -e production
```
Then run the following command to enable the feature flag:
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index b0d90ea0345..e98df17d944 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -947,7 +947,7 @@ backup beforehand.
For installations from source:
```shell
- sudo -u git -H bundle exec rails dbconsole RAILS_ENV=production
+ sudo -u git -H bundle exec rails dbconsole -e production
```
1. Check the `ci_group_variables` and `ci_variables` tables:
@@ -982,7 +982,7 @@ backup beforehand.
For installations from source:
```shell
- sudo -u git -H bundle exec rails dbconsole RAILS_ENV=production
+ sudo -u git -H bundle exec rails dbconsole -e production
```
1. Clear all the tokens for projects, groups, and the whole instance:
@@ -1015,7 +1015,7 @@ backup beforehand.
For installations from source:
```shell
- sudo -u git -H bundle exec rails dbconsole RAILS_ENV=production
+ sudo -u git -H bundle exec rails dbconsole -e production
```
1. Clear all the tokens for pending jobs:
diff --git a/doc/security/unlock_user.md b/doc/security/unlock_user.md
index befb5d12877..bf3bbbb701e 100644
--- a/doc/security/unlock_user.md
+++ b/doc/security/unlock_user.md
@@ -16,7 +16,7 @@ To unlock a locked user:
sudo gitlab-rails console -e production
## For installations from source
- sudo -u git -H bundle exec rails console RAILS_ENV=production
+ sudo -u git -H bundle exec rails console -e production
```
1. Find the user to unlock. You can search by email or ID.
diff --git a/doc/user/project/merge_requests/merge_request_approvals.md b/doc/user/project/merge_requests/merge_request_approvals.md
index d378c119aa8..e5896e62397 100644
--- a/doc/user/project/merge_requests/merge_request_approvals.md
+++ b/doc/user/project/merge_requests/merge_request_approvals.md
@@ -277,7 +277,7 @@ gitlab-rails console
# Installation from source
cd /home/git/gitlab
-sudo -u git -H bin/rails console RAILS_ENV=production
+sudo -u git -H bin/rails console -e production
```
Then run `Feature.enable(:approval_rules)` to enable the updated interface.
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 1694f3fe3fb..c986414c223 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -82,6 +82,7 @@ module API
optional :blocked, type: Boolean, default: false, desc: 'Filters only blocked users'
optional :created_after, type: DateTime, desc: 'Return users created after the specified time'
optional :created_before, type: DateTime, desc: 'Return users created before the specified time'
+ optional :without_projects, type: Boolean, default: false, desc: 'Filters only users without projects'
all_or_none_of :extern_uid, :provider
use :sort_params
@@ -94,7 +95,7 @@ module API
authenticated_as_admin! if params[:external].present? || (params[:extern_uid].present? && params[:provider].present?)
unless current_user&.admin?
- params.except!(:created_after, :created_before, :order_by, :sort, :two_factor)
+ params.except!(:created_after, :created_before, :order_by, :sort, :two_factor, :without_projects)
end
users = UsersFinder.new(current_user, params).execute
diff --git a/lib/container_registry/client.rb b/lib/container_registry/client.rb
index 12f7f04634f..56f556c229a 100644
--- a/lib/container_registry/client.rb
+++ b/lib/container_registry/client.rb
@@ -159,13 +159,13 @@ module ContainerRegistry
end
def faraday
- @faraday ||= Faraday.new(@base_uri) do |conn|
+ @faraday ||= faraday_base do |conn|
initialize_connection(conn, @options, &method(:accept_manifest))
end
end
def faraday_blob
- @faraday_blob ||= Faraday.new(@base_uri) do |conn|
+ @faraday_blob ||= faraday_base do |conn|
initialize_connection(conn, @options)
end
end
@@ -173,12 +173,16 @@ module ContainerRegistry
# Create a new request to make sure the Authorization header is not inserted
# via the Faraday middleware
def faraday_redirect
- @faraday_redirect ||= Faraday.new(@base_uri) do |conn|
+ @faraday_redirect ||= faraday_base do |conn|
conn.request :json
conn.adapter :net_http
end
end
+ def faraday_base(&block)
+ Faraday.new(@base_uri, headers: { user_agent: "GitLab/#{Gitlab::VERSION}" }, &block)
+ end
+
def delete_if_exists(path)
result = faraday.delete(path)
diff --git a/lib/gitlab/ci/templates/Deploy-ECS.gitlab-ci.yml b/lib/gitlab/ci/templates/Deploy-ECS.gitlab-ci.yml
index ecca1731579..a41b399032f 100644
--- a/lib/gitlab/ci/templates/Deploy-ECS.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Deploy-ECS.gitlab-ci.yml
@@ -9,7 +9,7 @@ include:
- template: Jobs/Build.gitlab-ci.yml
.deploy_to_ecs:
- image: registry.gitlab.com/gitlab-org/cloud-deploy:latest
+ image: registry.gitlab.com/gitlab-org/cloud-deploy/aws-ecs:latest
script:
- ecs update-task-definition
diff --git a/lib/gitlab/static_site_editor/config.rb b/lib/gitlab/static_site_editor/config.rb
index 4bc0fc95abd..41d54ee0a92 100644
--- a/lib/gitlab/static_site_editor/config.rb
+++ b/lib/gitlab/static_site_editor/config.rb
@@ -3,33 +3,49 @@
module Gitlab
module StaticSiteEditor
class Config
+ SUPPORTED_EXTENSIONS = %w[.md].freeze
+
def initialize(repository, ref, file_path, return_url)
@repository = repository
@ref = ref
@file_path = file_path
@return_url = return_url
+ @commit_id = repository.commit(ref)&.id if ref
end
def payload
{
branch: ref,
path: file_path,
- commit: commit.id,
+ commit_id: commit_id,
project_id: project.id,
project: project.path,
namespace: project.namespace.path,
- return_url: return_url
+ return_url: return_url,
+ is_supported_content: supported_content?
}
end
private
- attr_reader :repository, :ref, :file_path, :return_url
+ attr_reader :repository, :ref, :file_path, :return_url, :commit_id
delegate :project, to: :repository
- def commit
- repository.commit(ref)
+ def supported_content?
+ master_branch? && extension_supported? && file_exists?
+ end
+
+ def master_branch?
+ ref == 'master'
+ end
+
+ def extension_supported?
+ File.extname(file_path).in?(SUPPORTED_EXTENSIONS)
+ end
+
+ def file_exists?
+ commit_id.present? && repository.blob_at(commit_id, file_path).present?
end
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index a267e65a925..3b1c8f0d706 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -11891,6 +11891,9 @@ msgstr ""
msgid "Learn how to %{no_packages_link_start}publish and share your packages%{no_packages_link_end} with GitLab."
msgstr ""
+msgid "Learn how to enable synchronization"
+msgstr ""
+
msgid "Learn more"
msgstr ""
@@ -13827,6 +13830,9 @@ msgstr ""
msgid "Nothing to preview."
msgstr ""
+msgid "Nothing to synchronize"
+msgstr ""
+
msgid "Notification events"
msgstr ""
@@ -19452,6 +19458,9 @@ msgstr ""
msgid "StaticSiteEditor|Return to site"
msgstr ""
+msgid "StaticSiteEditor|Static site editor"
+msgstr ""
+
msgid "StaticSiteEditor|Success!"
msgstr ""
@@ -19866,6 +19875,12 @@ msgstr ""
msgid "Synced"
msgstr ""
+msgid "Synchronization disabled"
+msgstr ""
+
+msgid "Synchronization of container repositories is disabled."
+msgstr ""
+
msgid "System"
msgstr ""
diff --git a/spec/controllers/groups/registry/repositories_controller_spec.rb b/spec/controllers/groups/registry/repositories_controller_spec.rb
index eadc3a7f739..a84664c6c04 100644
--- a/spec/controllers/groups/registry/repositories_controller_spec.rb
+++ b/spec/controllers/groups/registry/repositories_controller_spec.rb
@@ -7,6 +7,13 @@ describe Groups::Registry::RepositoriesController do
let_it_be(:guest) { create(:user) }
let_it_be(:group, reload: true) { create(:group) }
+ subject do
+ get :index, params: {
+ group_id: group,
+ format: format
+ }
+ end
+
before do
stub_container_registry_config(enabled: true)
group.add_owner(user)
@@ -15,51 +22,67 @@ describe Groups::Registry::RepositoriesController do
end
shared_examples 'renders a list of repositories' do
+ let_it_be(:repo) { create_project_with_repo(test_group) }
+
+ it 'returns a list of projects for json format' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_kind_of(Array)
+ expect(json_response.first).to include(
+ 'id' => repo.id,
+ 'name' => repo.name
+ )
+ end
+ end
+
+ shared_examples 'renders correctly' do
context 'when user has access to registry' do
- it 'show index page' do
- expect(Gitlab::Tracking).not_to receive(:event)
+ let_it_be(:test_group) { group }
- get :index, params: {
- group_id: group
- }
+ context 'html format' do
+ let(:format) { :html }
- expect(response).to have_gitlab_http_status(:ok)
- end
+ it 'show index page' do
+ expect(Gitlab::Tracking).not_to receive(:event)
- it 'has the correct response schema' do
- get :index, params: {
- group_id: group,
- format: :json
- }
+ subject
- expect(response).to match_response_schema('registry/repositories')
- expect(response).to include_pagination_headers
+ expect(response).to have_gitlab_http_status(:ok)
+ end
end
- it 'returns a list of projects for json format' do
- project = create(:project, group: group)
- repo = create(:container_repository, project: project)
-
- get :index, params: {
- group_id: group,
- format: :json
- }
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to be_kind_of(Array)
- expect(json_response.first).to include(
- 'id' => repo.id,
- 'name' => repo.name
- )
- end
+ context 'json format' do
+ let(:format) { :json }
+
+ it 'has the correct response schema' do
+ subject
+
+ expect(response).to match_response_schema('registry/repositories')
+ expect(response).to include_pagination_headers
+ end
- it 'tracks the event' do
- expect(Gitlab::Tracking).to receive(:event).with(anything, 'list_repositories', {})
+ it_behaves_like 'renders a list of repositories'
- get :index, params: {
- group_id: group,
- format: :json
- }
+ it_behaves_like 'a gitlab tracking event', described_class.name, 'list_repositories'
+
+ context 'with project in subgroup' do
+ let_it_be(:test_group) { create(:group, parent: group ) }
+
+ it_behaves_like 'renders a list of repositories'
+
+ context 'with project in subgroup and group' do
+ let_it_be(:repo_in_test_group) { create_project_with_repo(test_group) }
+ let_it_be(:repo_in_group) { create_project_with_repo(group) }
+
+ it 'returns all the projects' do
+ subject
+
+ expect(json_response).to be_kind_of(Array)
+ expect(json_response.length).to eq 2
+ end
+ end
+ end
end
end
@@ -69,20 +92,30 @@ describe Groups::Registry::RepositoriesController do
sign_in(guest)
end
- it 'renders not found' do
- get :index, params: {
- group_id: group
- }
- expect(response).to have_gitlab_http_status(:not_found)
+ context 'json format' do
+ let(:format) { :json }
+
+ it_behaves_like 'returning response status', :not_found
+ end
+
+ context 'html format' do
+ let(:format) { :html }
+
+ it_behaves_like 'returning response status', :not_found
end
end
end
context 'GET #index' do
- it_behaves_like 'renders a list of repositories'
+ it_behaves_like 'renders correctly'
end
context 'GET #show' do
- it_behaves_like 'renders a list of repositories'
+ it_behaves_like 'renders correctly'
+ end
+
+ def create_project_with_repo(group)
+ project = create(:project, group: test_group)
+ create(:container_repository, project: project)
end
end
diff --git a/spec/controllers/projects/static_site_editor_controller_spec.rb b/spec/controllers/projects/static_site_editor_controller_spec.rb
index d1224bb75c0..f7c8848b8cf 100644
--- a/spec/controllers/projects/static_site_editor_controller_spec.rb
+++ b/spec/controllers/projects/static_site_editor_controller_spec.rb
@@ -26,7 +26,21 @@ describe Projects::StaticSiteEditorController do
end
end
- %w[guest developer maintainer].each do |role|
+ context 'as guest' do
+ let(:user) { create(:user) }
+
+ before do
+ project.add_guest(user)
+ sign_in(user)
+ get :show, params: default_params
+ end
+
+ it 'responds with 404 page' do
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ %w[developer maintainer].each do |role|
context "as #{role}" do
let(:user) { create(:user) }
diff --git a/spec/frontend/static_site_editor/components/edit_header_spec.js b/spec/frontend/static_site_editor/components/edit_header_spec.js
new file mode 100644
index 00000000000..2b0fe226a0b
--- /dev/null
+++ b/spec/frontend/static_site_editor/components/edit_header_spec.js
@@ -0,0 +1,38 @@
+import { shallowMount } from '@vue/test-utils';
+
+import EditHeader from '~/static_site_editor/components/edit_header.vue';
+import { DEFAULT_HEADING } from '~/static_site_editor/constants';
+
+import { sourceContentTitle } from '../mock_data';
+
+describe('~/static_site_editor/components/edit_header.vue', () => {
+ let wrapper;
+
+ const buildWrapper = (propsData = {}) => {
+ wrapper = shallowMount(EditHeader, {
+ propsData: {
+ ...propsData,
+ },
+ });
+ };
+
+ const findHeading = () => wrapper.find({ ref: 'sseHeading' });
+
+ beforeEach(() => {
+ buildWrapper();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders the default heading if there is no title prop', () => {
+ expect(findHeading().text()).toBe(DEFAULT_HEADING);
+ });
+
+ it('renders the title prop value in the heading', () => {
+ buildWrapper({ title: sourceContentTitle });
+
+ expect(findHeading().text()).toBe(sourceContentTitle);
+ });
+});
diff --git a/spec/frontend/static_site_editor/components/publish_toolbar_spec.js b/spec/frontend/static_site_editor/components/publish_toolbar_spec.js
index 0edc3f4c920..f00fc38430f 100644
--- a/spec/frontend/static_site_editor/components/publish_toolbar_spec.js
+++ b/spec/frontend/static_site_editor/components/publish_toolbar_spec.js
@@ -3,6 +3,8 @@ import { GlNewButton, GlLoadingIcon } from '@gitlab/ui';
import PublishToolbar from '~/static_site_editor/components/publish_toolbar.vue';
+import { returnUrl } from '../mock_data';
+
describe('Static Site Editor Toolbar', () => {
let wrapper;
@@ -15,6 +17,7 @@ describe('Static Site Editor Toolbar', () => {
});
};
+ const findReturnUrlLink = () => wrapper.find({ ref: 'returnUrlLink' });
const findSaveChangesButton = () => wrapper.find(GlNewButton);
const findLoadingIndicator = () => wrapper.find(GlLoadingIcon);
@@ -38,6 +41,17 @@ describe('Static Site Editor Toolbar', () => {
expect(findLoadingIndicator().classes()).toContain('invisible');
});
+ it('does not render returnUrl link', () => {
+ expect(findReturnUrlLink().exists()).toBe(false);
+ });
+
+ it('renders returnUrl link when returnUrl prop exists', () => {
+ buildWrapper({ returnUrl });
+
+ expect(findReturnUrlLink().exists()).toBe(true);
+ expect(findReturnUrlLink().attributes('href')).toBe(returnUrl);
+ });
+
describe('when saveable', () => {
it('enables Submit Changes button', () => {
buildWrapper({ saveable: true });
diff --git a/spec/frontend/static_site_editor/components/static_site_editor_spec.js b/spec/frontend/static_site_editor/components/static_site_editor_spec.js
index 2c4fa0e061a..d427df9bd4b 100644
--- a/spec/frontend/static_site_editor/components/static_site_editor_spec.js
+++ b/spec/frontend/static_site_editor/components/static_site_editor_spec.js
@@ -7,9 +7,10 @@ import createState from '~/static_site_editor/store/state';
import StaticSiteEditor from '~/static_site_editor/components/static_site_editor.vue';
import EditArea from '~/static_site_editor/components/edit_area.vue';
+import EditHeader from '~/static_site_editor/components/edit_header.vue';
import PublishToolbar from '~/static_site_editor/components/publish_toolbar.vue';
-import { sourceContent } from '../mock_data';
+import { sourceContent, sourceContentTitle } from '../mock_data';
const localVue = createLocalVue();
@@ -60,6 +61,7 @@ describe('StaticSiteEditor', () => {
};
const findEditArea = () => wrapper.find(EditArea);
+ const findEditHeader = () => wrapper.find(EditHeader);
const findPublishToolbar = () => wrapper.find(PublishToolbar);
const findSkeletonLoader = () => wrapper.find(GlSkeletonLoader);
@@ -77,16 +79,21 @@ describe('StaticSiteEditor', () => {
expect(findEditArea().exists()).toBe(false);
});
+ it('does not render edit header', () => {
+ expect(findEditHeader().exists()).toBe(false);
+ });
+
it('does not render toolbar', () => {
expect(findPublishToolbar().exists()).toBe(false);
});
});
describe('when content is loaded', () => {
- const content = 'edit area content';
+ const content = sourceContent;
+ const title = sourceContentTitle;
beforeEach(() => {
- buildContentLoadedStore({ initialState: { content } });
+ buildContentLoadedStore({ initialState: { content, title } });
buildWrapper();
});
@@ -94,6 +101,10 @@ describe('StaticSiteEditor', () => {
expect(findEditArea().exists()).toBe(true);
});
+ it('renders the edit header', () => {
+ expect(findEditHeader().exists()).toBe(true);
+ });
+
it('does not render skeleton loader', () => {
expect(findSkeletonLoader().exists()).toBe(false);
});
@@ -102,6 +113,10 @@ describe('StaticSiteEditor', () => {
expect(findEditArea().props('value')).toBe(content);
});
+ it('passes page title to edit header', () => {
+ expect(findEditHeader().props('title')).toBe(title);
+ });
+
it('renders toolbar', () => {
expect(findPublishToolbar().exists()).toBe(true);
});
diff --git a/spec/frontend/static_site_editor/mock_data.js b/spec/frontend/static_site_editor/mock_data.js
index 1993636ab12..345ae0ce6f6 100644
--- a/spec/frontend/static_site_editor/mock_data.js
+++ b/spec/frontend/static_site_editor/mock_data.js
@@ -11,11 +11,11 @@ twitter_image: '/images/tweets/handbook-gitlab.png'
- TOC
{:toc .hidden-md .hidden-lg}
`;
-
export const sourceContentTitle = 'Handbook';
export const username = 'gitlabuser';
export const projectId = '123456';
+export const returnUrl = 'https://www.gitlab.com';
export const sourcePath = 'foobar.md.html';
export const savedContentMeta = {
diff --git a/spec/lib/container_registry/client_spec.rb b/spec/lib/container_registry/client_spec.rb
index 5d2334a6d8f..0aad6568793 100644
--- a/spec/lib/container_registry/client_spec.rb
+++ b/spec/lib/container_registry/client_spec.rb
@@ -6,6 +6,21 @@ describe ContainerRegistry::Client do
let(:token) { '12345' }
let(:options) { { token: token } }
let(:client) { described_class.new("http://container-registry", options) }
+ let(:push_blob_headers) do
+ {
+ 'Accept' => 'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json',
+ 'Authorization' => "bearer #{token}",
+ 'Content-Type' => 'application/octet-stream',
+ 'User-Agent' => "GitLab/#{Gitlab::VERSION}"
+ }
+ end
+ let(:headers_with_accept_types) do
+ {
+ 'Accept' => 'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json',
+ 'Authorization' => "bearer #{token}",
+ 'User-Agent' => "GitLab/#{Gitlab::VERSION}"
+ }
+ end
shared_examples '#repository_manifest' do |manifest_type|
let(:manifest) do
@@ -25,14 +40,15 @@ describe ContainerRegistry::Client do
"size" => 2828661
}
]
- }
+ }
end
it 'GET /v2/:name/manifests/mytag' do
stub_request(:get, "http://container-registry/v2/group/test/manifests/mytag")
.with(headers: {
- 'Accept' => described_class::ACCEPTED_TYPES.join(', '),
- 'Authorization' => "bearer #{token}"
+ 'Accept' => 'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json',
+ 'Authorization' => "bearer #{token}",
+ 'User-Agent' => "GitLab/#{Gitlab::VERSION}"
})
.to_return(status: 200, body: manifest.to_json, headers: { content_type: manifest_type })
@@ -44,12 +60,23 @@ describe ContainerRegistry::Client do
it_behaves_like '#repository_manifest', described_class::OCI_MANIFEST_V1_TYPE
describe '#blob' do
+ let(:blob_headers) do
+ {
+ 'Accept' => 'application/octet-stream',
+ 'Authorization' => "bearer #{token}",
+ 'User-Agent' => "GitLab/#{Gitlab::VERSION}"
+ }
+ end
+
+ let(:redirect_header) do
+ {
+ 'User-Agent' => "GitLab/#{Gitlab::VERSION}"
+ }
+ end
+
it 'GET /v2/:name/blobs/:digest' do
stub_request(:get, "http://container-registry/v2/group/test/blobs/sha256:0123456789012345")
- .with(headers: {
- 'Accept' => 'application/octet-stream',
- 'Authorization' => "bearer #{token}"
- })
+ .with(headers: blob_headers)
.to_return(status: 200, body: "Blob")
expect(client.blob('group/test', 'sha256:0123456789012345')).to eq('Blob')
@@ -57,15 +84,14 @@ describe ContainerRegistry::Client do
it 'follows 307 redirect for GET /v2/:name/blobs/:digest' do
stub_request(:get, "http://container-registry/v2/group/test/blobs/sha256:0123456789012345")
- .with(headers: {
- 'Accept' => 'application/octet-stream',
- 'Authorization' => "bearer #{token}"
- })
+ .with(headers: blob_headers)
.to_return(status: 307, body: "", headers: { Location: 'http://redirected' })
# We should probably use hash_excluding here, but that requires an update to WebMock:
# https://github.com/bblimke/webmock/blob/master/lib/webmock/matchers/hash_excluding_matcher.rb
stub_request(:get, "http://redirected/")
- .with { |request| !request.headers.include?('Authorization') }
+ .with(headers: redirect_header) do |request|
+ !request.headers.include?('Authorization')
+ end
.to_return(status: 200, body: "Successfully redirected")
response = client.blob('group/test', 'sha256:0123456789012345')
@@ -76,10 +102,11 @@ describe ContainerRegistry::Client do
def stub_upload(path, content, digest, status = 200)
stub_request(:post, "http://container-registry/v2/#{path}/blobs/uploads/")
+ .with(headers: headers_with_accept_types)
.to_return(status: status, body: "", headers: { 'location' => 'http://container-registry/next_upload?id=someid' })
stub_request(:put, "http://container-registry/next_upload?digest=#{digest}&id=someid")
- .with(body: content)
+ .with(body: content, headers: push_blob_headers)
.to_return(status: status, body: "", headers: {})
end
@@ -136,11 +163,20 @@ describe ContainerRegistry::Client do
end
describe '#put_tag' do
+ let(:manifest_headers) do
+ {
+ 'Accept' => 'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json',
+ 'Authorization' => "bearer #{token}",
+ 'Content-Type' => 'application/vnd.docker.distribution.manifest.v2+json',
+ 'User-Agent' => "GitLab/#{Gitlab::VERSION}"
+ }
+ end
+
subject { client.put_tag('path', 'tagA', { foo: :bar }) }
it 'uploads the manifest and returns the digest' do
stub_request(:put, "http://container-registry/v2/path/manifests/tagA")
- .with(body: "{\n \"foo\": \"bar\"\n}")
+ .with(body: "{\n \"foo\": \"bar\"\n}", headers: manifest_headers)
.to_return(status: 200, body: "", headers: { 'docker-content-digest' => 'sha256:123' })
expect(subject).to eq 'sha256:123'
@@ -153,6 +189,7 @@ describe ContainerRegistry::Client do
context 'when the tag exists' do
before do
stub_request(:delete, "http://container-registry/v2/group/test/tags/reference/a")
+ .with(headers: headers_with_accept_types)
.to_return(status: 200, body: "")
end
@@ -162,6 +199,7 @@ describe ContainerRegistry::Client do
context 'when the tag does not exist' do
before do
stub_request(:delete, "http://container-registry/v2/group/test/tags/reference/a")
+ .with(headers: headers_with_accept_types)
.to_return(status: 404, body: "")
end
@@ -171,6 +209,7 @@ describe ContainerRegistry::Client do
context 'when an error occurs' do
before do
stub_request(:delete, "http://container-registry/v2/group/test/tags/reference/a")
+ .with(headers: headers_with_accept_types)
.to_return(status: 500, body: "")
end
diff --git a/spec/lib/gitlab/static_site_editor/config_spec.rb b/spec/lib/gitlab/static_site_editor/config_spec.rb
index dea79fb0e92..8f61476722d 100644
--- a/spec/lib/gitlab/static_site_editor/config_spec.rb
+++ b/spec/lib/gitlab/static_site_editor/config_spec.rb
@@ -18,13 +18,44 @@ describe Gitlab::StaticSiteEditor::Config do
it 'returns data for the frontend component' do
is_expected.to eq(
branch: 'master',
- commit: repository.commit.id,
+ commit_id: repository.commit.id,
namespace: 'namespace',
path: 'README.md',
project: 'project',
project_id: project.id,
- return_url: 'http://example.com'
+ return_url: 'http://example.com',
+ is_supported_content: true
)
end
+
+ context 'when branch is not master' do
+ let(:ref) { 'my-branch' }
+
+ it { is_expected.to include(is_supported_content: false) }
+ end
+
+ context 'when file does not have a markdown extension' do
+ let(:file_path) { 'README.txt' }
+
+ it { is_expected.to include(is_supported_content: false) }
+ end
+
+ context 'when file does not have an extension' do
+ let(:file_path) { 'README' }
+
+ it { is_expected.to include(is_supported_content: false) }
+ end
+
+ context 'when file does not exist' do
+ let(:file_path) { 'UNKNOWN.md' }
+
+ it { is_expected.to include(is_supported_content: false) }
+ end
+
+ context 'when repository is empty' do
+ let(:project) { create(:project_empty_repo) }
+
+ it { is_expected.to include(is_supported_content: false) }
+ end
end
end
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index ee0f7545adc..864f6f77f39 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -280,6 +280,18 @@ describe API::Users, :do_not_mock_admin_mode do
expect(json_response.first['id']).to eq(user_with_2fa.id)
end
+ it "returns users without projects" do
+ user_without_projects = create(:user)
+ create(:project, namespace: user.namespace)
+ create(:project, namespace: admin.namespace)
+
+ get api('/users', admin), params: { without_projects: true }
+
+ expect(response).to match_response_schema('public_api/v4/user/admins')
+ expect(json_response.size).to eq(1)
+ expect(json_response.first['id']).to eq(user_without_projects.id)
+ end
+
it 'returns 400 when provided incorrect sort params' do
get api('/users', admin), params: { order_by: 'magic', sort: 'asc' }
diff --git a/spec/support/shared_examples/requests/response_status_shared_examples.rb b/spec/support/shared_examples/requests/response_status_shared_examples.rb
new file mode 100644
index 00000000000..6c450881efe
--- /dev/null
+++ b/spec/support/shared_examples/requests/response_status_shared_examples.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'returning response status' do |status|
+ it "returns #{status}" do
+ subject
+
+ expect(response).to have_gitlab_http_status(status)
+ end
+end
diff --git a/spec/uploaders/object_storage_spec.rb b/spec/uploaders/object_storage_spec.rb
index e844b0ad799..f42d581ece4 100644
--- a/spec/uploaders/object_storage_spec.rb
+++ b/spec/uploaders/object_storage_spec.rb
@@ -597,22 +597,6 @@ describe ObjectStorage do
end
context 'when local file is used' do
- context 'when valid file is used' do
- let(:uploaded_file) do
- fixture_file_upload('spec/fixtures/rails_sample.jpg', 'image/jpg')
- end
-
- it "properly caches the file" do
- subject
-
- expect(uploader).to be_exists
- expect(uploader.path).to start_with(uploader_class.root)
- expect(uploader.filename).to eq('rails_sample.jpg')
- end
- end
- end
-
- context 'when local file is used' do
let(:temp_file) { Tempfile.new("test") }
before do
@@ -627,6 +611,14 @@ describe ObjectStorage do
context 'when valid file is specified' do
let(:uploaded_file) { temp_file }
+ it 'properly caches the file' do
+ subject
+
+ expect(uploader).to be_exists
+ expect(uploader.path).to start_with(uploader_class.root)
+ expect(uploader.filename).to eq(File.basename(uploaded_file.path))
+ end
+
context 'when object storage and direct upload is specified' do
before do
stub_uploads_object_storage(uploader_class, enabled: true, direct_upload: true)