summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--app/assets/javascripts/diffs/components/app.vue2
-rw-r--r--app/models/ci/bridge.rb4
-rw-r--r--app/models/ci/pipeline.rb4
-rw-r--r--app/models/snippet.rb2
-rw-r--r--app/services/projects/update_repository_storage_service.rb47
-rw-r--r--app/workers/post_receive.rb5
-rw-r--r--changelogs/unreleased/207249-prevent-editing-weight-to-scroll-to-the-top.yml5
-rw-r--r--changelogs/unreleased/add-retiresjs-vars-to-dependency-scanning.yml5
-rw-r--r--changelogs/unreleased/add-trigger-include-artifact.yml5
-rw-r--r--changelogs/unreleased/allow-selecting-all-queues-with-sidekiq-cluster.yml5
-rw-r--r--changelogs/unreleased/allow-to-disable-defaults.yml5
-rw-r--r--changelogs/unreleased/fj-update-snippet-from-git-action.yml5
-rw-r--r--changelogs/unreleased/remove-cs-kubernetes-workaround.yml5
-rw-r--r--changelogs/unreleased/update_repo_storage_checksum.yml5
-rw-r--r--config/environments/development.rb10
-rw-r--r--doc/administration/monitoring/gitlab_self_monitoring_project/index.md7
-rw-r--r--doc/administration/operations/extra_sidekiq_processes.md24
-rw-r--r--doc/administration/troubleshooting/sidekiq.md20
-rw-r--r--doc/ci/yaml/README.md36
-rw-r--r--doc/development/profiling.md13
-rw-r--r--doc/development/sidekiq_debugging.md19
-rw-r--r--lib/gitlab/ci/artifact_file_reader.rb71
-rw-r--r--lib/gitlab/ci/config.rb14
-rw-r--r--lib/gitlab/ci/config/entry/bridge.rb7
-rw-r--r--lib/gitlab/ci/config/entry/include.rb2
-rw-r--r--lib/gitlab/ci/config/entry/inherit.rb30
-rw-r--r--lib/gitlab/ci/config/entry/job.rb7
-rw-r--r--lib/gitlab/ci/config/entry/processable.rb30
-rw-r--r--lib/gitlab/ci/config/entry/root.rb13
-rw-r--r--lib/gitlab/ci/config/entry/workflow.rb1
-rw-r--r--lib/gitlab/ci/config/external/context.rb5
-rw-r--r--lib/gitlab/ci/config/external/file/artifact.rb93
-rw-r--r--lib/gitlab/ci/config/external/file/local.rb3
-rw-r--r--lib/gitlab/ci/config/external/file/project.rb3
-rw-r--r--lib/gitlab/ci/config/external/mapper.rb3
-rw-r--r--lib/gitlab/ci/pipeline/chain/base.rb2
-rw-r--r--lib/gitlab/ci/pipeline/chain/command.rb4
-rw-r--r--lib/gitlab/ci/pipeline/chain/config/process.rb3
-rw-r--r--lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml9
-rw-r--r--lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/yaml_processor.rb9
-rw-r--r--lib/gitlab/config/entry/attributable.rb2
-rw-r--r--lib/gitlab/config/entry/configurable.rb15
-rw-r--r--locale/gitlab.pot12
-rwxr-xr-xscripts/trigger-build6
-rw-r--r--spec/fixtures/ci_build_artifacts.zipbin106365 -> 107464 bytes
-rw-r--r--spec/lib/backup/manager_spec.rb17
-rw-r--r--spec/lib/gitlab/ci/artifact_file_reader_spec.rb100
-rw-r--r--spec/lib/gitlab/ci/config/entry/bridge_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/job_spec.rb16
-rw-r--r--spec/lib/gitlab/ci/config/entry/jobs_spec.rb1
-rw-r--r--spec/lib/gitlab/ci/config/entry/processable_spec.rb105
-rw-r--r--spec/lib/gitlab/ci/config/entry/root_spec.rb17
-rw-r--r--spec/lib/gitlab/ci/config/external/file/artifact_spec.rb167
-rw-r--r--spec/lib/gitlab/ci/config/external/file/local_spec.rb17
-rw-r--r--spec/lib/gitlab/ci/config/external/file/project_spec.rb17
-rw-r--r--spec/lib/gitlab/ci/config_spec.rb88
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb76
-rw-r--r--spec/lib/gitlab/config/entry/attributable_spec.rb2
-rw-r--r--spec/models/ci/job_artifact_spec.rb6
-rw-r--r--spec/models/ci/pipeline_spec.rb13
-rw-r--r--spec/models/snippet_spec.rb26
-rw-r--r--spec/requests/api/runner_spec.rb2
-rw-r--r--spec/services/ci/create_pipeline_service/custom_config_content_spec.rb67
-rw-r--r--spec/services/projects/fork_service_spec.rb1
-rw-r--r--spec/services/projects/update_repository_storage_service_spec.rb68
-rw-r--r--spec/support/shared_examples/lib/gitlab/config/inheritable_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/services/projects/update_repository_storage_service_shared_examples.rb46
-rw-r--r--spec/workers/post_receive_spec.rb22
70 files changed, 1242 insertions, 222 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f9c320e9e96..f257df035f2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,6 @@ entry.
## 12.8.4
-- No changes.
### Fixed (8 changes)
- Fix Group Import API file upload when object storage is disabled. !25715
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue
index f9d3d31e152..77cd2afc106 100644
--- a/app/assets/javascripts/diffs/components/app.vue
+++ b/app/assets/javascripts/diffs/components/app.vue
@@ -398,7 +398,7 @@ export default {
}"
>
<commit-widget v-if="commit" :commit="commit" />
- <div v-if="isBatchLoading" class="loading"><gl-loading-icon /></div>
+ <div v-if="isBatchLoading" class="loading"><gl-loading-icon size="lg" /></div>
<template v-else-if="renderDiffFiles">
<diff-file
v-for="file in diffFiles"
diff --git a/app/models/ci/bridge.rb b/app/models/ci/bridge.rb
index a28e44d44c1..d62aa09e432 100644
--- a/app/models/ci/bridge.rb
+++ b/app/models/ci/bridge.rb
@@ -89,6 +89,10 @@ module Ci
end
end
+ def parent_pipeline
+ pipeline if triggers_child_pipeline?
+ end
+
def triggers_child_pipeline?
yaml_for_downstream.present?
end
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index ff257c6cd68..bc0528bdbe0 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -787,6 +787,10 @@ module Ci
.fabricate!
end
+ def find_job_with_archive_artifacts(name)
+ builds.latest.with_artifacts_archive.find_by_name(name)
+ end
+
def latest_builds_with_artifacts
# We purposely cast the builds to an Array here. Because we always use the
# rows if there are more than 0 this prevents us from having to run two
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index 770d9b5205c..27e1778e9b6 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -197,6 +197,8 @@ class Snippet < ApplicationRecord
end
def blobs
+ return [] unless repository_exists?
+
repository.ls_files(repository.root_ref).map { |file| Blob.lazy(self, repository.root_ref, file) }
end
diff --git a/app/services/projects/update_repository_storage_service.rb b/app/services/projects/update_repository_storage_service.rb
index 30b99e85304..1565b534b19 100644
--- a/app/services/projects/update_repository_storage_service.rb
+++ b/app/services/projects/update_repository_storage_service.rb
@@ -4,6 +4,7 @@ module Projects
class UpdateRepositoryStorageService < BaseService
include Gitlab::ShellAdapter
+ Error = Class.new(StandardError)
RepositoryAlreadyMoved = Class.new(StandardError)
def initialize(project)
@@ -17,37 +18,45 @@ module Projects
# exception.
raise RepositoryAlreadyMoved if project.repository_storage == new_repository_storage_key
- if mirror_repositories(new_repository_storage_key)
- mark_old_paths_for_archive
+ mirror_repositories(new_repository_storage_key)
- project.update(repository_storage: new_repository_storage_key, repository_read_only: false)
- project.leave_pool_repository
- project.track_project_repository
+ mark_old_paths_for_archive
- enqueue_housekeeping
- else
- project.update(repository_read_only: false)
- end
+ project.update(repository_storage: new_repository_storage_key, repository_read_only: false)
+ project.leave_pool_repository
+ project.track_project_repository
+
+ enqueue_housekeeping
+
+ success
+
+ rescue Error => e
+ project.update(repository_read_only: false)
+
+ Gitlab::ErrorTracking.track_exception(e, project_path: project.full_path)
+
+ error(s_("UpdateRepositoryStorage|Error moving repository storage for %{project_full_path} - %{message}") % { project_full_path: project.full_path, message: e.message })
end
private
def mirror_repositories(new_repository_storage_key)
- result = mirror_repository(new_repository_storage_key)
+ mirror_repository(new_repository_storage_key)
if project.wiki.repository_exists?
- result &&= mirror_repository(new_repository_storage_key, type: Gitlab::GlRepository::WIKI)
+ mirror_repository(new_repository_storage_key, type: Gitlab::GlRepository::WIKI)
end
-
- result
end
def mirror_repository(new_storage_key, type: Gitlab::GlRepository::PROJECT)
- return false unless wait_for_pushes(type)
+ unless wait_for_pushes(type)
+ raise Error, s_('UpdateRepositoryStorage|Timeout waiting for %{type} repository pushes') % { type: type.name }
+ end
repository = type.repository_for(project)
full_path = repository.full_path
raw_repository = repository.raw
+ checksum = repository.checksum
# Initialize a git repository on the target path
gitlab_shell.create_repository(new_storage_key, raw_repository.relative_path, full_path)
@@ -56,7 +65,15 @@ module Projects
raw_repository.gl_repository,
full_path)
- new_repository.fetch_repository_as_mirror(raw_repository)
+ unless new_repository.fetch_repository_as_mirror(raw_repository)
+ raise Error, s_('UpdateRepositoryStorage|Failed to fetch %{type} repository as mirror') % { type: type.name }
+ end
+
+ new_checksum = new_repository.checksum
+
+ if checksum != new_checksum
+ raise Error, s_('UpdateRepositoryStorage|Failed to verify %{type} repository checksum from %{old} to %{new}') % { type: type.name, old: checksum, new: new_checksum }
+ end
end
def mark_old_paths_for_archive
diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb
index 5178fabb2d8..05b6d6d570c 100644
--- a/app/workers/post_receive.rb
+++ b/app/workers/post_receive.rb
@@ -77,6 +77,11 @@ class PostReceive # rubocop:disable Scalability/IdempotentWorker
return false unless user
+ # We can remove once we implement multi-file snippets
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/39269
+ blob = snippet.blobs.first
+ snippet.update(file_name: blob.path, content: blob.data) if blob
+
# At the moment, we only expires the repository caches.
# In the future we might need to call ProjectCacheWorker
# (or the custom class we create) to update the snippet
diff --git a/changelogs/unreleased/207249-prevent-editing-weight-to-scroll-to-the-top.yml b/changelogs/unreleased/207249-prevent-editing-weight-to-scroll-to-the-top.yml
new file mode 100644
index 00000000000..59382ad677e
--- /dev/null
+++ b/changelogs/unreleased/207249-prevent-editing-weight-to-scroll-to-the-top.yml
@@ -0,0 +1,5 @@
+---
+title: Prevent editing weight to scroll to the top.
+merge_request: 26613
+author: Gilang Gumilar
+type: fixed
diff --git a/changelogs/unreleased/add-retiresjs-vars-to-dependency-scanning.yml b/changelogs/unreleased/add-retiresjs-vars-to-dependency-scanning.yml
new file mode 100644
index 00000000000..5c9f312f44e
--- /dev/null
+++ b/changelogs/unreleased/add-retiresjs-vars-to-dependency-scanning.yml
@@ -0,0 +1,5 @@
+---
+title: Add vars to allow air-gapped usage of Retire.js (Dependency Scanning)
+merge_request: 26463
+author:
+type: added
diff --git a/changelogs/unreleased/add-trigger-include-artifact.yml b/changelogs/unreleased/add-trigger-include-artifact.yml
new file mode 100644
index 00000000000..acfad941751
--- /dev/null
+++ b/changelogs/unreleased/add-trigger-include-artifact.yml
@@ -0,0 +1,5 @@
+---
+title: 'Create child pipelines dynamically using content from artifact as CI configuration'
+merge_request: 23790
+author:
+type: fixed
diff --git a/changelogs/unreleased/allow-selecting-all-queues-with-sidekiq-cluster.yml b/changelogs/unreleased/allow-selecting-all-queues-with-sidekiq-cluster.yml
new file mode 100644
index 00000000000..7dba322b07e
--- /dev/null
+++ b/changelogs/unreleased/allow-selecting-all-queues-with-sidekiq-cluster.yml
@@ -0,0 +1,5 @@
+---
+title: Allow selecting all queues with sidekiq-cluster
+merge_request: 26594
+author:
+type: added
diff --git a/changelogs/unreleased/allow-to-disable-defaults.yml b/changelogs/unreleased/allow-to-disable-defaults.yml
new file mode 100644
index 00000000000..c5c6616a8c2
--- /dev/null
+++ b/changelogs/unreleased/allow-to-disable-defaults.yml
@@ -0,0 +1,5 @@
+---
+title: Allow to disable inheritance of default job settings
+merge_request: 25690
+author:
+type: added
diff --git a/changelogs/unreleased/fj-update-snippet-from-git-action.yml b/changelogs/unreleased/fj-update-snippet-from-git-action.yml
new file mode 100644
index 00000000000..bf210ba1a14
--- /dev/null
+++ b/changelogs/unreleased/fj-update-snippet-from-git-action.yml
@@ -0,0 +1,5 @@
+---
+title: Sync snippet after Git action
+merge_request: 26565
+author:
+type: changed
diff --git a/changelogs/unreleased/remove-cs-kubernetes-workaround.yml b/changelogs/unreleased/remove-cs-kubernetes-workaround.yml
new file mode 100644
index 00000000000..879da58aa3c
--- /dev/null
+++ b/changelogs/unreleased/remove-cs-kubernetes-workaround.yml
@@ -0,0 +1,5 @@
+---
+title: Remove kubernetes workaround in container scanning
+merge_request: 21188
+author:
+type: changed
diff --git a/changelogs/unreleased/update_repo_storage_checksum.yml b/changelogs/unreleased/update_repo_storage_checksum.yml
new file mode 100644
index 00000000000..b2f8b673730
--- /dev/null
+++ b/changelogs/unreleased/update_repo_storage_checksum.yml
@@ -0,0 +1,5 @@
+---
+title: Ensure checksums match when updating repository storage
+merge_request: 26334
+author:
+type: changed
diff --git a/config/environments/development.rb b/config/environments/development.rb
index dc804197fef..b6b025112fe 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -50,4 +50,14 @@ Rails.application.configure do
# BetterErrors live shell (REPL) on every stack frame
BetterErrors::Middleware.allow_ip!("127.0.0.1/0")
+
+ # Reassign some performance related settings when we profile the app
+ if Gitlab::Utils.to_boolean(ENV['RAILS_PROFILE'].to_s)
+ warn "Hot-reloading is disabled as you are running with RAILS_PROFILE enabled"
+ config.cache_classes = true
+ config.eager_load = true
+ config.active_record.migration_error = false
+ config.active_record.verbose_query_logs = false
+ config.action_view.cache_template_loading = true
+ end
end
diff --git a/doc/administration/monitoring/gitlab_self_monitoring_project/index.md b/doc/administration/monitoring/gitlab_self_monitoring_project/index.md
index 1946e55603c..6f9821f4ace 100644
--- a/doc/administration/monitoring/gitlab_self_monitoring_project/index.md
+++ b/doc/administration/monitoring/gitlab_self_monitoring_project/index.md
@@ -17,7 +17,7 @@ members to the group in order to give them maintainer access to the project.
This project will be used for self monitoring your GitLab instance.
-## Activating the self monitoring project
+## Creating the self monitoring project
1. Navigate to **Admin Area > Settings > Metrics and profiling**, and expand the **Self monitoring** section.
1. Toggle the **Create Project** button on.
@@ -26,10 +26,11 @@ created, GitLab displays a message with a link to the project. The project
will also be linked in the help text above the **Create Project** button. You can also
find the project under **Projects > Your projects**.
-## Deactivating the self monitoring project
+## Deleting the self monitoring project
CAUTION: **Warning:**
-If you deactivate the self monitoring project, it will be permanently deleted.
+If you delete the self monitoring project, you will lose any changes made to the
+project. If you create the project again, it will be created in its default state.
1. Navigate to **Admin Area > Settings > Metrics and profiling**, and expand the **Self monitoring** section.
1. Toggle the **Create Project** button off.
diff --git a/doc/administration/operations/extra_sidekiq_processes.md b/doc/administration/operations/extra_sidekiq_processes.md
index 3ad411f6f5a..f859db5caff 100644
--- a/doc/administration/operations/extra_sidekiq_processes.md
+++ b/doc/administration/operations/extra_sidekiq_processes.md
@@ -53,6 +53,20 @@ To start extra Sidekiq processes, you must enable `sidekiq-cluster`:
]
```
+ [In GitLab 12.9](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26594) and
+ later, the special queue name `*` means all queues. This starts two
+ processes, each handling all queues:
+
+ ```ruby
+ sidekiq_cluster['queue_groups'] = [
+ "*",
+ "*"
+ ]
+ ```
+
+ `*` cannot be combined with concrete queue names - `*, mailers` will
+ just handle the `mailers` queue.
+
1. Save the file and reconfigure GitLab for the changes to take effect:
```shell
@@ -154,6 +168,10 @@ from highest to lowest precedence:
The operator precedence for this syntax is fixed: it's not possible to make AND
have higher precedence than OR.
+[In GitLab 12.9](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26594) and
+later, as with the standard queue group syntax above, a single `*` as the
+entire queue group selects all queues.
+
### Example queries
In `/etc/gitlab/gitlab.rb`:
@@ -163,9 +181,11 @@ sidekiq_cluster['enable'] = true
sidekiq_cluster['experimental_queue_selector'] = true
sidekiq_cluster['queue_groups'] = [
# Run all non-CPU-bound queues that are high urgency
- 'resource_boundary!=cpu&urgency=high,
+ 'resource_boundary!=cpu&urgency=high',
# Run all continuous integration and pages queues that are not high urgency
- 'feature_category=continuous_integration,pages&urgency!=high
+ 'feature_category=continuous_integration,pages&urgency!=high',
+ # Run all queues
+ '*'
]
```
diff --git a/doc/administration/troubleshooting/sidekiq.md b/doc/administration/troubleshooting/sidekiq.md
index b72bce5b3c6..8176ebab2e8 100644
--- a/doc/administration/troubleshooting/sidekiq.md
+++ b/doc/administration/troubleshooting/sidekiq.md
@@ -18,6 +18,26 @@ troubleshooting steps that will help you diagnose the bottleneck.
> may be using all available CPU, or have a Ruby Global Interpreter Lock,
> preventing other threads from continuing.
+## Log arguments to Sidekiq jobs
+
+If you want to see what arguments are being passed to Sidekiq jobs you can set
+the `SIDEKIQ_LOG_ARGUMENTS` [environment variable](https://docs.gitlab.com/omnibus/settings/environment-variables.html) to `1` (true).
+
+Example:
+
+```
+gitlab_rails['env'] = {"SIDEKIQ_LOG_ARGUMENTS" => "1"}
+```
+
+Please note: It is not recommend to enable this setting in production because some
+Sidekiq jobs (such as sending a password reset email) take secret arguments (for
+example the password reset token).
+
+When using [Sidekiq JSON logging](../logs.md#sidekiqlog),
+arguments logs are limited to a maximum size of 10 kilobytes of text;
+any arguments after this limit will be discarded and replaced with a
+single argument containing the string `"..."`.
+
## Thread dump
Send the Sidekiq process ID the `TTIN` signal and it will output thread
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 00b5d5d0d6d..9976a423996 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -158,6 +158,42 @@ rspec 2.6:
script: bundle exec rspec
```
+### `inherit`
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/207484) in GitLab 12.9.
+
+You can disable inheritance of globally defined defaults
+and variables with the `inherit:` parameter.
+
+In the example below:
+
+- `rubocop` **will** inherit both the `before_script` and the variable `DOMAIN`.
+- `rspec` **will not** inherit the `before_script` or the variable `DOMAIN`.
+- `capybara` **will** inherit the `before_script`, but **will not** inherit the variable `DOMAIN`.
+
+```yaml
+default:
+ before_script:
+ - echo Hello World
+
+variables:
+ DOMAIN: example.com
+
+rubocop:
+ script: bundle exec rubocop
+
+rspec:
+ inherit:
+ default: false
+ variables: false
+ script: bundle exec rspec
+
+capybara:
+ inherit:
+ variables: false
+ script: bundle exec capybara
+```
+
## Parameter details
The following are detailed explanations for parameters used to configure CI/CD pipelines.
diff --git a/doc/development/profiling.md b/doc/development/profiling.md
index 316273f37b8..04713055117 100644
--- a/doc/development/profiling.md
+++ b/doc/development/profiling.md
@@ -120,3 +120,16 @@ Bullet will log query problems to both the Rails log as well as the Chrome
console.
As a follow up to finding `N+1` queries with Bullet, consider writing a [QueryRecoder test](query_recorder.md) to prevent a regression.
+
+## Settings that impact performance
+
+1. `development` environment by default works with hot-reloading enabled, this makes Rails to check file changes every request, and create a potential contention lock, as hot reload is single threaded.
+1. `development` environment can load code lazily once the request is fired which results in first request to always be slow.
+
+To disable those features for profiling/benchmarking set the `RAILS_PROFILE` environment variable to `true` before starting GitLab. For example when using GDK:
+
+- create a file [`env.runit`](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/master/doc/runit.md#modifying-environment-configuration-for-services) in the root GDK directory
+- add `export RAILS_PROFILE=true` to your `env.runit` file
+- restart GDK with `gdk restart`
+
+*This environment variable is only applicable for the development mode.*
diff --git a/doc/development/sidekiq_debugging.md b/doc/development/sidekiq_debugging.md
index 2b3a9481b93..b6a11dd813d 100644
--- a/doc/development/sidekiq_debugging.md
+++ b/doc/development/sidekiq_debugging.md
@@ -2,20 +2,5 @@
## Log arguments to Sidekiq jobs
-If you want to see what arguments are being passed to Sidekiq jobs you can set
-the `SIDEKIQ_LOG_ARGUMENTS` [environment variable](https://docs.gitlab.com/omnibus/settings/environment-variables.html) to `1` (true).
-
-Example:
-
-```
-gitlab_rails['env'] = {"SIDEKIQ_LOG_ARGUMENTS" => "1"}
-```
-
-Please note: It is not recommend to enable this setting in production because some
-Sidekiq jobs (such as sending a password reset email) take secret arguments (for
-example the password reset token).
-
-When using [Sidekiq JSON logging](../administration/logs.md#sidekiqlog),
-arguments logs are limited to a maximum size of 10 kilobytes of text;
-any arguments after this limit will be discarded and replaced with a
-single argument containing the string `"..."`.
+This content has been moved to the
+[Troubleshooting Sidekiq docs](../administration/troubleshooting/sidekiq.md).
diff --git a/lib/gitlab/ci/artifact_file_reader.rb b/lib/gitlab/ci/artifact_file_reader.rb
new file mode 100644
index 00000000000..c2d17cc176e
--- /dev/null
+++ b/lib/gitlab/ci/artifact_file_reader.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+# This class takes in input a Ci::Build object and an artifact path to read.
+# It downloads and extracts the artifacts archive, then returns the content
+# of the artifact, if found.
+module Gitlab
+ module Ci
+ class ArtifactFileReader
+ Error = Class.new(StandardError)
+
+ MAX_ARCHIVE_SIZE = 5.megabytes
+
+ def initialize(job)
+ @job = job
+
+ raise ArgumentError, 'Job does not have artifacts' unless @job.artifacts?
+
+ validate!
+ end
+
+ def read(path)
+ return unless job.artifacts_metadata
+
+ metadata_entry = job.artifacts_metadata_entry(path)
+
+ if metadata_entry.total_size > MAX_ARCHIVE_SIZE
+ raise Error, "Artifacts archive for job `#{job.name}` is too large: max #{max_archive_size_in_mb}"
+ end
+
+ read_zip_file!(path)
+ end
+
+ private
+
+ attr_reader :job
+
+ def validate!
+ if job.job_artifacts_archive.size > MAX_ARCHIVE_SIZE
+ raise Error, "Artifacts archive for job `#{job.name}` is too large: max #{max_archive_size_in_mb}"
+ end
+
+ unless job.artifacts_metadata?
+ raise Error, "Job `#{job.name}` has missing artifacts metadata and cannot be extracted!"
+ end
+ end
+
+ def read_zip_file!(file_path)
+ job.artifacts_file.use_file do |archive_path|
+ Zip::File.open(archive_path) do |zip_file|
+ entry = zip_file.find_entry(file_path)
+ unless entry
+ raise Error, "Path `#{file_path}` does not exist inside the `#{job.name}` artifacts archive!"
+ end
+
+ if entry.name_is_directory?
+ raise Error, "Path `#{file_path}` was expected to be a file but it was a directory!"
+ end
+
+ zip_file.get_input_stream(entry) do |is|
+ is.read
+ end
+ end
+ end
+ end
+
+ def max_archive_size_in_mb
+ ActiveSupport::NumberHelper.number_to_human_size(MAX_ARCHIVE_SIZE)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/config.rb b/lib/gitlab/ci/config.rb
index 38ab3475d01..e069f734e32 100644
--- a/lib/gitlab/ci/config.rb
+++ b/lib/gitlab/ci/config.rb
@@ -18,12 +18,9 @@ module Gitlab
attr_reader :root
- def initialize(config, project: nil, sha: nil, user: nil)
- @context = build_context(project: project, sha: sha, user: user)
-
- if Feature.enabled?(:ci_limit_yaml_expansion, project, default_enabled: true)
- @context.set_deadline(TIMEOUT_SECONDS)
- end
+ def initialize(config, project: nil, sha: nil, user: nil, parent_pipeline: nil)
+ @context = build_context(project: project, sha: sha, user: user, parent_pipeline: parent_pipeline)
+ @context.set_deadline(TIMEOUT_SECONDS)
@config = expand_config(config)
@@ -87,11 +84,12 @@ module Gitlab
initial_config
end
- def build_context(project:, sha:, user:)
+ def build_context(project:, sha:, user:, parent_pipeline:)
Config::External::Context.new(
project: project,
sha: sha || project&.repository&.root_ref_sha,
- user: user)
+ user: user,
+ parent_pipeline: parent_pipeline)
end
def track_and_raise_for_dev_exception(error)
diff --git a/lib/gitlab/ci/config/entry/bridge.rb b/lib/gitlab/ci/config/entry/bridge.rb
index 6fdaa373170..f4362d3b0ce 100644
--- a/lib/gitlab/ci/config/entry/bridge.rb
+++ b/lib/gitlab/ci/config/entry/bridge.rb
@@ -11,7 +11,7 @@ module Gitlab
class Bridge < ::Gitlab::Config::Entry::Node
include ::Gitlab::Ci::Config::Entry::Processable
- ALLOWED_KEYS = %i[trigger allow_failure when variables needs].freeze
+ ALLOWED_KEYS = %i[trigger allow_failure when needs].freeze
validations do
validates :config, allowed_keys: ALLOWED_KEYS + PROCESSABLE_ALLOWED_KEYS
@@ -45,10 +45,6 @@ module Gitlab
inherit: false,
metadata: { allowed_needs: %i[job bridge] }
- entry :variables, ::Gitlab::Ci::Config::Entry::Variables,
- description: 'Environment variables available for this job.',
- inherit: false
-
attributes :when, :allow_failure
def self.matching?(name, config)
@@ -67,7 +63,6 @@ module Gitlab
needs: (needs_value if needs_defined?),
ignore: !!allow_failure,
when: self.when,
- variables: (variables_value if variables_defined?),
scheduling_type: needs_defined? && !bridge_needs ? :dag : :stage
).compact
end
diff --git a/lib/gitlab/ci/config/entry/include.rb b/lib/gitlab/ci/config/entry/include.rb
index f2f3dd84eda..cd09d83b728 100644
--- a/lib/gitlab/ci/config/entry/include.rb
+++ b/lib/gitlab/ci/config/entry/include.rb
@@ -10,7 +10,7 @@ module Gitlab
class Include < ::Gitlab::Config::Entry::Node
include ::Gitlab::Config::Entry::Validatable
- ALLOWED_KEYS = %i[local file remote template].freeze
+ ALLOWED_KEYS = %i[local file remote template artifact job].freeze
validations do
validates :config, hash_or_string: true
diff --git a/lib/gitlab/ci/config/entry/inherit.rb b/lib/gitlab/ci/config/entry/inherit.rb
new file mode 100644
index 00000000000..540f1e62c6c
--- /dev/null
+++ b/lib/gitlab/ci/config/entry/inherit.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Config
+ module Entry
+ ##
+ # This class represents a inherit entry
+ #
+ class Inherit < ::Gitlab::Config::Entry::Node
+ include ::Gitlab::Config::Entry::Configurable
+
+ ALLOWED_KEYS = %i[default variables].freeze
+
+ validations do
+ validates :config, allowed_keys: ALLOWED_KEYS
+ end
+
+ entry :default, ::Gitlab::Config::Entry::Boolean,
+ description: 'Indicates whether to inherit `default:`.',
+ default: true
+
+ entry :variables, ::Gitlab::Config::Entry::Boolean,
+ description: 'Indicates whether to inherit `variables:`.',
+ default: true
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/config/entry/job.rb b/lib/gitlab/ci/config/entry/job.rb
index 8db21b116eb..1ea59491378 100644
--- a/lib/gitlab/ci/config/entry/job.rb
+++ b/lib/gitlab/ci/config/entry/job.rb
@@ -13,7 +13,7 @@ module Gitlab
ALLOWED_WHEN = %w[on_success on_failure always manual delayed].freeze
ALLOWED_KEYS = %i[tags script type image services
allow_failure type when start_in artifacts cache
- dependencies before_script needs after_script variables
+ dependencies before_script needs after_script
environment coverage retry parallel interruptible timeout
resource_group release].freeze
@@ -112,10 +112,6 @@ module Gitlab
metadata: { allowed_needs: %i[job cross_dependency] },
inherit: false
- entry :variables, Entry::Variables,
- description: 'Environment variables available for this job.',
- inherit: false
-
entry :environment, Entry::Environment,
description: 'Environment configuration for this job.',
inherit: false
@@ -174,7 +170,6 @@ module Gitlab
when: self.when,
start_in: self.start_in,
dependencies: dependencies,
- variables: variables_defined? ? variables_value : {},
environment: environment_defined? ? environment_value : nil,
environment_name: environment_defined? ? environment_value[:name] : nil,
coverage: coverage_defined? ? coverage_value : nil,
diff --git a/lib/gitlab/ci/config/entry/processable.rb b/lib/gitlab/ci/config/entry/processable.rb
index bfa2905ed77..b4da48957b0 100644
--- a/lib/gitlab/ci/config/entry/processable.rb
+++ b/lib/gitlab/ci/config/entry/processable.rb
@@ -14,7 +14,7 @@ module Gitlab
include ::Gitlab::Config::Entry::Attributable
include ::Gitlab::Config::Entry::Inheritable
- PROCESSABLE_ALLOWED_KEYS = %i[extends stage only except rules].freeze
+ PROCESSABLE_ALLOWED_KEYS = %i[extends stage only except rules variables inherit].freeze
included do
validations do
@@ -54,12 +54,21 @@ module Gitlab
allowed_when: %w[on_success on_failure always never manual delayed].freeze
}
+ entry :variables, ::Gitlab::Ci::Config::Entry::Variables,
+ description: 'Environment variables available for this job.',
+ inherit: false
+
+ entry :inherit, ::Gitlab::Ci::Config::Entry::Inherit,
+ description: 'Indicates whether to inherit defaults or not.',
+ inherit: false,
+ default: {}
+
attributes :extends, :rules
end
def compose!(deps = nil)
super do
- has_workflow_rules = deps&.workflow&.has_rules?
+ has_workflow_rules = deps&.workflow_entry&.has_rules?
# If workflow:rules: or rules: are used
# they are considered not compatible
@@ -73,6 +82,9 @@ module Gitlab
@entries.delete(:except) unless except_defined? # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
+ # inherit root variables
+ @root_variables_value = deps&.variables_value # rubocop:disable Gitlab/ModuleWithInstanceVariables
+
yield if block_given?
end
end
@@ -82,7 +94,10 @@ module Gitlab
end
def overwrite_entry(deps, key, current_entry)
- deps.default[key] unless current_entry.specified?
+ return unless inherit_entry&.default_value
+ return unless deps.default_entry
+
+ deps.default_entry[key] unless current_entry.specified?
end
def value
@@ -90,9 +105,18 @@ module Gitlab
stage: stage_value,
extends: extends,
rules: rules_value,
+ variables: root_and_job_variables_value,
only: only_value,
except: except_value }.compact
end
+
+ def root_and_job_variables_value
+ if inherit_entry&.variables_value
+ @root_variables_value.to_h.merge(variables_value.to_h) # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ else
+ variables_value.to_h
+ end
+ end
end
end
end
diff --git a/lib/gitlab/ci/config/entry/root.rb b/lib/gitlab/ci/config/entry/root.rb
index caa0725c4bd..19d6a470941 100644
--- a/lib/gitlab/ci/config/entry/root.rb
+++ b/lib/gitlab/ci/config/entry/root.rb
@@ -65,7 +65,8 @@ module Gitlab
reserved: true
entry :workflow, Entry::Workflow,
- description: 'List of evaluable rules to determine Pipeline status'
+ description: 'List of evaluable rules to determine Pipeline status',
+ default: {}
dynamic_helpers :jobs
@@ -73,7 +74,7 @@ module Gitlab
:image_value,
:services_value,
:after_script_value,
- :cache_value, to: :default
+ :cache_value, to: :default_entry
attr_reader :jobs_config
@@ -102,14 +103,6 @@ module Gitlab
end
end
- def default
- self[:default]
- end
-
- def workflow
- self[:workflow] if workflow_defined?
- end
-
private
# rubocop: disable CodeReuse/ActiveRecord
diff --git a/lib/gitlab/ci/config/entry/workflow.rb b/lib/gitlab/ci/config/entry/workflow.rb
index 1d9007c9b9b..5bc992a38a0 100644
--- a/lib/gitlab/ci/config/entry/workflow.rb
+++ b/lib/gitlab/ci/config/entry/workflow.rb
@@ -12,7 +12,6 @@ module Gitlab
validations do
validates :config, type: Hash
validates :config, allowed_keys: ALLOWED_KEYS
- validates :config, presence: true
end
entry :rules, Entry::Rules,
diff --git a/lib/gitlab/ci/config/external/context.rb b/lib/gitlab/ci/config/external/context.rb
index bb4439cd069..814dcc66362 100644
--- a/lib/gitlab/ci/config/external/context.rb
+++ b/lib/gitlab/ci/config/external/context.rb
@@ -7,13 +7,14 @@ module Gitlab
class Context
TimeoutError = Class.new(StandardError)
- attr_reader :project, :sha, :user
+ attr_reader :project, :sha, :user, :parent_pipeline
attr_reader :expandset, :execution_deadline
- def initialize(project: nil, sha: nil, user: nil)
+ def initialize(project: nil, sha: nil, user: nil, parent_pipeline: nil)
@project = project
@sha = sha
@user = user
+ @parent_pipeline = parent_pipeline
@expandset = Set.new
@execution_deadline = 0
diff --git a/lib/gitlab/ci/config/external/file/artifact.rb b/lib/gitlab/ci/config/external/file/artifact.rb
new file mode 100644
index 00000000000..fcfdda21c08
--- /dev/null
+++ b/lib/gitlab/ci/config/external/file/artifact.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Config
+ module External
+ module File
+ class Artifact < Base
+ extend ::Gitlab::Utils::Override
+ include Gitlab::Utils::StrongMemoize
+
+ attr_reader :job_name
+
+ def initialize(params, context)
+ @location = params[:artifact]
+ @job_name = params[:job]
+
+ super
+ end
+
+ def content
+ strong_memoize(:content) do
+ next unless artifact_job
+
+ Gitlab::Ci::ArtifactFileReader.new(artifact_job).read(location)
+ rescue Gitlab::Ci::ArtifactFileReader::Error => error
+ errors.push(error.message)
+ end
+ end
+
+ def matching?
+ super &&
+ Feature.enabled?(:ci_dynamic_child_pipeline, project)
+ end
+
+ private
+
+ def project
+ context&.parent_pipeline&.project
+ end
+
+ def validate_content!
+ return unless ensure_preconditions_satisfied!
+
+ errors.push("File `#{location}` is empty!") unless content.present?
+ end
+
+ def ensure_preconditions_satisfied!
+ unless creating_child_pipeline?
+ errors.push('Including configs from artifacts is only allowed when triggering child pipelines')
+ return false
+ end
+
+ unless job_name.present?
+ errors.push("Job must be provided when including configs from artifacts")
+ return false
+ end
+
+ unless artifact_job.present?
+ errors.push("Job `#{job_name}` not found in parent pipeline or does not have artifacts!")
+ return false
+ end
+
+ true
+ end
+
+ def artifact_job
+ strong_memoize(:artifact_job) do
+ next unless creating_child_pipeline?
+
+ context.parent_pipeline.find_job_with_archive_artifacts(job_name)
+ end
+ end
+
+ def creating_child_pipeline?
+ context.parent_pipeline.present?
+ end
+
+ override :expand_context_attrs
+ def expand_context_attrs
+ {
+ project: context.project,
+ sha: context.sha,
+ user: context.user,
+ parent_pipeline: context.parent_pipeline
+ }
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/config/external/file/local.rb b/lib/gitlab/ci/config/external/file/local.rb
index 8cb1575a3e1..e74f5b33de7 100644
--- a/lib/gitlab/ci/config/external/file/local.rb
+++ b/lib/gitlab/ci/config/external/file/local.rb
@@ -40,7 +40,8 @@ module Gitlab
{
project: context.project,
sha: context.sha,
- user: context.user
+ user: context.user,
+ parent_pipeline: context.parent_pipeline
}
end
end
diff --git a/lib/gitlab/ci/config/external/file/project.rb b/lib/gitlab/ci/config/external/file/project.rb
index c7b49b495fa..be479741784 100644
--- a/lib/gitlab/ci/config/external/file/project.rb
+++ b/lib/gitlab/ci/config/external/file/project.rb
@@ -71,7 +71,8 @@ module Gitlab
{
project: project,
sha: sha,
- user: context.user
+ user: context.user,
+ parent_pipeline: context.parent_pipeline
}
end
end
diff --git a/lib/gitlab/ci/config/external/mapper.rb b/lib/gitlab/ci/config/external/mapper.rb
index 0143d7784fa..97ae6c4ceba 100644
--- a/lib/gitlab/ci/config/external/mapper.rb
+++ b/lib/gitlab/ci/config/external/mapper.rb
@@ -13,7 +13,8 @@ module Gitlab
External::File::Remote,
External::File::Template,
External::File::Local,
- External::File::Project
+ External::File::Project,
+ External::File::Artifact
].freeze
Error = Class.new(StandardError)
diff --git a/lib/gitlab/ci/pipeline/chain/base.rb b/lib/gitlab/ci/pipeline/chain/base.rb
index aabdf7ce47d..9b494f3a7ec 100644
--- a/lib/gitlab/ci/pipeline/chain/base.rb
+++ b/lib/gitlab/ci/pipeline/chain/base.rb
@@ -7,7 +7,7 @@ module Gitlab
class Base
attr_reader :pipeline, :command, :config
- delegate :project, :current_user, to: :command
+ delegate :project, :current_user, :parent_pipeline, to: :command
def initialize(pipeline, command)
@pipeline = pipeline
diff --git a/lib/gitlab/ci/pipeline/chain/command.rb b/lib/gitlab/ci/pipeline/chain/command.rb
index 6a16e6df23d..fa46114615c 100644
--- a/lib/gitlab/ci/pipeline/chain/command.rb
+++ b/lib/gitlab/ci/pipeline/chain/command.rb
@@ -72,6 +72,10 @@ module Gitlab
project.repository.ambiguous_ref?(origin_ref)
end
end
+
+ def parent_pipeline
+ bridge&.parent_pipeline
+ end
end
end
end
diff --git a/lib/gitlab/ci/pipeline/chain/config/process.rb b/lib/gitlab/ci/pipeline/chain/config/process.rb
index 09d1b0edc93..1e47be21b93 100644
--- a/lib/gitlab/ci/pipeline/chain/config/process.rb
+++ b/lib/gitlab/ci/pipeline/chain/config/process.rb
@@ -15,7 +15,8 @@ module Gitlab
@command.config_content, {
project: project,
sha: @pipeline.sha,
- user: current_user
+ user: current_user,
+ parent_pipeline: parent_pipeline
}
)
rescue Gitlab::Ci::YamlProcessor::ValidationError => ex
diff --git a/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml
index f708e95c2cf..6efb6b4e273 100644
--- a/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml
@@ -5,9 +5,7 @@ variables:
container_scanning:
stage: test
- image:
- name: registry.gitlab.com/gitlab-org/security-products/analyzers/klar:$CS_MAJOR_VERSION
- entrypoint: []
+ image: registry.gitlab.com/gitlab-org/security-products/analyzers/klar:$CS_MAJOR_VERSION
variables:
# By default, use the latest clair vulnerabilities database, however, allow it to be overridden here with a specific image
# to enable container scanning to run offline, or to provide a consistent list of vulnerabilities for integration testing purposes
@@ -22,10 +20,7 @@ container_scanning:
- name: $CLAIR_DB_IMAGE
alias: clair-vulnerabilities-db
script:
- # the kubernetes executor currently ignores the Docker image entrypoint value, so the start.sh script must
- # be explicitly executed here in order for this to work with both the kubernetes and docker executors
- # see this issue for more details https://gitlab.com/gitlab-org/gitlab-runner/issues/4125
- - /container-scanner/start.sh
+ - /analyzer run
artifacts:
reports:
container_scanning: gl-container-scanning-report.json
diff --git a/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
index 5ff6413898f..4a9fa3091be 100644
--- a/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
@@ -59,6 +59,8 @@ dependency_scanning:
BUNDLER_AUDIT_UPDATE_DISABLED \
BUNDLER_AUDIT_ADVISORY_DB_URL \
BUNDLER_AUDIT_ADVISORY_DB_REF_NAME \
+ RETIREJS_JS_ADVISORY_DB \
+ RETIREJS_NODE_ADVISORY_DB \
) \
--volume "$PWD:/code" \
--volume /var/run/docker.sock:/var/run/docker.sock \
diff --git a/lib/gitlab/ci/yaml_processor.rb b/lib/gitlab/ci/yaml_processor.rb
index ae3ff4a51e2..764047dae6d 100644
--- a/lib/gitlab/ci/yaml_processor.rb
+++ b/lib/gitlab/ci/yaml_processor.rb
@@ -57,7 +57,7 @@ module Gitlab
when: job[:when] || 'on_success',
environment: job[:environment_name],
coverage_regex: job[:coverage],
- yaml_variables: transform_to_yaml_variables(job_variables(name)),
+ yaml_variables: transform_to_yaml_variables(job[:variables]),
needs_attributes: job.dig(:needs, :job),
interruptible: job[:interruptible],
only: job[:only],
@@ -146,13 +146,6 @@ module Gitlab
end
end
- def job_variables(name)
- job_variables = @jobs.dig(name.to_sym, :variables)
-
- @variables.to_h
- .merge(job_variables.to_h)
- end
-
def transform_to_yaml_variables(variables)
variables.to_h.map do |key, value|
{ key: key.to_s, value: value, public: true }
diff --git a/lib/gitlab/config/entry/attributable.rb b/lib/gitlab/config/entry/attributable.rb
index 4deb233d10e..d266d5218de 100644
--- a/lib/gitlab/config/entry/attributable.rb
+++ b/lib/gitlab/config/entry/attributable.rb
@@ -10,7 +10,7 @@ module Gitlab
def attributes(*attributes)
attributes.flatten.each do |attribute|
if method_defined?(attribute)
- raise ArgumentError, "Method already defined: #{attribute}"
+ raise ArgumentError, "Method '#{attribute}' already defined in '#{name}'"
end
define_method(attribute) do
diff --git a/lib/gitlab/config/entry/configurable.rb b/lib/gitlab/config/entry/configurable.rb
index 3fd562c2904..571e7a5127e 100644
--- a/lib/gitlab/config/entry/configurable.rb
+++ b/lib/gitlab/config/entry/configurable.rb
@@ -76,7 +76,7 @@ module Gitlab
# rubocop: disable CodeReuse/ActiveRecord
def entry(key, entry, description: nil, default: nil, inherit: nil, reserved: nil, metadata: {})
entry_name = key.to_sym
- raise ArgumentError, "Entry #{key} already defined" if @nodes.to_h[entry_name]
+ raise ArgumentError, "Entry '#{key}' already defined in '#{name}'" if @nodes.to_h[entry_name]
factory = ::Gitlab::Config::Entry::Factory.new(entry)
.with(description: description)
@@ -98,8 +98,8 @@ module Gitlab
def helpers(*nodes, dynamic: false)
nodes.each do |symbol|
- if method_defined?("#{symbol}_defined?") || method_defined?("#{symbol}_value")
- raise ArgumentError, "Method #{symbol}_defined? or #{symbol}_value already defined"
+ if method_defined?("#{symbol}_defined?") || method_defined?("#{symbol}_entry") || method_defined?("#{symbol}_value")
+ raise ArgumentError, "Method '#{symbol}_defined?', '#{symbol}_entry' or '#{symbol}_value' already defined in '#{name}'"
end
unless @nodes.to_h[symbol]
@@ -110,10 +110,13 @@ module Gitlab
entries[symbol]&.specified?
end
- define_method("#{symbol}_value") do
- return unless entries[symbol] && entries[symbol].valid?
+ define_method("#{symbol}_entry") do
+ entries[symbol]
+ end
- entries[symbol].value
+ define_method("#{symbol}_value") do
+ entry = entries[symbol]
+ entry.value if entry&.valid?
end
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index e93052df7e0..18cfcea9335 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -21221,6 +21221,18 @@ msgstr ""
msgid "UpdateProject|Project could not be updated!"
msgstr ""
+msgid "UpdateRepositoryStorage|Error moving repository storage for %{project_full_path} - %{message}"
+msgstr ""
+
+msgid "UpdateRepositoryStorage|Failed to fetch %{type} repository as mirror"
+msgstr ""
+
+msgid "UpdateRepositoryStorage|Failed to verify %{type} repository checksum from %{old} to %{new}"
+msgstr ""
+
+msgid "UpdateRepositoryStorage|Timeout waiting for %{type} repository pushes"
+msgstr ""
+
msgid "Updated"
msgstr ""
diff --git a/scripts/trigger-build b/scripts/trigger-build
index 6359446ecd1..c7b45480bf3 100755
--- a/scripts/trigger-build
+++ b/scripts/trigger-build
@@ -176,11 +176,9 @@ module Trigger
edition = Trigger.ee? ? 'EE' : 'CE'
{
- # Back-compatibility until https://gitlab.com/gitlab-org/build/CNG/merge_requests/189 is merged
- "GITLAB_#{edition}_VERSION" => ENV['CI_COMMIT_REF_NAME'],
- "GITLAB_VERSION" => ENV['CI_COMMIT_REF_NAME'],
+ "GITLAB_VERSION" => ENV['CI_COMMIT_SHA'],
"GITLAB_TAG" => ENV['CI_COMMIT_TAG'],
- "GITLAB_ASSETS_TAG" => ENV['CI_COMMIT_TAG'] ? ENV['CI_COMMIT_REF_NAME'] : ENV['CI_COMMIT_REF_SLUG'],
+ "GITLAB_ASSETS_TAG" => ENV['CI_COMMIT_TAG'] ? ENV['CI_COMMIT_REF_NAME'] : ENV['CI_COMMIT_SHA'],
"FORCE_RAILS_IMAGE_BUILDS" => 'true',
"#{edition}_PIPELINE" => 'true'
}
diff --git a/spec/fixtures/ci_build_artifacts.zip b/spec/fixtures/ci_build_artifacts.zip
index dae976d918e..91ec9f7dcd0 100644
--- a/spec/fixtures/ci_build_artifacts.zip
+++ b/spec/fixtures/ci_build_artifacts.zip
Binary files differ
diff --git a/spec/lib/backup/manager_spec.rb b/spec/lib/backup/manager_spec.rb
index cee299522ce..b86e92d5969 100644
--- a/spec/lib/backup/manager_spec.rb
+++ b/spec/lib/backup/manager_spec.rb
@@ -319,18 +319,21 @@ describe Backup::Manager do
context 'when there is a non-tarred backup in the directory' do
before do
- allow(Dir).to receieve(:glob).and_return(
+ allow(Dir).to receive(:glob).and_return(
[
'backup_information.yml'
]
)
+ allow(File).to receive(:exist?).and_return(true)
+ end
+
+ it 'selects the non-tarred backup to restore from' do
+ expect(Kernel).not_to receive(:system)
- it 'selects the non-tarred backup to restore from' do
- expect { subject.unpack }.to output.to_stdout
- expect(progress).to have_received(:puts)
- .with(a_string_matching('Non tarred backup found '))
- expect(Kernel).not_to receive(:system)
- end
+ subject.unpack
+
+ expect(progress).to have_received(:puts)
+ .with(a_string_matching('Non tarred backup found '))
end
end
end
diff --git a/spec/lib/gitlab/ci/artifact_file_reader_spec.rb b/spec/lib/gitlab/ci/artifact_file_reader_spec.rb
new file mode 100644
index 00000000000..04017b9ae3e
--- /dev/null
+++ b/spec/lib/gitlab/ci/artifact_file_reader_spec.rb
@@ -0,0 +1,100 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Ci::ArtifactFileReader do
+ let(:job) { create(:ci_build) }
+ let(:path) { 'generated.yml' } # included in the ci_build_artifacts.zip
+
+ describe '#read' do
+ subject { described_class.new(job).read(path) }
+
+ context 'when job has artifacts and metadata' do
+ let!(:artifacts) { create(:ci_job_artifact, :archive, job: job) }
+ let!(:metadata) { create(:ci_job_artifact, :metadata, job: job) }
+
+ it 'returns the content at the path' do
+ is_expected.to be_present
+ expect(YAML.safe_load(subject).keys).to contain_exactly('rspec', 'time', 'custom')
+ end
+
+ context 'when path does not exist' do
+ let(:path) { 'file/does/not/exist.txt' }
+ let(:expected_error) do
+ "Path `#{path}` does not exist inside the `#{job.name}` artifacts archive!"
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(described_class::Error, expected_error)
+ end
+ end
+
+ context 'when path points to a directory' do
+ let(:path) { 'other_artifacts_0.1.2' }
+ let(:expected_error) do
+ "Path `#{path}` was expected to be a file but it was a directory!"
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(described_class::Error, expected_error)
+ end
+ end
+
+ context 'when path is nested' do
+ # path exists in ci_build_artifacts.zip
+ let(:path) { 'other_artifacts_0.1.2/doc_sample.txt' }
+
+ it 'returns the content at the nested path' do
+ is_expected.to be_present
+ end
+ end
+
+ context 'when artifact archive size is greater than the limit' do
+ let(:expected_error) do
+ "Artifacts archive for job `#{job.name}` is too large: max 1 KB"
+ end
+
+ before do
+ stub_const("#{described_class}::MAX_ARCHIVE_SIZE", 1.kilobyte)
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(described_class::Error, expected_error)
+ end
+ end
+
+ context 'when metadata entry shows size greater than the limit' do
+ let(:expected_error) do
+ "Artifacts archive for job `#{job.name}` is too large: max 5 MB"
+ end
+
+ before do
+ expect_next_instance_of(Gitlab::Ci::Build::Artifacts::Metadata::Entry) do |entry|
+ expect(entry).to receive(:total_size).and_return(10.megabytes)
+ end
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(described_class::Error, expected_error)
+ end
+ end
+ end
+
+ context 'when job does not have metadata artifacts' do
+ let!(:artifacts) { create(:ci_job_artifact, :archive, job: job) }
+ let(:expected_error) do
+ "Job `#{job.name}` has missing artifacts metadata and cannot be extracted!"
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(described_class::Error, expected_error)
+ end
+ end
+
+ context 'when job does not have artifacts' do
+ it 'raises ArgumentError' do
+ expect { subject }.to raise_error(ArgumentError, 'Job does not have artifacts')
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/config/entry/bridge_spec.rb b/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
index ad388886681..d08ce30618d 100644
--- a/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
@@ -106,6 +106,7 @@ describe Gitlab::Ci::Config::Entry::Bridge do
ignore: false,
stage: 'test',
only: { refs: %w[branches tags] },
+ variables: {},
scheduling_type: :stage)
end
end
@@ -128,6 +129,7 @@ describe Gitlab::Ci::Config::Entry::Bridge do
ignore: false,
stage: 'test',
only: { refs: %w[branches tags] },
+ variables: {},
scheduling_type: :stage)
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb
index 313b504ab59..7df0eccb3ed 100644
--- a/spec/lib/gitlab/ci/config/entry/job_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb
@@ -6,6 +6,7 @@ describe Gitlab::Ci::Config::Entry::Job do
let(:entry) { described_class.new(config, name: :rspec) }
it_behaves_like 'with inheritable CI config' do
+ let(:config) { { script: 'echo' } }
let(:inheritable_key) { 'default' }
let(:inheritable_class) { Gitlab::Ci::Config::Entry::Default }
@@ -15,6 +16,10 @@ describe Gitlab::Ci::Config::Entry::Job do
let(:ignored_inheritable_columns) do
%i[]
end
+
+ before do
+ allow(entry).to receive_message_chain(:inherit_entry, :default_value).and_return(true)
+ end
end
describe '.nodes' do
@@ -24,7 +29,8 @@ describe Gitlab::Ci::Config::Entry::Job do
let(:result) do
%i[before_script script stage type after_script cache
image services only except rules needs variables artifacts
- environment coverage retry interruptible timeout release tags]
+ environment coverage retry interruptible timeout release tags
+ inherit]
end
it { is_expected.to match_array result }
@@ -500,7 +506,13 @@ describe Gitlab::Ci::Config::Entry::Job do
let(:unspecified) { double('unspecified', 'specified?' => false) }
let(:default) { double('default', '[]' => unspecified) }
let(:workflow) { double('workflow', 'has_rules?' => false) }
- let(:deps) { double('deps', 'default' => default, '[]' => unspecified, 'workflow' => workflow) }
+
+ let(:deps) do
+ double('deps',
+ 'default_entry' => default,
+ 'workflow_entry' => workflow,
+ 'variables_value' => nil)
+ end
context 'when job config overrides default config' do
before do
diff --git a/spec/lib/gitlab/ci/config/entry/jobs_spec.rb b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
index c8c188d71bf..203342ab620 100644
--- a/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
@@ -99,6 +99,7 @@ describe Gitlab::Ci::Config::Entry::Jobs do
only: { refs: %w[branches tags] },
stage: 'test',
trigger: { project: 'my/project' },
+ variables: {},
scheduling_type: :stage
},
regular_job: {
diff --git a/spec/lib/gitlab/ci/config/entry/processable_spec.rb b/spec/lib/gitlab/ci/config/entry/processable_spec.rb
index 410aef1cd53..5c2c6520f25 100644
--- a/spec/lib/gitlab/ci/config/entry/processable_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/processable_spec.rb
@@ -7,6 +7,10 @@ describe Gitlab::Ci::Config::Entry::Processable do
Class.new(::Gitlab::Config::Entry::Node) do
include Gitlab::Ci::Config::Entry::Processable
+ entry :tags, ::Gitlab::Config::Entry::ArrayOfStrings,
+ description: 'Set the default tags.',
+ inherit: true
+
def self.name
'job'
end
@@ -189,14 +193,17 @@ describe Gitlab::Ci::Config::Entry::Processable do
end
describe '#compose!' do
- let(:specified) do
- double('specified', 'specified?' => true, value: 'specified')
- end
-
let(:unspecified) { double('unspecified', 'specified?' => false) }
let(:default) { double('default', '[]' => unspecified) }
let(:workflow) { double('workflow', 'has_rules?' => false) }
- let(:deps) { double('deps', 'default' => default, '[]' => unspecified, 'workflow' => workflow) }
+ let(:variables) { }
+
+ let(:deps) do
+ double('deps',
+ default_entry: default,
+ workflow_entry: workflow,
+ variables_value: variables)
+ end
context 'with workflow rules' do
using RSpec::Parameterized::TableSyntax
@@ -240,6 +247,84 @@ describe Gitlab::Ci::Config::Entry::Processable do
end
end
end
+
+ context 'with inheritance' do
+ context 'of variables' do
+ let(:config) do
+ { variables: { A: 'job', B: 'job' } }
+ end
+
+ before do
+ entry.compose!(deps)
+ end
+
+ context 'with only job variables' do
+ it 'does return defined variables' do
+ expect(entry.value).to include(
+ variables: { 'A' => 'job', 'B' => 'job' }
+ )
+ end
+ end
+
+ context 'when root yaml variables are used' do
+ let(:variables) do
+ Gitlab::Ci::Config::Entry::Variables.new(
+ A: 'root', C: 'root'
+ ).value
+ end
+
+ it 'does return all variables and overwrite them' do
+ expect(entry.value).to include(
+ variables: { 'A' => 'job', 'B' => 'job', 'C' => 'root' }
+ )
+ end
+
+ context 'when inherit of defaults is disabled' do
+ let(:config) do
+ {
+ variables: { A: 'job', B: 'job' },
+ inherit: { variables: false }
+ }
+ end
+
+ it 'does return only job variables' do
+ expect(entry.value).to include(
+ variables: { 'A' => 'job', 'B' => 'job' }
+ )
+ end
+ end
+ end
+ end
+
+ context 'of default:tags' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:default_tags, :tags, :inherit_default, :result) do
+ nil | %w[a b] | nil | %w[a b]
+ nil | %w[a b] | true | %w[a b]
+ nil | %w[a b] | false | %w[a b]
+ %w[b c] | %w[a b] | nil | %w[a b]
+ %w[b c] | %w[a b] | true | %w[a b]
+ %w[b c] | %w[a b] | false | %w[a b]
+ %w[b c] | nil | nil | %w[b c]
+ %w[b c] | nil | true | %w[b c]
+ %w[b c] | nil | false | nil
+ end
+
+ with_them do
+ let(:config) { { tags: tags, inherit: { default: inherit_default } } }
+ let(:default_specified_tags) { double('tags', 'specified?' => true, 'valid?' => true, 'value' => default_tags) }
+
+ before do
+ allow(default).to receive('[]').with(:tags).and_return(default_specified_tags)
+
+ entry.compose!(deps)
+ end
+
+ it { expect(entry.tags_value).to eq(result) }
+ end
+ end
+ end
end
context 'when composed' do
@@ -254,10 +339,12 @@ describe Gitlab::Ci::Config::Entry::Processable do
end
it 'returns correct value' do
- expect(entry.value)
- .to eq(name: :rspec,
- stage: 'test',
- only: { refs: %w[branches tags] })
+ expect(entry.value).to eq(
+ name: :rspec,
+ stage: 'test',
+ only: { refs: %w[branches tags] },
+ variables: {}
+ )
end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/root_spec.rb b/spec/lib/gitlab/ci/config/entry/root_spec.rb
index cf0a3cfa963..c3871b6b3cf 100644
--- a/spec/lib/gitlab/ci/config/entry/root_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/root_spec.rb
@@ -32,7 +32,7 @@ describe Gitlab::Ci::Config::Entry::Root do
image: 'ruby:2.2',
default: {},
services: ['postgres:9.1', 'mysql:5.5'],
- variables: { VAR: 'value' },
+ variables: { VAR: 'root' },
after_script: ['make clean'],
stages: %w(build pages release),
cache: { key: 'k', untracked: true, paths: ['public/'] },
@@ -42,6 +42,7 @@ describe Gitlab::Ci::Config::Entry::Root do
stage: 'release',
before_script: [],
after_script: [],
+ variables: { 'VAR' => 'job' },
script: ["make changelog | tee release_changelog.txt"],
release: {
tag_name: 'v0.06',
@@ -127,7 +128,7 @@ describe Gitlab::Ci::Config::Entry::Root do
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push' },
- variables: {},
+ variables: { 'VAR' => 'root' },
ignore: false,
after_script: ['make clean'],
only: { refs: %w[branches tags] },
@@ -141,7 +142,7 @@ describe Gitlab::Ci::Config::Entry::Root do
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push' },
- variables: {},
+ variables: { 'VAR' => 'root' },
ignore: false,
after_script: ['make clean'],
only: { refs: %w[branches tags] },
@@ -157,7 +158,7 @@ describe Gitlab::Ci::Config::Entry::Root do
services: [{ name: "postgres:9.1" }, { name: "mysql:5.5" }],
cache: { key: "k", untracked: true, paths: ["public/"], policy: "pull-push" },
only: { refs: %w(branches tags) },
- variables: {},
+ variables: { 'VAR' => 'job' },
after_script: [],
ignore: false,
scheduling_type: :stage }
@@ -175,11 +176,11 @@ describe Gitlab::Ci::Config::Entry::Root do
image: 'ruby:2.1',
services: ['postgres:9.1', 'mysql:5.5']
},
- variables: { VAR: 'value' },
+ variables: { VAR: 'root' },
stages: %w(build pages),
cache: { key: 'k', untracked: true, paths: ['public/'] },
rspec: { script: %w[rspec ls] },
- spinach: { before_script: [], variables: { VAR: 'AA' }, script: 'spinach' } }
+ spinach: { before_script: [], variables: { VAR: 'job' }, script: 'spinach' } }
end
context 'when composed' do
@@ -203,7 +204,7 @@ describe Gitlab::Ci::Config::Entry::Root do
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
cache: { key: 'k', untracked: true, paths: ['public/'], policy: "pull-push" },
- variables: {},
+ variables: { 'VAR' => 'root' },
ignore: false,
after_script: ['make clean'],
only: { refs: %w[branches tags] },
@@ -215,7 +216,7 @@ describe Gitlab::Ci::Config::Entry::Root do
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
cache: { key: 'k', untracked: true, paths: ['public/'], policy: "pull-push" },
- variables: { 'VAR' => 'AA' },
+ variables: { 'VAR' => 'job' },
ignore: false,
after_script: ['make clean'],
only: { refs: %w[branches tags] },
diff --git a/spec/lib/gitlab/ci/config/external/file/artifact_spec.rb b/spec/lib/gitlab/ci/config/external/file/artifact_spec.rb
new file mode 100644
index 00000000000..a8eb13c47bc
--- /dev/null
+++ b/spec/lib/gitlab/ci/config/external/file/artifact_spec.rb
@@ -0,0 +1,167 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Ci::Config::External::File::Artifact do
+ let(:parent_pipeline) { create(:ci_pipeline) }
+ let(:context) do
+ Gitlab::Ci::Config::External::Context.new(parent_pipeline: parent_pipeline)
+ end
+
+ let(:external_file) { described_class.new(params, context) }
+
+ describe '#matching?' do
+ context 'when params contain artifact location' do
+ let(:params) { { artifact: 'generated.yml' } }
+
+ it 'returns true' do
+ expect(external_file).to be_matching
+ end
+ end
+
+ context 'when params does not contain artifact location' do
+ let(:params) { {} }
+
+ it 'returns false' do
+ expect(external_file).not_to be_matching
+ end
+ end
+ end
+
+ describe '#valid?' do
+ shared_examples 'is invalid' do
+ it 'is not valid' do
+ expect(external_file).not_to be_valid
+ end
+
+ it 'sets the expected error' do
+ expect(external_file.errors)
+ .to contain_exactly(expected_error)
+ end
+ end
+
+ describe 'when used in non child pipeline context' do
+ let(:parent_pipeline) { nil }
+ let(:params) { { artifact: 'generated.yml' } }
+
+ let(:expected_error) do
+ 'Including configs from artifacts is only allowed when triggering child pipelines'
+ end
+
+ it_behaves_like 'is invalid'
+ end
+
+ context 'when used in child pipeline context' do
+ let(:parent_pipeline) { create(:ci_pipeline) }
+
+ context 'when job is not provided' do
+ let(:params) { { artifact: 'generated.yml' } }
+
+ let(:expected_error) do
+ 'Job must be provided when including configs from artifacts'
+ end
+
+ it_behaves_like 'is invalid'
+ end
+
+ context 'when job is provided' do
+ let(:params) { { artifact: 'generated.yml', job: 'generator' } }
+
+ context 'when job does not exist in the parent pipeline' do
+ let(:expected_error) do
+ 'Job `generator` not found in parent pipeline or does not have artifacts!'
+ end
+
+ it_behaves_like 'is invalid'
+ end
+
+ context 'when job exists in the parent pipeline' do
+ let!(:generator_job) { create(:ci_build, name: 'generator', pipeline: parent_pipeline) }
+
+ context 'when job does not have artifacts' do
+ let(:expected_error) do
+ 'Job `generator` not found in parent pipeline or does not have artifacts!'
+ end
+
+ it_behaves_like 'is invalid'
+ end
+
+ context 'when job has archive artifacts' do
+ let!(:artifacts) do
+ create(:ci_job_artifact, :archive,
+ job: generator_job,
+ file: fixture_file_upload(Rails.root.join('spec/fixtures/pages.zip'), 'application/zip'))
+ end
+
+ let(:expected_error) do
+ 'Job `generator` has missing artifacts metadata and cannot be extracted!'
+ end
+
+ it_behaves_like 'is invalid'
+
+ context 'when job has artifacts exceeding the max allowed size' do
+ let(:expected_error) do
+ "Artifacts archive for job `generator` is too large: max 1 KB"
+ end
+
+ before do
+ stub_const("#{Gitlab::Ci::ArtifactFileReader}::MAX_ARCHIVE_SIZE", 1.kilobyte)
+ end
+
+ it_behaves_like 'is invalid'
+ end
+
+ context 'when job has artifacts metadata' do
+ let!(:metadata) do
+ create(:ci_job_artifact, :metadata, job: generator_job)
+ end
+
+ let(:expected_error) do
+ 'Path `generated.yml` does not exist inside the `generator` artifacts archive!'
+ end
+
+ it_behaves_like 'is invalid'
+
+ context 'when file is found in metadata' do
+ let!(:artifacts) { create(:ci_job_artifact, :archive, job: generator_job) }
+ let!(:metadata) { create(:ci_job_artifact, :metadata, job: generator_job) }
+
+ context 'when file is empty' do
+ before do
+ allow_next_instance_of(Gitlab::Ci::ArtifactFileReader) do |reader|
+ allow(reader).to receive(:read).and_return('')
+ end
+ end
+
+ let(:expected_error) do
+ 'File `generated.yml` is empty!'
+ end
+
+ it_behaves_like 'is invalid'
+ end
+
+ context 'when file is not empty' do
+ it 'is valid' do
+ expect(external_file).to be_valid
+ expect(external_file.content).to be_present
+ end
+
+ it 'propagates parent_pipeline to nested includes' do
+ expected_attrs = {
+ parent_pipeline: parent_pipeline,
+ project: anything,
+ sha: anything,
+ user: anything
+ }
+ expect(context).to receive(:mutate).with(expected_attrs).and_call_original
+ external_file.content
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/config/external/file/local_spec.rb b/spec/lib/gitlab/ci/config/external/file/local_spec.rb
index 53205a18762..c9851239859 100644
--- a/spec/lib/gitlab/ci/config/external/file/local_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/local_spec.rb
@@ -6,10 +6,19 @@ describe Gitlab::Ci::Config::External::File::Local do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
let(:sha) { '12345' }
- let(:context_params) { { project: project, sha: sha, user: user } }
let(:context) { Gitlab::Ci::Config::External::Context.new(**context_params) }
let(:params) { { local: location } }
let(:local_file) { described_class.new(params, context) }
+ let(:parent_pipeline) { double(:parent_pipeline) }
+
+ let(:context_params) do
+ {
+ project: project,
+ sha: sha,
+ user: user,
+ parent_pipeline: parent_pipeline
+ }
+ end
before do
allow_any_instance_of(Gitlab::Ci::Config::External::Context)
@@ -117,7 +126,11 @@ describe Gitlab::Ci::Config::External::File::Local do
subject { local_file.send(:expand_context_attrs) }
it 'inherits project, user and sha' do
- is_expected.to include(user: user, project: project, sha: sha)
+ is_expected.to include(
+ user: user,
+ project: project,
+ sha: sha,
+ parent_pipeline: parent_pipeline)
end
end
diff --git a/spec/lib/gitlab/ci/config/external/file/project_spec.rb b/spec/lib/gitlab/ci/config/external/file/project_spec.rb
index 77a71f9972b..b2924ae9d91 100644
--- a/spec/lib/gitlab/ci/config/external/file/project_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/project_spec.rb
@@ -7,10 +7,19 @@ describe Gitlab::Ci::Config::External::File::Project do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
let(:context_user) { user }
- let(:context_params) { { project: context_project, sha: '12345', user: context_user } }
+ let(:parent_pipeline) { double(:parent_pipeline) }
let(:context) { Gitlab::Ci::Config::External::Context.new(**context_params) }
let(:project_file) { described_class.new(params, context) }
+ let(:context_params) do
+ {
+ project: context_project,
+ sha: '12345',
+ user: context_user,
+ parent_pipeline: parent_pipeline
+ }
+ end
+
before do
project.add_developer(user)
@@ -152,7 +161,11 @@ describe Gitlab::Ci::Config::External::File::Project do
subject { project_file.send(:expand_context_attrs) }
it 'inherits user, and target project and sha' do
- is_expected.to include(user: user, project: project, sha: project.commit('master').id)
+ is_expected.to include(
+ user: user,
+ project: project,
+ sha: project.commit('master').id,
+ parent_pipeline: parent_pipeline)
end
end
diff --git a/spec/lib/gitlab/ci/config_spec.rb b/spec/lib/gitlab/ci/config_spec.rb
index 525335cfea9..82ca8a29c5a 100644
--- a/spec/lib/gitlab/ci/config_spec.rb
+++ b/spec/lib/gitlab/ci/config_spec.rb
@@ -376,23 +376,6 @@ describe Gitlab::Ci::Config do
end
end
- context 'when context expansion timeout is disabled' do
- before do
- allow_next_instance_of(Gitlab::Ci::Config::External::Context) do |instance|
- allow(instance).to receive(:check_execution_time!).and_call_original
- end
-
- allow(Feature)
- .to receive(:enabled?)
- .with(:ci_limit_yaml_expansion, project, default_enabled: true)
- .and_return(false)
- end
-
- it 'does not raises errors' do
- expect { config }.not_to raise_error
- end
- end
-
describe 'external file version' do
context 'when external local file SHA is defined' do
it 'is using a defined value' do
@@ -541,5 +524,76 @@ describe Gitlab::Ci::Config do
end
end
end
+
+ context 'when including file from artifact' do
+ let(:config) do
+ described_class.new(
+ gitlab_ci_yml,
+ project: nil,
+ sha: nil,
+ user: nil,
+ parent_pipeline: parent_pipeline)
+ end
+
+ let(:gitlab_ci_yml) do
+ <<~HEREDOC
+ include:
+ - artifact: generated.yml
+ job: rspec
+ HEREDOC
+ end
+
+ let(:parent_pipeline) { nil }
+
+ context 'when used in the context of a child pipeline' do
+ # This job has ci_build_artifacts.zip artifact archive which
+ # contains generated.yml
+ let!(:job) { create(:ci_build, :artifacts, name: 'rspec', pipeline: parent_pipeline) }
+ let(:parent_pipeline) { create(:ci_pipeline) }
+
+ it 'returns valid config' do
+ expect(config).to be_valid
+ end
+
+ context 'when job key is missing' do
+ let(:gitlab_ci_yml) do
+ <<~HEREDOC
+ include:
+ - artifact: generated.yml
+ HEREDOC
+ end
+
+ it 'raises an error' do
+ expect { config }.to raise_error(
+ described_class::ConfigError,
+ 'Job must be provided when including configs from artifacts'
+ )
+ end
+ end
+
+ context 'when artifact key is missing' do
+ let(:gitlab_ci_yml) do
+ <<~HEREDOC
+ include:
+ - job: rspec
+ HEREDOC
+ end
+
+ it 'raises an error' do
+ expect { config }.to raise_error(
+ described_class::ConfigError,
+ /needs to match exactly one accessor!/
+ )
+ end
+ end
+ end
+
+ it 'disallows the use in parent pipelines' do
+ expect { config }.to raise_error(
+ described_class::ConfigError,
+ 'Including configs from artifacts is only allowed when triggering child pipelines'
+ )
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index e303557bd00..5c85a136972 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -509,28 +509,44 @@ module Gitlab
describe "before_script" do
context "in global context" do
- let(:config) do
- {
- before_script: ["global script"],
- test: { script: ["script"] }
- }
+ using RSpec::Parameterized::TableSyntax
+
+ where(:inherit, :result) do
+ nil | ["global script"]
+ { default: false } | nil
+ { default: true } | ["global script"]
end
- it "return commands with scripts concatenated" do
- expect(subject[:options][:before_script]).to eq(["global script"])
+ with_them do
+ let(:config) do
+ {
+ before_script: ["global script"],
+ test: { script: ["script"], inherit: inherit }
+ }
+ end
+
+ it { expect(subject[:options][:before_script]).to eq(result) }
end
end
context "in default context" do
- let(:config) do
- {
- default: { before_script: ["global script"] },
- test: { script: ["script"] }
- }
+ using RSpec::Parameterized::TableSyntax
+
+ where(:inherit, :result) do
+ nil | ["global script"]
+ { default: false } | nil
+ { default: true } | ["global script"]
end
- it "return commands with scripts concatenated" do
- expect(subject[:options][:before_script]).to eq(["global script"])
+ with_them do
+ let(:config) do
+ {
+ default: { before_script: ["global script"] },
+ test: { script: ["script"], inherit: inherit }
+ }
+ end
+
+ it { expect(subject[:options][:before_script]).to eq(result) }
end
end
@@ -793,7 +809,7 @@ module Gitlab
context 'when job and global variables are defined' do
let(:global_variables) do
- { 'VAR1' => 'global1', 'VAR3' => 'global3' }
+ { 'VAR1' => 'global1', 'VAR3' => 'global3', 'VAR4' => 'global4' }
end
let(:job_variables) do
{ 'VAR1' => 'value1', 'VAR2' => 'value2' }
@@ -802,16 +818,32 @@ module Gitlab
{
before_script: ['pwd'],
variables: global_variables,
- rspec: { script: 'rspec', variables: job_variables }
+ rspec: { script: 'rspec', variables: job_variables, inherit: inherit }
}
end
- it 'returns all unique variables' do
- expect(subject).to contain_exactly(
- { key: 'VAR3', value: 'global3', public: true },
- { key: 'VAR1', value: 'value1', public: true },
- { key: 'VAR2', value: 'value2', public: true }
- )
+ context 'when no inheritance is specified' do
+ let(:inherit) { }
+
+ it 'returns all unique variables' do
+ expect(subject).to contain_exactly(
+ { key: 'VAR4', value: 'global4', public: true },
+ { key: 'VAR3', value: 'global3', public: true },
+ { key: 'VAR1', value: 'value1', public: true },
+ { key: 'VAR2', value: 'value2', public: true }
+ )
+ end
+ end
+
+ context 'when inheritance is disabled' do
+ let(:inherit) { { variables: false } }
+
+ it 'does not inherit variables' do
+ expect(subject).to contain_exactly(
+ { key: 'VAR1', value: 'value1', public: true },
+ { key: 'VAR2', value: 'value2', public: true }
+ )
+ end
end
end
diff --git a/spec/lib/gitlab/config/entry/attributable_spec.rb b/spec/lib/gitlab/config/entry/attributable_spec.rb
index bc29a194181..64a4670f483 100644
--- a/spec/lib/gitlab/config/entry/attributable_spec.rb
+++ b/spec/lib/gitlab/config/entry/attributable_spec.rb
@@ -59,7 +59,7 @@ describe Gitlab::Config::Entry::Attributable do
end
end
- expectation.to raise_error(ArgumentError, 'Method already defined: length')
+ expectation.to raise_error(ArgumentError, /Method 'length' already defined in/)
end
end
end
diff --git a/spec/models/ci/job_artifact_spec.rb b/spec/models/ci/job_artifact_spec.rb
index 8f56d735f36..0a7a44b225c 100644
--- a/spec/models/ci/job_artifact_spec.rb
+++ b/spec/models/ci/job_artifact_spec.rb
@@ -25,7 +25,7 @@ describe Ci::JobArtifact do
end
it_behaves_like 'UpdateProjectStatistics' do
- subject { build(:ci_job_artifact, :archive, size: 106365) }
+ subject { build(:ci_job_artifact, :archive, size: 107464) }
end
end
@@ -35,7 +35,7 @@ describe Ci::JobArtifact do
end
it_behaves_like 'UpdateProjectStatistics' do
- subject { build(:ci_job_artifact, :archive, size: 106365) }
+ subject { build(:ci_job_artifact, :archive, size: 107464) }
end
end
@@ -173,7 +173,7 @@ describe Ci::JobArtifact do
let(:artifact) { create(:ci_job_artifact, :archive, project: project) }
it 'sets the size from the file size' do
- expect(artifact.size).to eq(106365)
+ expect(artifact.size).to eq(107464)
end
end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 76051ecb177..f775906a545 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -2553,6 +2553,19 @@ describe Ci::Pipeline, :mailer do
end
end
+ describe '#find_job_with_archive_artifacts' do
+ let!(:old_job) { create(:ci_build, name: 'rspec', retried: true, pipeline: pipeline) }
+ let!(:job_without_artifacts) { create(:ci_build, name: 'rspec', pipeline: pipeline) }
+ let!(:expected_job) { create(:ci_build, :artifacts, name: 'rspec', pipeline: pipeline ) }
+ let!(:different_job) { create(:ci_build, name: 'deploy', pipeline: pipeline) }
+
+ subject { pipeline.find_job_with_archive_artifacts('rspec') }
+
+ it 'finds the expected job' do
+ expect(subject).to eq(expected_job)
+ end
+ end
+
describe '#latest_builds_with_artifacts' do
let!(:fresh_build) { create(:ci_build, :success, :artifacts, pipeline: pipeline) }
let!(:stale_build) { create(:ci_build, :success, :expired, :artifacts, pipeline: pipeline) }
diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb
index 87ace7b51f4..95807f5f0c1 100644
--- a/spec/models/snippet_spec.rb
+++ b/spec/models/snippet_spec.rb
@@ -511,6 +511,32 @@ describe Snippet do
end
end
+ describe '#blobs' do
+ let(:snippet) { create(:snippet) }
+
+ context 'when repository does not exist' do
+ it 'returns empty array' do
+ expect(snippet.blobs).to be_empty
+ end
+ end
+
+ context 'when repository exists' do
+ let(:snippet) { create(:snippet, :repository) }
+
+ it 'returns array of blobs' do
+ expect(snippet.blobs).to all(be_a(Blob))
+ end
+ end
+
+ it 'returns a blob representing the snippet data' do
+ blob = snippet.blob
+
+ expect(blob).to be_a(Blob)
+ expect(blob.path).to eq(snippet.file_name)
+ expect(blob.data).to eq(snippet.content)
+ end
+ end
+
describe '#to_json' do
let(:snippet) { build(:snippet) }
diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb
index e76ab8d409b..6e5c2088ee7 100644
--- a/spec/requests/api/runner_spec.rb
+++ b/spec/requests/api/runner_spec.rb
@@ -756,7 +756,7 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
expect(json_response['dependencies'].count).to eq(1)
expect(json_response['dependencies']).to include(
{ 'id' => job.id, 'name' => job.name, 'token' => job.token,
- 'artifacts_file' => { 'filename' => 'ci_build_artifacts.zip', 'size' => 106365 } })
+ 'artifacts_file' => { 'filename' => 'ci_build_artifacts.zip', 'size' => 107464 } })
end
end
diff --git a/spec/services/ci/create_pipeline_service/custom_config_content_spec.rb b/spec/services/ci/create_pipeline_service/custom_config_content_spec.rb
index 2657f1d300a..112b19fcbc5 100644
--- a/spec/services/ci/create_pipeline_service/custom_config_content_spec.rb
+++ b/spec/services/ci/create_pipeline_service/custom_config_content_spec.rb
@@ -4,30 +4,77 @@ require 'spec_helper'
describe Ci::CreatePipelineService do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:admin) }
- let(:upstream_pipeline) { create(:ci_pipeline) }
let(:ref) { 'refs/heads/master' }
let(:service) { described_class.new(project, user, { ref: ref }) }
+ let(:upstream_pipeline) { create(:ci_pipeline, project: project) }
+ let(:bridge) { create(:ci_bridge, pipeline: upstream_pipeline) }
+
+ subject { service.execute(:push, bridge: bridge) }
+
context 'custom config content' do
let(:bridge) do
create(:ci_bridge, status: 'running', pipeline: upstream_pipeline, project: upstream_pipeline.project).tap do |bridge|
- allow(bridge).to receive(:yaml_for_downstream).and_return(
- <<~YML
- rspec:
- script: rspec
- custom:
- script: custom
- YML
- )
+ allow(bridge).to receive(:yaml_for_downstream).and_return(config_from_bridge)
end
end
- subject { service.execute(:push, bridge: bridge) }
+ let(:config_from_bridge) do
+ <<~YML
+ rspec:
+ script: rspec
+ custom:
+ script: custom
+ YML
+ end
+
+ before do
+ allow(bridge).to receive(:yaml_for_downstream).and_return config_from_bridge
+ end
it 'creates a pipeline using the content passed in as param' do
expect(subject).to be_persisted
expect(subject.builds.map(&:name)).to eq %w[rspec custom]
expect(subject.config_source).to eq 'bridge_source'
end
+
+ context 'when bridge includes yaml from artifact' do
+ # the generated.yml is available inside the ci_build_artifacts.zip associated
+ # to the generator_job
+ let(:config_from_bridge) do
+ <<~YML
+ include:
+ - artifact: generated.yml
+ job: generator
+ YML
+ end
+
+ context 'when referenced job exists' do
+ let!(:generator_job) do
+ create(:ci_build, :artifacts,
+ project: project,
+ pipeline: upstream_pipeline,
+ name: 'generator')
+ end
+
+ it 'created a pipeline using the content passed in as param and download the artifact' do
+ expect(subject).to be_persisted
+ expect(subject.builds.pluck(:name)).to eq %w[rspec time custom]
+ expect(subject.config_source).to eq 'bridge_source'
+ end
+ end
+
+ context 'when referenced job does not exist' do
+ it 'creates an empty pipeline' do
+ expect(subject).to be_persisted
+ expect(subject).to be_failed
+ expect(subject.errors.full_messages)
+ .to contain_exactly(
+ 'Job `generator` not found in parent pipeline or does not have artifacts!')
+ expect(subject.builds.pluck(:name)).to be_empty
+ expect(subject.config_source).to eq 'bridge_source'
+ end
+ end
+ end
end
end
diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb
index 12c51d01d63..cbf7a135c41 100644
--- a/spec/services/projects/fork_service_spec.rb
+++ b/spec/services/projects/fork_service_spec.rb
@@ -315,6 +315,7 @@ describe Projects::ForkService do
# Stub everything required to move a project to a Gitaly shard that does not exist
stub_storage_settings('test_second_storage' => { 'path' => 'tmp/tests/second_storage' })
allow_any_instance_of(Gitlab::Git::Repository).to receive(:fetch_repository_as_mirror).and_return(true)
+ allow_any_instance_of(Gitlab::Git::Repository).to receive(:checksum).and_return(::Gitlab::Git::BLANK_SHA)
Projects::UpdateRepositoryStorageService.new(project).execute('test_second_storage')
fork_after_move = fork_project(project)
diff --git a/spec/services/projects/update_repository_storage_service_spec.rb b/spec/services/projects/update_repository_storage_service_spec.rb
index a0917f718e6..2e9a4626abb 100644
--- a/spec/services/projects/update_repository_storage_service_spec.rb
+++ b/spec/services/projects/update_repository_storage_service_spec.rb
@@ -16,6 +16,15 @@ describe Projects::UpdateRepositoryStorageService do
context 'without wiki and design repository' do
let(:project) { create(:project, :repository, repository_read_only: true, wiki_enabled: false) }
+ let!(:checksum) { project.repository.checksum }
+ let(:project_repository_double) { double(:repository) }
+
+ before do
+ allow(Gitlab::Git::Repository).to receive(:new).and_call_original
+ allow(Gitlab::Git::Repository).to receive(:new)
+ .with('test_second_storage', project.repository.raw.relative_path, project.repository.gl_repository, project.repository.full_path)
+ .and_return(project_repository_double)
+ end
context 'when the move succeeds' do
it 'moves the repository to the new storage and unmarks the repository as read only' do
@@ -23,10 +32,14 @@ describe Projects::UpdateRepositoryStorageService do
project.repository.path_to_repo
end
- expect_any_instance_of(Gitlab::Git::Repository).to receive(:fetch_repository_as_mirror)
+ expect(project_repository_double).to receive(:fetch_repository_as_mirror)
.with(project.repository.raw).and_return(true)
+ expect(project_repository_double).to receive(:checksum)
+ .and_return(checksum)
+
+ result = subject.execute('test_second_storage')
- subject.execute('test_second_storage')
+ expect(result[:status]).to eq(:success)
expect(project).not_to be_repository_read_only
expect(project.repository_storage).to eq('test_second_storage')
expect(gitlab_shell.repository_exists?('default', old_path)).to be(false)
@@ -44,16 +57,50 @@ describe Projects::UpdateRepositoryStorageService do
context 'when the move fails' do
it 'unmarks the repository as read-only without updating the repository storage' do
- expect_any_instance_of(Gitlab::Git::Repository).to receive(:fetch_repository_as_mirror)
+ expect(project_repository_double).to receive(:fetch_repository_as_mirror)
.with(project.repository.raw).and_return(false)
expect(GitlabShellWorker).not_to receive(:perform_async)
- subject.execute('test_second_storage')
+ result = subject.execute('test_second_storage')
+ expect(result[:status]).to eq(:error)
expect(project).not_to be_repository_read_only
expect(project.repository_storage).to eq('default')
end
end
+
+ context 'when the checksum does not match' do
+ it 'unmarks the repository as read-only without updating the repository storage' do
+ expect(project_repository_double).to receive(:fetch_repository_as_mirror)
+ .with(project.repository.raw).and_return(true)
+ expect(project_repository_double).to receive(:checksum)
+ .and_return('not matching checksum')
+ expect(GitlabShellWorker).not_to receive(:perform_async)
+
+ result = subject.execute('test_second_storage')
+
+ expect(result[:status]).to eq(:error)
+ expect(project).not_to be_repository_read_only
+ expect(project.repository_storage).to eq('default')
+ end
+ end
+
+ context 'when a object pool was joined' do
+ let!(:pool) { create(:pool_repository, :ready, source_project: project) }
+
+ it 'leaves the pool' do
+ expect(project_repository_double).to receive(:fetch_repository_as_mirror)
+ .with(project.repository.raw).and_return(true)
+ expect(project_repository_double).to receive(:checksum)
+ .and_return(checksum)
+
+ result = subject.execute('test_second_storage')
+
+ expect(result[:status]).to eq(:success)
+ expect(project.repository_storage).to eq('test_second_storage')
+ expect(project.reload_pool_repository).to be_nil
+ end
+ end
end
context 'with wiki repository' do
@@ -66,18 +113,5 @@ describe Projects::UpdateRepositoryStorageService do
end
end
end
-
- context 'when a object pool was joined' do
- let(:project) { create(:project, :repository, wiki_enabled: false, repository_read_only: true) }
- let(:pool) { create(:pool_repository, :ready, source_project: project) }
-
- it 'leaves the pool' do
- allow_any_instance_of(Gitlab::Git::Repository).to receive(:fetch_repository_as_mirror).and_return(true)
-
- subject.execute('test_second_storage')
-
- expect(project.reload_pool_repository).to be_nil
- end
- end
end
end
diff --git a/spec/support/shared_examples/lib/gitlab/config/inheritable_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/config/inheritable_shared_examples.rb
index 556d81133bc..95772b1774a 100644
--- a/spec/support/shared_examples/lib/gitlab/config/inheritable_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/config/inheritable_shared_examples.rb
@@ -53,7 +53,7 @@ RSpec.shared_examples 'with inheritable CI config' do
let(:deps) do
if inheritable_key
- double('deps', inheritable_key => inheritable, '[]' => unspecified)
+ double('deps', "#{inheritable_key}_entry" => inheritable, '[]' => unspecified)
else
inheritable
end
@@ -68,7 +68,7 @@ RSpec.shared_examples 'with inheritable CI config' do
it 'does inherit value' do
expect(inheritable).to receive('[]').with(entry_key).and_return(specified)
- entry.compose!(deps)
+ entry.send(:inherit!, deps)
expect(entry[entry_key]).to eq(specified)
end
@@ -86,7 +86,7 @@ RSpec.shared_examples 'with inheritable CI config' do
expect do
# we ignore exceptions as `#overwrite_entry`
# can raise exception on duplicates
- entry.compose!(deps) rescue described_class::InheritError
+ entry.send(:inherit!, deps) rescue described_class::InheritError
end.not_to change { entry[entry_key] }
end
end
@@ -94,7 +94,7 @@ RSpec.shared_examples 'with inheritable CI config' do
context 'when inheritable does not specify' do
it 'does not inherit value' do
- entry.compose!(deps)
+ entry.send(:inherit!, deps)
expect(entry[entry_key]).to be_a(
Gitlab::Config::Entry::Undefined)
diff --git a/spec/support/shared_examples/services/projects/update_repository_storage_service_shared_examples.rb b/spec/support/shared_examples/services/projects/update_repository_storage_service_shared_examples.rb
index f222dff60ab..6f83f52d54b 100644
--- a/spec/support/shared_examples/services/projects/update_repository_storage_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/projects/update_repository_storage_service_shared_examples.rb
@@ -2,7 +2,10 @@
RSpec.shared_examples 'moves repository to another storage' do |repository_type|
let(:project_repository_double) { double(:repository) }
+ let!(:project_repository_checksum) { project.repository.checksum }
+
let(:repository_double) { double(:repository) }
+ let(:repository_checksum) { repository.checksum }
before do
# Default stub for non-specified params
@@ -19,15 +22,16 @@ RSpec.shared_examples 'moves repository to another storage' do |repository_type|
context 'when the move succeeds', :clean_gitlab_redis_shared_state do
before do
- allow(project_repository_double)
- .to receive(:fetch_repository_as_mirror)
+ allow(project_repository_double).to receive(:fetch_repository_as_mirror)
.with(project.repository.raw)
.and_return(true)
+ allow(project_repository_double).to receive(:checksum)
+ .and_return(project_repository_checksum)
- allow(repository_double)
- .to receive(:fetch_repository_as_mirror)
- .with(repository.raw)
- .and_return(true)
+ allow(repository_double).to receive(:fetch_repository_as_mirror)
+ .with(repository.raw).and_return(true)
+ allow(repository_double).to receive(:checksum)
+ .and_return(repository_checksum)
end
it "moves the project and its #{repository_type} repository to the new storage and unmarks the repository as read only" do
@@ -37,8 +41,9 @@ RSpec.shared_examples 'moves repository to another storage' do |repository_type|
old_repository_path = repository.full_path
- subject.execute('test_second_storage')
+ result = subject.execute('test_second_storage')
+ expect(result[:status]).to eq(:success)
expect(project).not_to be_repository_read_only
expect(project.repository_storage).to eq('test_second_storage')
expect(gitlab_shell.repository_exists?('default', old_project_repository_path)).to be(false)
@@ -87,13 +92,38 @@ RSpec.shared_examples 'moves repository to another storage' do |repository_type|
it 'unmarks the repository as read-only without updating the repository storage' do
allow(project_repository_double).to receive(:fetch_repository_as_mirror)
.with(project.repository.raw).and_return(true)
+ allow(project_repository_double).to receive(:checksum)
+ .and_return(project_repository_checksum)
allow(repository_double).to receive(:fetch_repository_as_mirror)
.with(repository.raw).and_return(false)
expect(GitlabShellWorker).not_to receive(:perform_async)
- subject.execute('test_second_storage')
+ result = subject.execute('test_second_storage')
+
+ expect(result[:status]).to eq(:error)
+ expect(project).not_to be_repository_read_only
+ expect(project.repository_storage).to eq('default')
+ end
+ end
+
+ context "when the checksum of the #{repository_type} repository does not match" do
+ it 'unmarks the repository as read-only without updating the repository storage' do
+ allow(project_repository_double).to receive(:fetch_repository_as_mirror)
+ .with(project.repository.raw).and_return(true)
+ allow(project_repository_double).to receive(:checksum)
+ .and_return(project_repository_checksum)
+
+ allow(repository_double).to receive(:fetch_repository_as_mirror)
+ .with(repository.raw).and_return(true)
+ allow(repository_double).to receive(:checksum)
+ .and_return('not matching checksum')
+
+ expect(GitlabShellWorker).not_to receive(:perform_async)
+
+ result = subject.execute('test_second_storage')
+ expect(result[:status]).to eq(:error)
expect(project).not_to be_repository_read_only
expect(project.repository_storage).to eq('default')
end
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index 72e423db611..2a2d0f5a857 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -421,17 +421,35 @@ describe PostReceive do
perform
end
end
+
+ it 'updates the snippet db information' do
+ blob = snippet.blobs.first
+
+ expect(snippet).to receive(:update).with(file_name: blob.path, content: blob.data)
+
+ perform
+ end
+
+ context 'when snippet does not have any blob' do
+ it 'does not update snippet db information' do
+ allow(snippet).to receive(:blobs).and_return([])
+
+ expect(snippet).not_to receive(:update)
+
+ perform
+ end
+ end
end
end
context 'with PersonalSnippet' do
- let!(:snippet) { create(:personal_snippet, author: project.owner) }
+ let!(:snippet) { create(:personal_snippet, :repository, author: project.owner) }
it_behaves_like 'snippet changes actions'
end
context 'with ProjectSnippet' do
- let!(:snippet) { create(:project_snippet, project: project, author: project.owner) }
+ let!(:snippet) { create(:project_snippet, :repository, project: project, author: project.owner) }
it_behaves_like 'snippet changes actions'
end