Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.rubocop.yml6
-rw-r--r--.rubocop_todo.yml11
-rw-r--r--app/assets/javascripts/diffs/components/diff_content.vue7
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue8
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js8
-rw-r--r--app/assets/javascripts/vue_shared/components/diff_viewer/viewers/empty_file.vue3
-rw-r--r--app/helpers/version_check_helper.rb3
-rw-r--r--app/serializers/diff_file_entity.rb1
-rw-r--r--changelogs/unreleased/47052-merge-button-does-not-appear-after-rebase-ing.yml5
-rw-r--r--changelogs/unreleased/54786-mr-empty-file-display.yml5
-rw-r--r--changelogs/unreleased/55402-broken-master-karma-test-failing-in-spec-javascripts-boards-components-issue_due_date_spec-js.yml5
-rw-r--r--doc/administration/container_registry.md46
-rw-r--r--doc/ci/yaml/README.md100
-rw-r--r--doc/user/project/pages/getting_started_part_three.md27
-rw-r--r--doc/user/project/pages/index.md2
-rw-r--r--doc/user/project/pages/lets_encrypt_for_gitlab_pages.md158
-rw-r--r--lib/gitlab/diff/file.rb4
-rw-r--r--lib/version_check.rb7
-rw-r--r--locale/gitlab.pot3
-rw-r--r--rubocop/cop/inject_enterprise_edition_module.rb47
-rw-r--r--rubocop/rubocop.rb1
-rw-r--r--scripts/prepare_build.sh24
-rw-r--r--spec/features/help_pages_spec.rb18
-rw-r--r--spec/helpers/version_check_helper_spec.rb12
-rw-r--r--spec/javascripts/boards/components/issue_due_date_spec.js7
-rw-r--r--spec/javascripts/diffs/components/diff_content_spec.js39
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_rebase_spec.js2
-rw-r--r--spec/javascripts/vue_mr_widget/stores/get_state_key_spec.js2
-rw-r--r--spec/javascripts/vue_mr_widget/stores/mr_widget_store_spec.js25
-rw-r--r--spec/lib/gitlab/diff/file_spec.rb89
-rw-r--r--spec/rubocop/cop/inject_enterprise_edition_module_spec.rb133
-rw-r--r--spec/spec_helper.rb6
-rw-r--r--spec/support/carrierwave.rb2
-rw-r--r--spec/support/db_cleaner.rb6
-rw-r--r--spec/support/setup_builds_storage.rb2
-rw-r--r--spec/support/shared_examples/serializers/diff_file_entity_examples.rb2
38 files changed, 702 insertions, 128 deletions
diff --git a/.rubocop.yml b/.rubocop.yml
index 741403af009..004449210e5 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -174,3 +174,9 @@ GitlabSecurity/PublicSend:
- 'ee/db/**/*'
- 'ee/lib/**/*.rake'
- 'ee/spec/**/*'
+
+Cop/InjectEnterpriseEditionModule:
+ Enabled: true
+ Exclude:
+ - 'spec/**/*'
+ - 'ee/spec/**/*'
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 3ab76965287..847a0f74aa2 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -149,17 +149,6 @@ RSpec/ExpectChange:
RSpec/ExpectInHook:
Enabled: false
-# Offense count: 7
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: implicit, each, example
-RSpec/HookArgument:
- Exclude:
- - 'spec/spec_helper.rb'
- - 'spec/support/carrierwave.rb'
- - 'spec/support/db_cleaner.rb'
- - 'spec/support/gitaly.rb'
- - 'spec/support/setup_builds_storage.rb'
-
# Offense count: 19
# Configuration parameters: EnforcedStyle.
# SupportedStyles: it_behaves_like, it_should_behave_like
diff --git a/app/assets/javascripts/diffs/components/diff_content.vue b/app/assets/javascripts/diffs/components/diff_content.vue
index ac963f2971e..42d09e44768 100644
--- a/app/assets/javascripts/diffs/components/diff_content.vue
+++ b/app/assets/javascripts/diffs/components/diff_content.vue
@@ -1,6 +1,7 @@
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue';
+import EmptyFileViewer from '~/vue_shared/components/diff_viewer/viewers/empty_file.vue';
import InlineDiffView from './inline_diff_view.vue';
import ParallelDiffView from './parallel_diff_view.vue';
import NoteForm from '../../notes/components/note_form.vue';
@@ -17,6 +18,7 @@ export default {
NoteForm,
DiffDiscussions,
ImageDiffOverlay,
+ EmptyFileViewer,
},
props: {
diffFile: {
@@ -75,14 +77,15 @@ export default {
<div class="diff-content">
<div class="diff-viewer">
<template v-if="isTextFile">
+ <empty-file-viewer v-if="diffFile.empty" />
<inline-diff-view
- v-if="isInlineView"
+ v-else-if="isInlineView"
:diff-file="diffFile"
:diff-lines="diffFile.highlighted_diff_lines || []"
:help-page-path="helpPagePath"
/>
<parallel-diff-view
- v-if="isParallelView"
+ v-else-if="isParallelView"
:diff-file="diffFile"
:diff-lines="diffFile.parallel_diff_lines || []"
:help-page-path="helpPagePath"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
index adfbcd18588..0bcccc50eb2 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
@@ -72,7 +72,7 @@ export default {
Flash('Something went wrong. Please try again.');
}
- eventHub.$emit('MRWidgetUpdateRequested');
+ eventHub.$emit('MRWidgetRebaseSuccess');
stopPolling();
}
})
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index 3c3e3efcc36..d8a75388e84 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -155,13 +155,13 @@ export default {
};
return new MRWidgetService(endpoints);
},
- checkStatus(cb) {
+ checkStatus(cb, isRebased) {
return this.service
.checkStatus()
.then(res => res.data)
.then(data => {
this.handleNotification(data);
- this.mr.setData(data);
+ this.mr.setData(data, isRebased);
this.setFaviconHelper();
if (cb) {
@@ -263,6 +263,10 @@ export default {
this.checkStatus(cb);
});
+ eventHub.$on('MRWidgetRebaseSuccess', cb => {
+ this.checkStatus(cb, true);
+ });
+
// `params` should be an Array contains a Boolean, like `[true]`
// Passing parameter as Boolean didn't work.
eventHub.$on('SetBranchRemoveFlag', params => {
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js b/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js
index f7f0c1b6cb7..066a3b833d7 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js
@@ -19,7 +19,7 @@ export default function deviseState(data) {
return stateKey.unresolvedDiscussions;
} else if (this.isPipelineBlocked) {
return stateKey.pipelineBlocked;
- } else if (this.hasSHAChanged) {
+ } else if (this.isSHAMismatch) {
return stateKey.shaMismatch;
} else if (this.mergeWhenPipelineSucceeds) {
return this.mergeError ? stateKey.autoMergeFailed : stateKey.mergeWhenPipelineSucceeds;
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
index 5c9a7133a6e..c777bcca0fa 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
@@ -11,7 +11,11 @@ export default class MergeRequestStore {
this.setData(data);
}
- setData(data) {
+ setData(data, isRebased) {
+ if (isRebased) {
+ this.sha = data.diff_head_sha;
+ }
+
const currentUser = data.current_user;
const pipelineStatus = data.pipeline ? data.pipeline.details.status : null;
@@ -84,7 +88,7 @@ export default class MergeRequestStore {
this.canMerge = !!data.merge_path;
this.canCreateIssue = currentUser.can_create_issue || false;
this.canCancelAutomaticMerge = !!data.cancel_merge_when_pipeline_succeeds_path;
- this.hasSHAChanged = this.sha !== data.diff_head_sha;
+ this.isSHAMismatch = this.sha !== data.diff_head_sha;
this.canBeMerged = data.can_be_merged || false;
this.isMergeAllowed = data.mergeable || false;
this.mergeOngoing = data.merge_ongoing;
diff --git a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/empty_file.vue b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/empty_file.vue
new file mode 100644
index 00000000000..53210cbcc93
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/empty_file.vue
@@ -0,0 +1,3 @@
+<template>
+ <div class="nothing-here-block">{{ __('Empty file') }}</div>
+</template>
diff --git a/app/helpers/version_check_helper.rb b/app/helpers/version_check_helper.rb
index ab77b149072..5e519cf5c19 100644
--- a/app/helpers/version_check_helper.rb
+++ b/app/helpers/version_check_helper.rb
@@ -6,8 +6,7 @@ module VersionCheckHelper
return unless Gitlab::CurrentSettings.version_check_enabled
return if User.single_user&.requires_usage_stats_consent?
- image_url = VersionCheck.new.url
- image_tag image_url, class: 'js-version-status-badge'
+ image_tag VersionCheck.url, class: 'js-version-status-badge'
end
def link_to_version
diff --git a/app/serializers/diff_file_entity.rb b/app/serializers/diff_file_entity.rb
index f0881829efd..b0aaec3326d 100644
--- a/app/serializers/diff_file_entity.rb
+++ b/app/serializers/diff_file_entity.rb
@@ -5,6 +5,7 @@ class DiffFileEntity < DiffFileBaseEntity
include IconsHelper
expose :too_large?, as: :too_large
+ expose :empty?, as: :empty
expose :added_lines
expose :removed_lines
diff --git a/changelogs/unreleased/47052-merge-button-does-not-appear-after-rebase-ing.yml b/changelogs/unreleased/47052-merge-button-does-not-appear-after-rebase-ing.yml
new file mode 100644
index 00000000000..fd1e4605f2d
--- /dev/null
+++ b/changelogs/unreleased/47052-merge-button-does-not-appear-after-rebase-ing.yml
@@ -0,0 +1,5 @@
+---
+title: Allow merge after rebase without page refresh on FF repositories
+merge_request: 23572
+author:
+type: fixed
diff --git a/changelogs/unreleased/54786-mr-empty-file-display.yml b/changelogs/unreleased/54786-mr-empty-file-display.yml
new file mode 100644
index 00000000000..5adf5744755
--- /dev/null
+++ b/changelogs/unreleased/54786-mr-empty-file-display.yml
@@ -0,0 +1,5 @@
+---
+title: Display empty files properly on MR diffs
+merge_request: 23671
+author: Sean Nichols
+type: fixed
diff --git a/changelogs/unreleased/55402-broken-master-karma-test-failing-in-spec-javascripts-boards-components-issue_due_date_spec-js.yml b/changelogs/unreleased/55402-broken-master-karma-test-failing-in-spec-javascripts-boards-components-issue_due_date_spec-js.yml
new file mode 100644
index 00000000000..d2ff095ce55
--- /dev/null
+++ b/changelogs/unreleased/55402-broken-master-karma-test-failing-in-spec-javascripts-boards-components-issue_due_date_spec-js.yml
@@ -0,0 +1,5 @@
+---
+title: Fix due date test
+merge_request: 23845
+author:
+type: other
diff --git a/doc/administration/container_registry.md b/doc/administration/container_registry.md
index cfe7b0e05e3..5b7a61ef8ff 100644
--- a/doc/administration/container_registry.md
+++ b/doc/administration/container_registry.md
@@ -604,6 +604,52 @@ Registry out of the box, it is possible to make it work if you follow
[Docker's documentation][docker-insecure-self-signed]. You may find some additional
information in [issue 18239][ce-18239].
+## Troubleshooting
+
+When using AWS S3 with the GitLab registry, an error may occur when pushing
+large images. Look in the Registry log for the following error:
+
+```
+level=error msg="response completed with error" err.code=unknown err.detail="unexpected EOF" err.message="unknown error"
+```
+
+To resolve the error specify a `chunksize` value in the Registry configuration.
+Start with a value between `25000000` (25MB) and `50000000` (50MB).
+
+**For Omnibus installations**
+
+1. Edit `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ registry['storage'] = {
+ 's3' => {
+ 'accesskey' => 'AKIAKIAKI',
+ 'secretkey' => 'secret123',
+ 'bucket' => 'gitlab-registry-bucket-AKIAKIAKI',
+ 'chunksize' => 25000000
+ }
+ }
+ ```
+
+1. Save the file and [reconfigure GitLab][] for the changes to take effect.
+
+---
+
+**For installations from source**
+
+1. Edit `config/gitlab.yml`:
+
+ ```yaml
+ storage:
+ s3:
+ accesskey: 'AKIAKIAKI'
+ secretkey: 'secret123'
+ bucket: 'gitlab-registry-bucket-AKIAKIAKI'
+ chunksize: 25000000
+ ```
+
+1. Save the file and [restart GitLab][] for the changes to take effect.
+
[ce-18239]: https://gitlab.com/gitlab-org/gitlab-ce/issues/18239
[docker-insecure-self-signed]: https://docs.docker.com/registry/insecure/#use-self-signed-certificates
[reconfigure gitlab]: restart_gitlab.md#omnibus-gitlab-reconfigure
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 01f4b023234..acfcd05624d 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -402,7 +402,7 @@ job:
script: echo 'test'
```
-is translated to
+is translated to:
```yaml
job:
@@ -412,49 +412,64 @@ job:
## `only` and `except` (complex)
-> `refs` and `kubernetes` policies introduced in GitLab 10.0
->
-> `variables` policy introduced in 10.7
->
-> `changes` policy [introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/19232) in 11.4
+> - `refs` and `kubernetes` policies introduced in GitLab 10.0.
+> - `variables` policy introduced in GitLab 10.7.
+> - `changes` policy [introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/19232) in GitLab 11.4.
CAUTION: **Warning:**
This an _alpha_ feature, and it is subject to change at any time without
prior notice!
-Since GitLab 10.0 it is possible to define a more elaborate only/except job
-policy configuration.
+GitLab supports both simple and complex strategies, so it's possible to use an
+array and a hash configuration scheme.
-GitLab now supports both, simple and complex strategies, so it is possible to
-use an array and a hash configuration scheme.
+Four keys are available:
-Four keys are now available: `refs`, `kubernetes` and `variables` and `changes`.
+- `refs`
+- `variables`
+- `changes`
+- `kubernetes`
-### `refs` and `kubernetes`
+If you use multiple keys under `only` or `except`, they act as an AND. The logic is:
-Refs strategy equals to simplified only/except configuration, whereas
-kubernetes strategy accepts only `active` keyword.
+> (any of refs) AND (any of variables) AND (any of changes) AND (if kubernetes is active)
-### `only:variables`
+### `only:refs` and `except:refs`
-`variables` keyword is used to define variables expressions. In other words
-you can use predefined variables / project / group or
-environment-scoped variables to define an expression GitLab is going to
-evaluate in order to decide whether a job should be created or not.
+The `refs` strategy can take the same values as the
+[simplified only/except configuration](#only-and-except-simplified).
-See the example below. Job is going to be created only when pipeline has been
-scheduled or runs for a `master` branch, and only if kubernetes service is
-active in the project.
+In the example below, the `deploy` job is going to be created only when the
+pipeline has been [scheduled][schedules] or runs for the `master` branch:
```yaml
-job:
+deploy:
only:
refs:
- master
- schedules
+```
+
+### `only:kubernetes` and `except:kubernetes`
+
+The `kubernetes` strategy accepts only the `active` keyword.
+
+In the example below, the `deploy` job is going to be created only when the
+Kubernetes service is active in the project:
+
+```yaml
+deploy:
+ only:
kubernetes: active
```
+### `only:variables` and `except:variables`
+
+The `variables` keyword is used to define variables expressions. In other words,
+you can use predefined variables / project / group or
+environment-scoped variables to define an expression GitLab is going to
+evaluate in order to decide whether a job should be created or not.
+
Examples of using variables expressions:
```yaml
@@ -468,7 +483,7 @@ deploy:
- $STAGING
```
-Another use case is exluding jobs depending on a commit message _(added in 11.0)_:
+Another use case is excluding jobs depending on a commit message:
```yaml
end-to-end:
@@ -478,11 +493,11 @@ end-to-end:
- $CI_COMMIT_MESSAGE =~ /skip-end-to-end-tests/
```
-Learn more about variables expressions on [a separate page][variables-expressions].
+Learn more about [variables expressions](../variables/README.md#variables-expressions).
-### `only:changes`
+### `only:changes` and `except:changes`
-Using `changes` keyword with `only` or `except` makes it possible to define if
+Using the `changes` keyword with `only` or `except`, makes it possible to define if
a job should be created based on files modified by a git push event.
For example:
@@ -499,13 +514,13 @@ docker build:
```
In the scenario above, if you are pushing multiple commits to GitLab to an
-existing branch, GitLab creates and triggers `docker build` job, provided that
+existing branch, GitLab creates and triggers the `docker build` job, provided that
one of the commits contains changes to either:
- The `Dockerfile` file.
- Any of the files inside `docker/scripts/` directory.
-- Any of the files and subfolders inside `dockerfiles` directory.
-- Any of the files with `rb`, `py`, `sh` extensions inside `more_scripts` directory.
+- Any of the files and subdirectories inside the `dockerfiles` directory.
+- Any of the files with `rb`, `py`, `sh` extensions inside the `more_scripts` directory.
CAUTION: **Warning:**
There are some caveats when using this feature with new branches and tags. See
@@ -614,7 +629,7 @@ failure.
fails.
1. `always` - execute job regardless of the status of jobs from prior stages.
1. `manual` - execute job manually (added in GitLab 8.10). Read about
- [manual actions](#when-manual) below.
+ [manual actions](#whenmanual) below.
For example:
@@ -674,7 +689,7 @@ Manual actions are a special type of job that are not executed automatically,
they need to be explicitly started by a user. An example usage of manual actions
would be a deployment to a production environment. Manual actions can be started
from the pipeline, job, environment, and deployment views. Read more at the
-[environments documentation][env-manual].
+[environments documentation](../environments.md#manually-deploying-to-environments).
Manual actions can be either optional or blocking. Blocking manual actions will
block the execution of the pipeline at the stage this action is defined in. It's
@@ -1323,7 +1338,7 @@ The test reports are collected regardless of the job results (success or failure
You can use [`artifacts:expire_in`](#artifacts-expire_in) to set up an expiration
date for their artifacts.
-NOTE: **Note:**
+NOTE: **Note:**
If you also want the ability to browse the report output files, include the
[`artifacts:paths`](#artifactspaths) keyword.
@@ -1657,7 +1672,7 @@ rspec:
```
NOTE: **Note:**
-`include` requires the external YAML files to have the extensions `.yml` or `.yaml`.
+`include` requires the external YAML files to have the extensions `.yml` or `.yaml`.
The external file will not be included if the extension is missing.
You can define it either as a single string, or, in case you want to include
@@ -1709,7 +1724,7 @@ include:
The remote file must be publicly accessible through a simple GET request, as we don't support authentication schemas in the remote URL.
NOTE: **Note:**
- In order to include files from another repository inside your local network,
+ In order to include files from another repository inside your local network,
you may need to enable the **Allow requests to the local network from hooks and services** checkbox
located in the **Settings > Network > Outbound requests** section within the **Admin area**.
@@ -2195,19 +2210,14 @@ try to quote them, or change them to a different form (e.g., `/bin/true`).
## Examples
-Visit the [examples README][examples] to see a list of examples using GitLab
-CI with various languages.
+See a [list of examples](../examples/README.md "CI/CD examples") for using
+GitLab CI/CD with various languages.
-[env-manual]: ../environments.md#manually-deploying-to-environments
-[examples]: ../examples/README.md
[ce-6323]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/6323
-[environment]: ../environments.md
[ce-6669]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/6669
-[variables]: ../variables/README.md
[ce-7983]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7983
[ce-7447]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7447
[ce-12909]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/12909
-[schedules]: ../../user/project/pipelines/schedules.md
-[variables-expressions]: ../variables/README.md#variables-expressions
-[ee]: https://about.gitlab.com/gitlab-ee/
-[gitlab-versions]: https://about.gitlab.com/products/
+[environment]: ../environments.md "CI/CD environments"
+[schedules]: ../../user/project/pipelines/schedules.md "Pipelines schedules"
+[variables]: ../variables/README.md "CI/CD variables"
diff --git a/doc/user/project/pages/getting_started_part_three.md b/doc/user/project/pages/getting_started_part_three.md
index 247e8d2a6a0..cea9628966d 100644
--- a/doc/user/project/pages/getting_started_part_three.md
+++ b/doc/user/project/pages/getting_started_part_three.md
@@ -234,26 +234,25 @@ reiterating the importance of HTTPS.
## Issuing Certificates
-GitLab Pages accepts [PEM](https://support.quovadisglobal.com/kb/a37/what-is-pem-format.aspx) certificates issued by
-[Certificate Authorities (CA)](https://en.wikipedia.org/wiki/Certificate_authority)
-and self-signed certificates. Of course,
-[you'd rather issue a certificate than generate a self-signed](https://en.wikipedia.org/wiki/Self-signed_certificate),
-for security reasons and for having browsers trusting your
-site's certificate.
-
-There are several different kinds of certificates, each one
-with certain security level. A static personal website will
+GitLab Pages accepts certificates provided in the [PEM](https://support.quovadisglobal.com/kb/a37/what-is-pem-format.aspx) format, issued by
+[Certificate Authorities (CAs)](https://en.wikipedia.org/wiki/Certificate_authority) or as
+[self-signed certificates](https://en.wikipedia.org/wiki/Self-signed_certificate). Note that [self-signed certificates are typically not used](https://securingtomorrow.mcafee.com/other-blogs/mcafee-labs/self-signed-certificates-secure-so-why-ban/)
+for public websites for security reasons and to ensure that browsers trust your site's certificate.
+
+There are various kinds of certificates, each one
+with a certain security level. A static personal website will
not require the same security level as an online banking web app,
-for instance. There are a couple Certificate Authorities that
+for instance.
+
+There are some certificate authorities that
offer free certificates, aiming to make the internet more secure
to everyone. The most popular is [Let's Encrypt](https://letsencrypt.org/),
which issues certificates trusted by most of browsers, it's open
-source, and free to use. Please read through this tutorial to
-understand [how to secure your GitLab Pages website with Let's Encrypt](https://about.gitlab.com/2016/04/11/tutorial-securing-your-gitlab-pages-with-tls-and-letsencrypt/).
+source, and free to use. See our tutorial on [how to secure your GitLab Pages website with Let's Encrypt](lets_encrypt_for_gitlab_pages.md).
-With the same popularity, there are [certificates issued by CloudFlare](https://www.cloudflare.com/ssl/),
+Similarly popular are [certificates issued by CloudFlare](https://www.cloudflare.com/ssl/),
which also offers a [free CDN service](https://blog.cloudflare.com/cloudflares-free-cdn-and-you/).
-Their certs are valid up to 15 years. Read through the tutorial on
+Their certs are valid up to 15 years. See the tutorial on
[how to add a CloudFlare Certificate to your GitLab Pages website](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/).
### Adding certificates to your project
diff --git a/doc/user/project/pages/index.md b/doc/user/project/pages/index.md
index 7de9ae0caea..ce4fccdaff3 100644
--- a/doc/user/project/pages/index.md
+++ b/doc/user/project/pages/index.md
@@ -170,7 +170,7 @@ optionally secure it with SSL/TLS certificates. You can read the following
tutorials to learn how to use these third-party certificates with GitLab Pages:
- [CloudFlare](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/)
-- [Let's Encrypt](https://about.gitlab.com/2016/04/11/tutorial-securing-your-gitlab-pages-with-tls-and-letsencrypt/) (mind that although this article is out-of-date, it can still be useful to guide you through the basic steps)
+- [Let's Encrypt](lets_encrypt_for_gitlab_pages.md)
## Advanced use
diff --git a/doc/user/project/pages/lets_encrypt_for_gitlab_pages.md b/doc/user/project/pages/lets_encrypt_for_gitlab_pages.md
new file mode 100644
index 00000000000..f639188684b
--- /dev/null
+++ b/doc/user/project/pages/lets_encrypt_for_gitlab_pages.md
@@ -0,0 +1,158 @@
+---
+description: "How to secure GitLab Pages websites with Let's Encrypt."
+---
+
+# Let's Encrypt for GitLab Pages
+
+If you have a GitLab Pages website served under your own domain,
+you might want to secure it with a SSL/TSL certificate.
+
+[Let's Encrypt](https://letsencrypt.org) is a free, automated, and
+open source Certificate Authority.
+
+## Requirements
+
+To follow along with this tutorial, we assume you already have:
+
+- Created a [project](getting_started_part_two.md) in GitLab which
+ contains your website's source code.
+- Acquired a domain (`example.com`) and added a [DNS entry](getting_started_part_three.md#dns-records)
+ pointing it to your Pages website.
+- [Added your domain to your Pages project](getting_started_part_three.md#add-your-custom-domain-to-gitlab-pages-settings)
+ and verified your ownership.
+- Cloned your project into your computer.
+- Your website up and running, served under HTTP protocol at `http://example.com`.
+
+## Obtaining a Let's Encrypt certificate
+
+Once you have the requirements addressed, follow the instructions
+below to learn how to obtain the certificate.
+
+NOTE: **Note:**
+The instructions below were tested on macOS Mojave. For other
+operating systems the steps might be slightly different. Follow the
+[CertBot instructions](https://certbot.eff.org/) according to your OS.
+
+1. On your computer, open a terminal and navigate to your repository's
+ root directory:
+
+ ```bash
+ cd path/to/dir
+ ```
+
+1. Install CertBot (the tool Let's Encrypt uses to issue certificates):
+
+ ```bash
+ brew install certbot
+ ```
+
+1. Request a certificate for your domain (`example.com`) and
+ provide an email account (`your@email.com`) to receive notifications:
+
+ ```bash
+ sudo certbot certonly -a manual -d example.com --email your@email.com
+ ```
+
+ Alternatively, you can register without adding an e-mail account,
+ but you won't be notified about the certificate expiration's date:
+
+ ```bash
+ sudo certbot certonly -a manual -d example.com --register-unsafely-without-email
+ ```
+
+ TIP: **Tip:**
+ Read through CertBot's documentation on their
+ [command line options](https://certbot.eff.org/docs/using.html#certbot-command-line-options).
+
+1. You'll be prompted with a message to agree with their terms.
+ Press `A` to agree and `Y` to let they log your IP.
+
+ CertBot will then prompt you with the following message:
+
+ ```bash
+ Create a file containing just this data:
+
+ Rxnv6WKo95hsuLVX3osmT6LgmzsJKSaK9htlPToohOP.HUGNKk82jlsmOOfphlt8Jy69iuglsn095nxOMH9j3Yb
+
+ And make it available on your web server at this URL:
+
+ http://example.com/.well-known/acme-challenge/Rxnv6WKo95hsuLVX3osmT6LgmzsJKSaK9htlPToohOP
+
+ Press Enter to Continue
+ ```
+
+1. **Do not press Enter yet.** Let's Encrypt will need to verify your
+ domain ownership before issuing the certificate. To do so, create 3
+ consecutive directories under your website's root:
+ `/.well-known/acme-challenge/Rxnv6WKo95hsuLVX3osmT6LgmzsJKSaK9htlPToohOP/`
+ and add to the last folder an `index.html` file containing the content
+ referred on the previous prompt message:
+
+ ```bash
+ Rxnv6WKo95hsuLVX3osmT6LgmzsJKSaK9htlPToohOP.HUGNKk82jlsmOOfphlt8Jy69iuglsn095nxOMH9j3Yb
+ ```
+
+ Note that this file needs to be accessed under
+ `http://example.com/.well-known/acme-challenge/Rxnv6WKo95hsuLVX3osmT6LgmzsJKSaK9htlPToohOP`
+ to allow Let's Encrypt to verify the ownership of your domain,
+ therefore, it needs to be part of the website content under the
+ repo's [`public`](index.md#how-it-works) folder.
+
+1. Add, commit, and push the file into your repo in GitLab. Once the pipeline
+ passes, press **Enter** on your terminal to continue issuing your
+ certificate. CertBot will then prompt you with the following message:
+
+ ```bash
+ Waiting for verification...
+ Cleaning up challenges
+
+ IMPORTANT NOTES:
+ - Congratulations! Your certificate and chain have been saved at:
+ /etc/letsencrypt/live/example.com/fullchain.pem
+ Your key file has been saved at:
+ /etc/letsencrypt/live/example.com/privkey.pem
+ Your cert will expire on 2019-03-12. To obtain a new or tweaked
+ version of this certificate in the future, simply run certbot
+ again. To non-interactively renew *all* of your certificates, run
+ "certbot renew"
+ - If you like Certbot, please consider supporting our work by:
+
+ Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
+ Donating to EFF: https://eff.org/donate-le
+ ```
+
+## Add your certificate to GitLab Pages
+
+Now that your certificate has been issued, let's add it to your Pages site:
+
+1. Back at GitLab, navigate to your project's **Settings > Pages**,
+ find your domain and click **Details** and **Edit** to add your certificate.
+1. From your terminal, copy and paste the certificate into the first field
+ **Certificate (PEM)**:
+
+ ```bash
+ sudo cat /etc/letsencrypt/live/example.com/fullchain.pem | pbcopy
+ ```
+
+1. Copy and paste the public key into the second field **Key (PEM)**:
+
+ ```bash
+ sudo cat /etc/letsencrypt/live/example.com/privkey.pem | pbcopy
+ ```
+
+1. Click **Save changes** to apply them to your website.
+1. Wait a few minutes for DNS propagation.
+1. Visit your website at `https://example.com`.
+
+To force `https` connections on your site, navigate to your
+project's **Settings > Pages** and check **Force domains with SSL
+certificates to use HTTPS**.
+
+## Renewal
+
+Let's Encrypt certificates expire every 90 days and you'll have to
+renew them periodically. To renew all your certificates at once, run:
+
+```bash
+sudo certbot renew
+```
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
index a85c5386d98..b5fc8d364c8 100644
--- a/lib/gitlab/diff/file.rb
+++ b/lib/gitlab/diff/file.rb
@@ -255,6 +255,10 @@ module Gitlab
end
# rubocop: enable CodeReuse/ActiveRecord
+ def empty?
+ valid_blobs.map(&:empty?).all?
+ end
+
def raw_binary?
try_blobs(:raw_binary?)
end
diff --git a/lib/version_check.rb b/lib/version_check.rb
index ccf7bb493db..c9f102f6b19 100644
--- a/lib/version_check.rb
+++ b/lib/version_check.rb
@@ -5,16 +5,17 @@ require "base64"
# This class is used to build image URL to
# check if it is a new version for update
class VersionCheck
- def data
+ def self.data
{ version: Gitlab::VERSION }
end
- def url
+ def self.url
encoded_data = Base64.urlsafe_encode64(data.to_json)
+
"#{host}?gitlab_info=#{encoded_data}"
end
- def host
+ def self.host
'https://version.gitlab.com/check.svg'
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index e47f1433b8a..0584d2006f7 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2668,6 +2668,9 @@ msgstr ""
msgid "Embed"
msgstr ""
+msgid "Empty file"
+msgstr ""
+
msgid "Enable"
msgstr ""
diff --git a/rubocop/cop/inject_enterprise_edition_module.rb b/rubocop/cop/inject_enterprise_edition_module.rb
new file mode 100644
index 00000000000..c8b8aca51ab
--- /dev/null
+++ b/rubocop/cop/inject_enterprise_edition_module.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+module RuboCop
+ module Cop
+ # Cop that blacklists the injecting of EE specific modules anywhere but on
+ # the last line of a file. Injecting a module in the middle of a file will
+ # cause merge conflicts, while placing it on the last line will not.
+ class InjectEnterpriseEditionModule < RuboCop::Cop::Cop
+ MSG = 'Injecting EE modules must be done on the last line of this file' \
+ ', outside of any class or module definitions'
+
+ METHODS = Set.new(%i[include extend prepend]).freeze
+
+ def_node_matcher :ee_const?, <<~PATTERN
+ (const (const _ :EE) _)
+ PATTERN
+
+ def on_send(node)
+ return unless METHODS.include?(node.children[1])
+ return unless ee_const?(node.children[2])
+
+ line = node.location.line
+ buffer = node.location.expression.source_buffer
+ last_line = buffer.last_line
+
+ # Parser treats the final newline (if present) as a separate line,
+ # meaning that a simple `line < last_line` would yield true even though
+ # the expression is the last line _of code_.
+ last_line -= 1 if buffer.source.end_with?("\n")
+
+ add_offense(node) if line < last_line
+ end
+
+ # Automatically correcting these offenses is not always possible, as
+ # sometimes code needs to be refactored to make this work. As such, we
+ # only allow developers to easily blacklist existing offenses.
+ def autocorrect(node)
+ lambda do |corrector|
+ corrector.insert_after(
+ node.source_range,
+ " # rubocop: disable #{cop_name}"
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb
index 4489159f422..3e33419eb2e 100644
--- a/rubocop/rubocop.rb
+++ b/rubocop/rubocop.rb
@@ -41,3 +41,4 @@ require_relative 'cop/code_reuse/presenter'
require_relative 'cop/code_reuse/serializer'
require_relative 'cop/code_reuse/active_record'
require_relative 'cop/group_public_or_visible_to_user'
+require_relative 'cop/inject_enterprise_edition_module'
diff --git a/scripts/prepare_build.sh b/scripts/prepare_build.sh
index 2e8fec166a3..d85c53090a4 100644
--- a/scripts/prepare_build.sh
+++ b/scripts/prepare_build.sh
@@ -5,7 +5,7 @@ export USE_BUNDLE_INSTALL=${USE_BUNDLE_INSTALL:-true}
export BUNDLE_INSTALL_FLAGS="--without=production --jobs=$(nproc) --path=vendor --retry=3 --quiet"
if [ "$USE_BUNDLE_INSTALL" != "false" ]; then
- bundle install --clean $BUNDLE_INSTALL_FLAGS && bundle check
+ bundle install --clean $BUNDLE_INSTALL_FLAGS && bundle check
fi
# Only install knapsack after bundle install! Otherwise oddly some native
@@ -22,18 +22,30 @@ export GITLAB_DATABASE=$(echo $CI_JOB_NAME | cut -f1 -d' ' | cut -f2 -d-)
# This would make the default database postgresql, and we could also use
# pg to mean postgresql.
if [ "$GITLAB_DATABASE" != 'mysql' ]; then
- export GITLAB_DATABASE='postgresql'
+ export GITLAB_DATABASE='postgresql'
fi
cp config/database.yml.$GITLAB_DATABASE config/database.yml
+if [ -f config/database_geo.yml.$GITLAB_DATABASE ]; then
+ cp config/database_geo.yml.$GITLAB_DATABASE config/database_geo.yml
+fi
+
# Set user to a non-superuser to ensure we test permissions
sed -i 's/username: root/username: gitlab/g' config/database.yml
if [ "$GITLAB_DATABASE" = 'postgresql' ]; then
- sed -i 's/localhost/postgres/g' config/database.yml
+ sed -i 's/localhost/postgres/g' config/database.yml
+
+ if [ -f config/database_geo.yml ]; then
+ sed -i 's/localhost/postgres/g' config/database_geo.yml
+ fi
else # Assume it's mysql
- sed -i 's/localhost/mysql/g' config/database.yml
+ sed -i 's/localhost/mysql/g' config/database.yml
+
+ if [ -f config/database_geo.yml ]; then
+ sed -i 's/localhost/mysql/g' config/database_geo.yml
+ fi
fi
cp config/resque.yml.example config/resque.yml
@@ -49,7 +61,7 @@ cp config/redis.shared_state.yml.example config/redis.shared_state.yml
sed -i 's/localhost/redis/g' config/redis.shared_state.yml
if [ "$SETUP_DB" != "false" ]; then
- setup_db
+ setup_db
elif getent hosts postgres || getent hosts mysql; then
- setup_db_user_only
+ setup_db_user_only
fi
diff --git a/spec/features/help_pages_spec.rb b/spec/features/help_pages_spec.rb
index c29dfb01381..e24b1f4349d 100644
--- a/spec/features/help_pages_spec.rb
+++ b/spec/features/help_pages_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe 'Help Pages' do
@@ -52,23 +54,21 @@ describe 'Help Pages' do
end
end
- context 'in a production environment with version check enabled', :js do
+ context 'in a production environment with version check enabled' do
before do
- allow(Rails.env).to receive(:production?) { true }
stub_application_setting(version_check_enabled: true)
- allow_any_instance_of(VersionCheck).to receive(:url) { '/version-check-url' }
+
+ allow(Rails.env).to receive(:production?).and_return(true)
+ allow(VersionCheck).to receive(:url).and_return('/version-check-url')
sign_in(create(:user))
visit help_path
end
it 'has a version check image' do
- expect(find('.js-version-status-badge', visible: false)['src']).to end_with('/version-check-url')
- end
-
- it 'hides the version check image if the image request fails' do
- # We use '--load-images=yes' with poltergeist so the image fails to load
- expect(page).to have_selector('.js-version-status-badge', visible: false)
+ # Check `data-src` due to lazy image loading
+ expect(find('.js-version-status-badge', visible: false)['data-src'])
+ .to end_with('/version-check-url')
end
end
diff --git a/spec/helpers/version_check_helper_spec.rb b/spec/helpers/version_check_helper_spec.rb
index 9d4e34abef5..bfec7ad4bba 100644
--- a/spec/helpers/version_check_helper_spec.rb
+++ b/spec/helpers/version_check_helper_spec.rb
@@ -13,21 +13,21 @@ describe VersionCheckHelper do
before do
allow(Rails.env).to receive(:production?) { true }
allow(Gitlab::CurrentSettings.current_application_settings).to receive(:version_check_enabled) { true }
- allow_any_instance_of(VersionCheck).to receive(:url) { 'https://version.host.com/check.svg?gitlab_info=xxx' }
-
- @image_tag = helper.version_status_badge
+ allow(VersionCheck).to receive(:url) { 'https://version.host.com/check.svg?gitlab_info=xxx' }
end
it 'should return an image tag' do
- expect(@image_tag).to match(/^<img/)
+ expect(helper.version_status_badge).to start_with('<img')
end
it 'should have a js prefixed css class' do
- expect(@image_tag).to match(/class="js-version-status-badge lazy"/)
+ expect(helper.version_status_badge)
+ .to match(/class="js-version-status-badge lazy"/)
end
it 'should have a VersionCheck url as the src' do
- expect(@image_tag).to match(%r{src="https://version\.host\.com/check\.svg\?gitlab_info=xxx"})
+ expect(helper.version_status_badge)
+ .to include(%{src="https://version.host.com/check.svg?gitlab_info=xxx"})
end
end
end
diff --git a/spec/javascripts/boards/components/issue_due_date_spec.js b/spec/javascripts/boards/components/issue_due_date_spec.js
index 9e49330c052..054cf8c5b7d 100644
--- a/spec/javascripts/boards/components/issue_due_date_spec.js
+++ b/spec/javascripts/boards/components/issue_due_date_spec.js
@@ -49,10 +49,11 @@ describe('Issue Due Date component', () => {
it('should render month and day for other dates', () => {
date.setDate(date.getDate() + 17);
vm = createComponent(date);
+ const today = new Date();
+ const isDueInCurrentYear = today.getFullYear() === date.getFullYear();
+ const format = isDueInCurrentYear ? 'mmm d' : 'mmm d, yyyy';
- expect(vm.$el.querySelector('time').textContent.trim()).toEqual(
- dateFormat(date, 'mmm d', true),
- );
+ expect(vm.$el.querySelector('time').textContent.trim()).toEqual(dateFormat(date, format, true));
});
it('should contain the correct `.text-danger` css class for overdue issue', () => {
diff --git a/spec/javascripts/diffs/components/diff_content_spec.js b/spec/javascripts/diffs/components/diff_content_spec.js
index d688560a260..9e158327a77 100644
--- a/spec/javascripts/diffs/components/diff_content_spec.js
+++ b/spec/javascripts/diffs/components/diff_content_spec.js
@@ -50,6 +50,45 @@ describe('DiffContent', () => {
});
});
+ describe('empty files', () => {
+ beforeEach(() => {
+ vm.diffFile.empty = true;
+ vm.diffFile.highlighted_diff_lines = [];
+ vm.diffFile.parallel_diff_lines = [];
+ });
+
+ it('should render a message', done => {
+ vm.$nextTick(() => {
+ const block = vm.$el.querySelector('.diff-viewer .nothing-here-block');
+
+ expect(block).not.toBe(null);
+ expect(block.textContent.trim()).toContain('Empty file');
+
+ done();
+ });
+ });
+
+ it('should not render multiple messages', done => {
+ vm.diffFile.mode_changed = true;
+ vm.diffFile.b_mode = '100755';
+ vm.diffFile.viewer.name = 'mode_changed';
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelectorAll('.nothing-here-block').length).toBe(1);
+
+ done();
+ });
+ });
+
+ it('should not render diff table', done => {
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('table')).toBe(null);
+
+ done();
+ });
+ });
+ });
+
describe('Non-Text diffs', () => {
beforeEach(() => {
vm.diffFile.viewer.name = 'image';
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_rebase_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_rebase_spec.js
index 300133dc602..212519743aa 100644
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_rebase_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/mr_widget_rebase_spec.js
@@ -114,7 +114,7 @@ describe('Merge request widget rebase component', () => {
// Wait for the eventHub to be called
.then(vm.$nextTick())
.then(() => {
- expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
+ expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetRebaseSuccess');
})
.then(done)
.catch(done.fail);
diff --git a/spec/javascripts/vue_mr_widget/stores/get_state_key_spec.js b/spec/javascripts/vue_mr_widget/stores/get_state_key_spec.js
index 9d34bdd1084..61ef26cd080 100644
--- a/spec/javascripts/vue_mr_widget/stores/get_state_key_spec.js
+++ b/spec/javascripts/vue_mr_widget/stores/get_state_key_spec.js
@@ -35,7 +35,7 @@ describe('getStateKey', () => {
expect(bound()).toEqual('mergeWhenPipelineSucceeds');
- context.hasSHAChanged = true;
+ context.isSHAMismatch = true;
expect(bound()).toEqual('shaMismatch');
diff --git a/spec/javascripts/vue_mr_widget/stores/mr_widget_store_spec.js b/spec/javascripts/vue_mr_widget/stores/mr_widget_store_spec.js
index f5079147f60..c226704694c 100644
--- a/spec/javascripts/vue_mr_widget/stores/mr_widget_store_spec.js
+++ b/spec/javascripts/vue_mr_widget/stores/mr_widget_store_spec.js
@@ -3,23 +3,30 @@ import { stateKey } from '~/vue_merge_request_widget/stores/state_maps';
import mockData from '../mock_data';
describe('MergeRequestStore', () => {
- describe('setData', () => {
- let store;
+ let store;
- beforeEach(() => {
- store = new MergeRequestStore(mockData);
- });
+ beforeEach(() => {
+ store = new MergeRequestStore(mockData);
+ });
- it('should set hasSHAChanged when the diff SHA changes', () => {
+ describe('setData', () => {
+ it('should set isSHAMismatch when the diff SHA changes', () => {
store.setData({ ...mockData, diff_head_sha: 'a-different-string' });
- expect(store.hasSHAChanged).toBe(true);
+ expect(store.isSHAMismatch).toBe(true);
});
- it('should not set hasSHAChanged when other data changes', () => {
+ it('should not set isSHAMismatch when other data changes', () => {
store.setData({ ...mockData, work_in_progress: !mockData.work_in_progress });
- expect(store.hasSHAChanged).toBe(false);
+ expect(store.isSHAMismatch).toBe(false);
+ });
+
+ it('should update cached sha after rebasing', () => {
+ store.setData({ ...mockData, diff_head_sha: 'abc123' }, true);
+
+ expect(store.isSHAMismatch).toBe(false);
+ expect(store.sha).toBe('abc123');
});
describe('isPipelinePassing', () => {
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index 3417896e259..b15d22c634a 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -583,6 +583,12 @@ describe Gitlab::Diff::File do
end
end
+ describe '#empty?' do
+ it 'returns true' do
+ expect(diff_file.empty?).to be_truthy
+ end
+ end
+
describe '#different_type?' do
it 'returns false' do
expect(diff_file).not_to be_different_type
@@ -662,4 +668,87 @@ describe Gitlab::Diff::File do
end
end
end
+
+ describe '#empty?' do
+ let(:project) do
+ create(:project, :custom_repo, files: {})
+ end
+ let(:branch_name) { 'master' }
+
+ def create_file(file_name, content)
+ Files::CreateService.new(
+ project,
+ project.owner,
+ commit_message: 'Update',
+ start_branch: branch_name,
+ branch_name: branch_name,
+ file_path: file_name,
+ file_content: content
+ ).execute
+
+ project.commit(branch_name).diffs.diff_files.first
+ end
+
+ def update_file(file_name, content)
+ Files::UpdateService.new(
+ project,
+ project.owner,
+ commit_message: 'Update',
+ start_branch: branch_name,
+ branch_name: branch_name,
+ file_path: file_name,
+ file_content: content
+ ).execute
+
+ project.commit(branch_name).diffs.diff_files.first
+ end
+
+ def delete_file(file_name)
+ Files::DeleteService.new(
+ project,
+ project.owner,
+ commit_message: 'Update',
+ start_branch: branch_name,
+ branch_name: branch_name,
+ file_path: file_name
+ ).execute
+
+ project.commit(branch_name).diffs.diff_files.first
+ end
+
+ context 'when empty file is created' do
+ it 'returns true' do
+ diff_file = create_file('empty.md', '')
+
+ expect(diff_file.empty?).to be_truthy
+ end
+ end
+
+ context 'when empty file is deleted' do
+ it 'returns true' do
+ create_file('empty.md', '')
+ diff_file = delete_file('empty.md')
+
+ expect(diff_file.empty?).to be_truthy
+ end
+ end
+
+ context 'when file with content is truncated' do
+ it 'returns false' do
+ create_file('with-content.md', 'file content')
+ diff_file = update_file('with-content.md', '')
+
+ expect(diff_file.empty?).to be_falsey
+ end
+ end
+
+ context 'when empty file has content added' do
+ it 'returns false' do
+ create_file('empty.md', '')
+ diff_file = update_file('empty.md', 'new content')
+
+ expect(diff_file.empty?).to be_falsey
+ end
+ end
+ end
end
diff --git a/spec/rubocop/cop/inject_enterprise_edition_module_spec.rb b/spec/rubocop/cop/inject_enterprise_edition_module_spec.rb
new file mode 100644
index 00000000000..08ffc3c3a53
--- /dev/null
+++ b/spec/rubocop/cop/inject_enterprise_edition_module_spec.rb
@@ -0,0 +1,133 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require 'rubocop'
+require 'rubocop/rspec/support'
+require_relative '../../../rubocop/cop/inject_enterprise_edition_module'
+
+describe RuboCop::Cop::InjectEnterpriseEditionModule do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+
+ it 'flags the use of `prepend EE` in the middle of a file' do
+ expect_offense(<<~SOURCE)
+ class Foo
+ prepend EE::Foo
+ ^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
+ end
+ SOURCE
+ end
+
+ it 'flags the use of `prepend ::EE` in the middle of a file' do
+ expect_offense(<<~SOURCE)
+ class Foo
+ prepend ::EE::Foo
+ ^^^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
+ end
+ SOURCE
+ end
+
+ it 'flags the use of `include EE` in the middle of a file' do
+ expect_offense(<<~SOURCE)
+ class Foo
+ include EE::Foo
+ ^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
+ end
+ SOURCE
+ end
+
+ it 'flags the use of `include ::EE` in the middle of a file' do
+ expect_offense(<<~SOURCE)
+ class Foo
+ include ::EE::Foo
+ ^^^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
+ end
+ SOURCE
+ end
+
+ it 'flags the use of `extend EE` in the middle of a file' do
+ expect_offense(<<~SOURCE)
+ class Foo
+ extend EE::Foo
+ ^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
+ end
+ SOURCE
+ end
+
+ it 'flags the use of `extend ::EE` in the middle of a file' do
+ expect_offense(<<~SOURCE)
+ class Foo
+ extend ::EE::Foo
+ ^^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
+ end
+ SOURCE
+ end
+
+ it 'does not flag prepending of regular modules' do
+ expect_no_offenses(<<~SOURCE)
+ class Foo
+ prepend Foo
+ end
+ SOURCE
+ end
+
+ it 'does not flag including of regular modules' do
+ expect_no_offenses(<<~SOURCE)
+ class Foo
+ include Foo
+ end
+ SOURCE
+ end
+
+ it 'does not flag extending using regular modules' do
+ expect_no_offenses(<<~SOURCE)
+ class Foo
+ extend Foo
+ end
+ SOURCE
+ end
+
+ it 'does not flag the use of `prepend EE` on the last line' do
+ expect_no_offenses(<<~SOURCE)
+ class Foo
+ end
+
+ Foo.prepend(EE::Foo)
+ SOURCE
+ end
+
+ it 'does not flag the use of `include EE` on the last line' do
+ expect_no_offenses(<<~SOURCE)
+ class Foo
+ end
+
+ Foo.include(EE::Foo)
+ SOURCE
+ end
+
+ it 'does not flag the use of `extend EE` on the last line' do
+ expect_no_offenses(<<~SOURCE)
+ class Foo
+ end
+
+ Foo.extend(EE::Foo)
+ SOURCE
+ end
+
+ it 'autocorrects offenses by just disabling the Cop' do
+ source = <<~SOURCE
+ class Foo
+ prepend EE::Foo
+ include Bar
+ end
+ SOURCE
+
+ expect(autocorrect_source(source)).to eq(<<~SOURCE)
+ class Foo
+ prepend EE::Foo # rubocop: disable Cop/InjectEnterpriseEditionModule
+ include Bar
+ end
+ SOURCE
+ end
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index cd69160be10..fb3421b61d3 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -115,7 +115,7 @@ RSpec.configure do |config|
TestEnv.clean_test_path
end
- config.before(:example) do
+ config.before do
# Enable all features by default for testing
allow(Feature).to receive(:enabled?) { true }
@@ -136,11 +136,11 @@ RSpec.configure do |config|
RequestStore.clear!
end
- config.after(:example) do
+ config.after do
Fog.unmock! if Fog.mock?
end
- config.after(:example) do
+ config.after do
Gitlab::CurrentSettings.clear_in_memory_application_settings!
end
diff --git a/spec/support/carrierwave.rb b/spec/support/carrierwave.rb
index b4b016e408f..b376822d530 100644
--- a/spec/support/carrierwave.rb
+++ b/spec/support/carrierwave.rb
@@ -1,7 +1,7 @@
CarrierWave.root = File.expand_path('tmp/tests/public', Rails.root)
RSpec.configure do |config|
- config.after(:each) do
+ config.after do
FileUtils.rm_rf(CarrierWave.root)
end
end
diff --git a/spec/support/db_cleaner.rb b/spec/support/db_cleaner.rb
index 5edc5de2a09..34b9efaaecd 100644
--- a/spec/support/db_cleaner.rb
+++ b/spec/support/db_cleaner.rb
@@ -23,7 +23,7 @@ RSpec.configure do |config|
DatabaseCleaner.clean_with(:deletion, cache_tables: false)
end
- config.before(:each) do
+ config.before do
DatabaseCleaner.strategy = :transaction
end
@@ -39,11 +39,11 @@ RSpec.configure do |config|
DatabaseCleaner.strategy = :deletion, { cache_tables: false }
end
- config.before(:each) do
+ config.before do
DatabaseCleaner.start
end
- config.append_after(:each) do
+ config.append_after do
DatabaseCleaner.clean
end
end
diff --git a/spec/support/setup_builds_storage.rb b/spec/support/setup_builds_storage.rb
index 2e7c88bfc09..1d2a4856724 100644
--- a/spec/support/setup_builds_storage.rb
+++ b/spec/support/setup_builds_storage.rb
@@ -11,7 +11,7 @@ RSpec.configure do |config|
FileUtils.mkdir_p(builds_path)
end
- config.before(:each) do
+ config.before do
FileUtils.rm_rf(builds_path)
FileUtils.mkdir_p(builds_path)
end
diff --git a/spec/support/shared_examples/serializers/diff_file_entity_examples.rb b/spec/support/shared_examples/serializers/diff_file_entity_examples.rb
index b8065886c42..1770308f789 100644
--- a/spec/support/shared_examples/serializers/diff_file_entity_examples.rb
+++ b/spec/support/shared_examples/serializers/diff_file_entity_examples.rb
@@ -32,7 +32,7 @@ shared_examples 'diff file entity' do
it 'exposes correct attributes' do
expect(subject).to include(:too_large, :added_lines, :removed_lines,
:context_lines_path, :highlighted_diff_lines,
- :parallel_diff_lines)
+ :parallel_diff_lines, :empty)
end
it 'includes viewer' do