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--GITLAB_PAGES_VERSION2
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue117
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/components/subnet_dropdown.vue0
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/components/vpc_dropdown.vue0
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/services/aws_services_facade.js41
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/store/actions.js8
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/store/cluster_dropdown/actions.js4
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/store/index.js8
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/store/mutation_types.js3
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/store/mutations.js6
-rw-r--r--app/controllers/concerns/uploads_actions.rb2
-rw-r--r--app/models/ci/pipeline_schedule.rb2
-rw-r--r--app/models/ci/trigger.rb2
-rw-r--r--app/models/clusters/concerns/application_core.rb2
-rw-r--r--app/models/commit_collection.rb11
-rw-r--r--app/models/upload.rb45
-rw-r--r--app/uploaders/avatar_uploader.rb2
-rw-r--r--app/uploaders/gitlab_uploader.rb11
-rw-r--r--app/workers/import_issues_csv_worker.rb2
-rw-r--r--app/workers/object_storage/background_move_worker.rb2
-rw-r--r--app/workers/object_storage/migrate_uploads_worker.rb2
-rw-r--r--changelogs/unreleased/ac-pull-mirror-branch-prefix.yml5
-rw-r--r--changelogs/unreleased/add-sorting-to-packages-list.yml5
-rw-r--r--changelogs/unreleased/bvl-fix-view-mr-deleted-repo.yml5
-rw-r--r--changelogs/unreleased/pages-1-11-0.yml5
-rw-r--r--com/lib/com/gitlab/patch/draw_route.rb16
-rw-r--r--com/spec/lib/gitlab/patch/draw_route_spec.rb25
-rw-r--r--config/application.rb10
-rw-r--r--config/initializers/0_inject_com_module.rb26
-rw-r--r--config/light_settings.rb32
-rw-r--r--db/migrate/20190924124627_add_pull_mirror_branch_prefix_to_projects.rb9
-rw-r--r--db/schema.rb1
-rw-r--r--lib/gitlab.rb13
-rw-r--r--lib/gitlab/background_migration/legacy_upload_mover.rb2
-rw-r--r--lib/gitlab/import_export/import_export.yml1
-rw-r--r--lib/gitlab/import_export/uploads_manager.rb2
-rw-r--r--lib/gitlab/patch/draw_route.rb7
-rw-r--r--lib/gitlab/sanitizers/exif.rb2
-rw-r--r--lib/gitlab/verify/uploads.rb2
-rw-r--r--locale/gitlab.pot63
-rw-r--r--spec/com_spec_helper.rb3
-rw-r--r--spec/factories/uploads.rb25
-rw-r--r--spec/fast_spec_helper.rb2
-rw-r--r--spec/features/merge_request/user_views_merge_request_from_deleted_fork_spec.rb31
-rw-r--r--spec/frontend/commit/__snapshots__/commit_pipeline_status_component_spec.js.snap39
-rw-r--r--spec/frontend/commit/commit_pipeline_status_component_spec.js39
-rw-r--r--spec/frontend/create_cluster/eks_cluster/components/eks_cluster_configuration_form_spec.js127
-rw-r--r--spec/frontend/create_cluster/eks_cluster/store/actions_spec.js27
-rw-r--r--spec/frontend/create_cluster/eks_cluster/store/mutations_spec.js9
-rw-r--r--spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/legacy_uploads_migrator_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/uploads_manager_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/uploads_restorer_spec.rb4
-rw-r--r--spec/lib/gitlab/sanitizers/exif_spec.rb2
-rw-r--r--spec/lib/gitlab_spec.rb12
-rw-r--r--spec/models/commit_collection_spec.rb11
-rw-r--r--spec/models/upload_spec.rb48
-rw-r--r--spec/models/uploads/fog_spec.rb2
-rw-r--r--spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/with_uploads_shared_examples.rb3
-rw-r--r--spec/uploaders/file_uploader_spec.rb10
-rw-r--r--spec/uploaders/gitlab_uploader_spec.rb10
-rw-r--r--spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb18
63 files changed, 795 insertions, 138 deletions
diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION
index 81c871de46b..1cac385c6cb 100644
--- a/GITLAB_PAGES_VERSION
+++ b/GITLAB_PAGES_VERSION
@@ -1 +1 @@
-1.10.0
+1.11.0
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue b/app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue
index 7ed51068d42..6f6b9ad025a 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue
+++ b/app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue
@@ -1,39 +1,92 @@
<script>
import { createNamespacedHelpers, mapState, mapActions } from 'vuex';
+import { sprintf, s__ } from '~/locale';
+import ClusterFormDropdown from './cluster_form_dropdown.vue';
import RegionDropdown from './region_dropdown.vue';
import RoleNameDropdown from './role_name_dropdown.vue';
import SecurityGroupDropdown from './security_group_dropdown.vue';
-import SubnetDropdown from './subnet_dropdown.vue';
-import VpcDropdown from './vpc_dropdown.vue';
const { mapState: mapRegionsState, mapActions: mapRegionsActions } = createNamespacedHelpers(
'regions',
);
+const { mapState: mapVpcsState, mapActions: mapVpcActions } = createNamespacedHelpers('vpcs');
+const { mapState: mapSubnetsState, mapActions: mapSubnetActions } = createNamespacedHelpers(
+ 'subnets',
+);
export default {
components: {
+ ClusterFormDropdown,
RegionDropdown,
RoleNameDropdown,
SecurityGroupDropdown,
- SubnetDropdown,
- VpcDropdown,
},
computed: {
- ...mapState(['selectedRegion']),
+ ...mapState(['selectedRegion', 'selectedVpc', 'selectedSubnet']),
...mapRegionsState({
regions: 'items',
isLoadingRegions: 'isLoadingItems',
loadingRegionsError: 'loadingItemsError',
}),
+ ...mapVpcsState({
+ vpcs: 'items',
+ isLoadingVpcs: 'isLoadingItems',
+ loadingVpcsError: 'loadingItemsError',
+ }),
+ ...mapSubnetsState({
+ subnets: 'items',
+ isLoadingSubnets: 'isLoadingItems',
+ loadingSubnetsError: 'loadingItemsError',
+ }),
+ vpcDropdownDisabled() {
+ return !this.selectedRegion;
+ },
+ subnetDropdownDisabled() {
+ return !this.selectedVpc;
+ },
+ vpcDropdownHelpText() {
+ return sprintf(
+ s__(
+ 'ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services%{endLink}.',
+ ),
+ {
+ startLink:
+ '<a href="https://console.aws.amazon.com/vpc/home?#vpc" target="_blank" rel="noopener noreferrer">',
+ endLink: '</a>',
+ },
+ false,
+ );
+ },
+ subnetDropdownHelpText() {
+ return sprintf(
+ s__(
+ 'ClusterIntegration|Choose the %{startLink}subnets%{endLink} in your VPC where your worker nodes will run.',
+ ),
+ {
+ startLink:
+ '<a href="https://console.aws.amazon.com/vpc/home?#subnets" target="_blank" rel="noopener noreferrer">',
+ endLink: '</a>',
+ },
+ false,
+ );
+ },
},
mounted() {
this.fetchRegions();
},
methods: {
- ...mapActions(['setRegion']),
- ...mapRegionsActions({
- fetchRegions: 'fetchItems',
- }),
+ ...mapActions(['setRegion', 'setVpc', 'setSubnet']),
+ ...mapRegionsActions({ fetchRegions: 'fetchItems' }),
+ ...mapVpcActions({ fetchVpcs: 'fetchItems' }),
+ ...mapSubnetActions({ fetchSubnets: 'fetchItems' }),
+ setRegionAndFetchVpcs(region) {
+ this.setRegion({ region });
+ this.fetchVpcs({ region });
+ },
+ setVpcAndFetchSubnets(vpc) {
+ this.setVpc({ vpc });
+ this.fetchSubnets({ vpc });
+ },
},
};
</script>
@@ -54,8 +107,52 @@ export default {
:regions="regions"
:error="loadingRegionsError"
:loading="isLoadingRegions"
- @input="setRegion({ region: $event })"
+ @input="setRegionAndFetchVpcs($event)"
+ />
+ </div>
+ <div class="form-group">
+ <label class="label-bold" name="eks-vpc" for="eks-vpc">{{
+ s__('ClusterIntegration|VPC')
+ }}</label>
+ <cluster-form-dropdown
+ field-id="eks-vpc"
+ field-name="eks-vpc"
+ :input="selectedVpc"
+ :items="vpcs"
+ :loading="isLoadingVpcs"
+ :disabled="vpcDropdownDisabled"
+ :disabled-text="s__('ClusterIntegration|Select a region to choose a VPC')"
+ :loading-text="s__('ClusterIntegration|Loading VPCs')"
+ :placeholder="s__('ClusterIntergation|Select a VPC')"
+ :search-field-placeholder="s__('ClusterIntegration|Search VPCs')"
+ :empty-text="s__('ClusterIntegration|No VPCs found')"
+ :has-errors="loadingVpcsError"
+ :error-message="s__('ClusterIntegration|Could not load VPCs for the selected region')"
+ @input="setVpcAndFetchSubnets($event)"
+ />
+ <p class="form-text text-muted" v-html="vpcDropdownHelpText"></p>
+ </div>
+ <div class="form-group">
+ <label class="label-bold" name="eks-subnet" for="eks-subnet">{{
+ s__('ClusterIntegration|Subnet')
+ }}</label>
+ <cluster-form-dropdown
+ field-id="eks-subnet"
+ field-name="eks-subnet"
+ :input="selectedSubnet"
+ :items="subnets"
+ :loading="isLoadingSubnets"
+ :disabled="subnetDropdownDisabled"
+ :disabled-text="s__('ClusterIntegration|Select a VPC to choose a subnet')"
+ :loading-text="s__('ClusterIntegration|Loading subnets')"
+ :placeholder="s__('ClusterIntergation|Select a subnet')"
+ :search-field-placeholder="s__('ClusterIntegration|Search subnets')"
+ :empty-text="s__('ClusterIntegration|No subnet found')"
+ :has-errors="loadingSubnetsError"
+ :error-message="s__('ClusterIntegration|Could not load subnets for the selected VPC')"
+ @input="setSubnet({ subnet: $event })"
/>
+ <p class="form-text text-muted" v-html="subnetDropdownHelpText"></p>
</div>
</form>
</template>
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/components/subnet_dropdown.vue b/app/assets/javascripts/create_cluster/eks_cluster/components/subnet_dropdown.vue
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/app/assets/javascripts/create_cluster/eks_cluster/components/subnet_dropdown.vue
+++ /dev/null
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/components/vpc_dropdown.vue b/app/assets/javascripts/create_cluster/eks_cluster/components/vpc_dropdown.vue
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/app/assets/javascripts/create_cluster/eks_cluster/components/vpc_dropdown.vue
+++ /dev/null
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/services/aws_services_facade.js b/app/assets/javascripts/create_cluster/eks_cluster/services/aws_services_facade.js
index 5a13d32e0d2..030b6b384b1 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/services/aws_services_facade.js
+++ b/app/assets/javascripts/create_cluster/eks_cluster/services/aws_services_facade.js
@@ -17,4 +17,45 @@ export const fetchRegions = () =>
.send();
});
+export const fetchVpcs = () =>
+ new Promise((resolve, reject) => {
+ const ec2 = new EC2();
+
+ ec2
+ .describeVpcs()
+ .on('success', ({ data: { Vpcs: vpcs } }) => {
+ const transformedVpcs = vpcs.map(({ VpcId: id }) => ({ id, name: id }));
+
+ resolve(transformedVpcs);
+ })
+ .on('error', error => {
+ reject(error);
+ })
+ .send();
+ });
+
+export const fetchSubnets = ({ vpc }) =>
+ new Promise((resolve, reject) => {
+ const ec2 = new EC2();
+
+ ec2
+ .describeSubnets({
+ Filters: [
+ {
+ Name: 'vpc-id',
+ Values: [vpc.id],
+ },
+ ],
+ })
+ .on('success', ({ data: { Subnets: subnets } }) => {
+ const transformedSubnets = subnets.map(({ SubnetId: id }) => ({ id, name: id }));
+
+ resolve(transformedSubnets);
+ })
+ .on('error', error => {
+ reject(error);
+ })
+ .send();
+ });
+
export default () => {};
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/store/actions.js b/app/assets/javascripts/create_cluster/eks_cluster/store/actions.js
index 68493be37e0..0809fc2dfc4 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/store/actions.js
+++ b/app/assets/javascripts/create_cluster/eks_cluster/store/actions.js
@@ -4,4 +4,12 @@ export const setRegion = ({ commit }, payload) => {
commit(types.SET_REGION, payload);
};
+export const setVpc = ({ commit }, payload) => {
+ commit(types.SET_VPC, payload);
+};
+
+export const setSubnet = ({ commit }, payload) => {
+ commit(types.SET_SUBNET, payload);
+};
+
export default () => {};
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/store/cluster_dropdown/actions.js b/app/assets/javascripts/create_cluster/eks_cluster/store/cluster_dropdown/actions.js
index 4f1ecb22719..5d250b2e29e 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/store/cluster_dropdown/actions.js
+++ b/app/assets/javascripts/create_cluster/eks_cluster/store/cluster_dropdown/actions.js
@@ -4,10 +4,10 @@ export default fetchItems => ({
requestItems: ({ commit }) => commit(types.REQUEST_ITEMS),
receiveItemsSuccess: ({ commit }, payload) => commit(types.RECEIVE_ITEMS_SUCCESS, payload),
receiveItemsError: ({ commit }, payload) => commit(types.RECEIVE_ITEMS_ERROR, payload),
- fetchItems: ({ dispatch }) => {
+ fetchItems: ({ dispatch }, payload) => {
dispatch('requestItems');
- return fetchItems()
+ return fetchItems(payload)
.then(items => dispatch('receiveItemsSuccess', { items }))
.catch(error => dispatch('receiveItemsError', { error }));
},
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/store/index.js b/app/assets/javascripts/create_cluster/eks_cluster/store/index.js
index 608c4ec9e1e..622095f2cc8 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/store/index.js
+++ b/app/assets/javascripts/create_cluster/eks_cluster/store/index.js
@@ -19,6 +19,14 @@ const createStore = () =>
namespaced: true,
...clusterDropdownStore(awsServices.fetchRegions),
},
+ vpcs: {
+ namespaced: true,
+ ...clusterDropdownStore(awsServices.fetchVpcs),
+ },
+ subnets: {
+ namespaced: true,
+ ...clusterDropdownStore(awsServices.fetchSubnets),
+ },
},
});
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/store/mutation_types.js b/app/assets/javascripts/create_cluster/eks_cluster/store/mutation_types.js
index 80c1354482b..ada76b21f18 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/store/mutation_types.js
+++ b/app/assets/javascripts/create_cluster/eks_cluster/store/mutation_types.js
@@ -1,2 +1,3 @@
-// eslint-disable-next-line import/prefer-default-export
export const SET_REGION = 'SET_REGION';
+export const SET_VPC = 'SET_VPC';
+export const SET_SUBNET = 'SET_SUBNET';
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/store/mutations.js b/app/assets/javascripts/create_cluster/eks_cluster/store/mutations.js
index 02f34d1bdcd..346716bb0df 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/store/mutations.js
+++ b/app/assets/javascripts/create_cluster/eks_cluster/store/mutations.js
@@ -4,4 +4,10 @@ export default {
[types.SET_REGION](state, { region }) {
state.selectedRegion = region;
},
+ [types.SET_VPC](state, { vpc }) {
+ state.selectedVpc = vpc;
+ },
+ [types.SET_SUBNET](state, { subnet }) {
+ state.selectedSubnet = subnet;
+ },
};
diff --git a/app/controllers/concerns/uploads_actions.rb b/app/controllers/concerns/uploads_actions.rb
index 60a68cec3c3..79bee6f89d8 100644
--- a/app/controllers/concerns/uploads_actions.rb
+++ b/app/controllers/concerns/uploads_actions.rb
@@ -91,7 +91,7 @@ module UploadsActions
upload_paths = uploader.upload_paths(params[:filename])
upload = Upload.find_by(model: model, uploader: uploader_class.to_s, path: upload_paths)
- upload&.build_uploader
+ upload&.retrieve_uploader
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/models/ci/pipeline_schedule.rb b/app/models/ci/pipeline_schedule.rb
index 42d4e86fe8d..946241b7d4c 100644
--- a/app/models/ci/pipeline_schedule.rb
+++ b/app/models/ci/pipeline_schedule.rb
@@ -86,3 +86,5 @@ module Ci
end
end
end
+
+Ci::PipelineSchedule.prepend_if_ee('EE::Ci::PipelineSchedule')
diff --git a/app/models/ci/trigger.rb b/app/models/ci/trigger.rb
index 8792c5cf98b..68548bd2fdc 100644
--- a/app/models/ci/trigger.rb
+++ b/app/models/ci/trigger.rb
@@ -45,3 +45,5 @@ module Ci
end
end
end
+
+Ci::Trigger.prepend_if_ee('EE::Ci::Trigger')
diff --git a/app/models/clusters/concerns/application_core.rb b/app/models/clusters/concerns/application_core.rb
index e748c0a855d..979cf0645f5 100644
--- a/app/models/clusters/concerns/application_core.rb
+++ b/app/models/clusters/concerns/application_core.rb
@@ -64,3 +64,5 @@ module Clusters
end
end
end
+
+Clusters::Concerns::ApplicationCore.prepend_if_ee('EE::Clusters::Concerns::ApplicationCore')
diff --git a/app/models/commit_collection.rb b/app/models/commit_collection.rb
index 6b303c52283..d4c29aa295b 100644
--- a/app/models/commit_collection.rb
+++ b/app/models/commit_collection.rb
@@ -72,8 +72,15 @@ class CommitCollection
end.compact]
# Replace the commits, keeping the same order
- @commits = @commits.map do |c|
- replacements.fetch(c.id, c)
+ @commits = @commits.map do |original_commit|
+ # Return the original instance: if it didn't need to be batchloaded, it was
+ # already enriched.
+ batch_loaded_commit = replacements.fetch(original_commit.id, original_commit)
+
+ # If batch loading the commit failed, fall back to the original commit.
+ # We need to explicitly check `.nil?` since otherwise a `BatchLoader` instance
+ # that looks like `nil` is returned.
+ batch_loaded_commit.nil? ? original_commit : batch_loaded_commit
end
self
diff --git a/app/models/upload.rb b/app/models/upload.rb
index 7560002ada8..384949ddb86 100644
--- a/app/models/upload.rb
+++ b/app/models/upload.rb
@@ -15,7 +15,7 @@ class Upload < ApplicationRecord
scope :with_files_stored_remotely, -> { where(store: ObjectStorage::Store::REMOTE) }
before_save :calculate_checksum!, if: :foreground_checksummable?
- after_commit :schedule_checksum, if: :checksummable?
+ after_commit :schedule_checksum, if: :needs_checksum?
# as the FileUploader is not mounted, the default CarrierWave ActiveRecord
# hooks are not executed and the file will not be deleted
@@ -53,20 +53,41 @@ class Upload < ApplicationRecord
def calculate_checksum!
self.checksum = nil
- return unless checksummable?
+ return unless needs_checksum?
self.checksum = Digest::SHA256.file(absolute_path).hexdigest
end
+ # Initialize the associated Uploader class with current model
+ #
+ # @param [String] mounted_as
+ # @return [GitlabUploader] one of the subclasses, defined at the model's uploader attribute
def build_uploader(mounted_as = nil)
uploader_class.new(model, mounted_as || mount_point).tap do |uploader|
uploader.upload = self
+ end
+ end
+
+ # Initialize the associated Uploader class with current model and
+ # retrieve existing file from the store to a local cache
+ #
+ # @param [String] mounted_as
+ # @return [GitlabUploader] one of the subclasses, defined at the model's uploader attribute
+ def retrieve_uploader(mounted_as = nil)
+ build_uploader(mounted_as).tap do |uploader|
uploader.retrieve_from_store!(identifier)
end
end
+ # This checks for existence of the upload on storage
+ #
+ # @return [Boolean] whether upload exists on storage
def exist?
- exist = File.exist?(absolute_path)
+ exist = if local?
+ File.exist?(absolute_path)
+ else
+ retrieve_uploader.exists?
+ end
# Help sysadmins find missing upload files
if persisted? && !exist
@@ -91,18 +112,24 @@ class Upload < ApplicationRecord
store == ObjectStorage::Store::LOCAL
end
+ # Returns whether generating checksum is needed
+ #
+ # This takes into account whether file exists, if any checksum exists
+ # or if the storage has checksum generation code implemented
+ #
+ # @return [Boolean] whether generating a checksum is needed
+ def needs_checksum?
+ checksum.nil? && local? && exist?
+ end
+
private
def delete_file!
- build_uploader.remove!
- end
-
- def checksummable?
- checksum.nil? && local? && exist?
+ retrieve_uploader.remove!
end
def foreground_checksummable?
- checksummable? && size <= CHECKSUM_THRESHOLD
+ needs_checksum? && size <= CHECKSUM_THRESHOLD
end
def schedule_checksum
diff --git a/app/uploaders/avatar_uploader.rb b/app/uploaders/avatar_uploader.rb
index 9af59b0aceb..d42c9dbedf4 100644
--- a/app/uploaders/avatar_uploader.rb
+++ b/app/uploaders/avatar_uploader.rb
@@ -19,7 +19,7 @@ class AvatarUploader < GitlabUploader
end
def absolute_path
- self.class.absolute_path(model.avatar.upload)
+ self.class.absolute_path(upload)
end
private
diff --git a/app/uploaders/gitlab_uploader.rb b/app/uploaders/gitlab_uploader.rb
index cefcd3d3f5a..7dc211b14e4 100644
--- a/app/uploaders/gitlab_uploader.rb
+++ b/app/uploaders/gitlab_uploader.rb
@@ -99,6 +99,17 @@ class GitlabUploader < CarrierWave::Uploader::Base
end
end
+ # Used to replace an existing upload with another +file+ without modifying stored metadata
+ # Use this method only to repair/replace an existing upload, or to upload to a Geo secondary node
+ #
+ # @param [CarrierWave::SanitizedFile] file that will replace existing upload
+ # @return CarrierWave::SanitizedFile
+ def replace_file_without_saving!(file)
+ raise ArgumentError, 'should be a CarrierWave::SanitizedFile' unless file.is_a? CarrierWave::SanitizedFile
+
+ storage.store!(file)
+ end
+
private
# Designed to be overridden by child uploaders that have a dynamic path
diff --git a/app/workers/import_issues_csv_worker.rb b/app/workers/import_issues_csv_worker.rb
index d44fdfec8ae..b9d7099af71 100644
--- a/app/workers/import_issues_csv_worker.rb
+++ b/app/workers/import_issues_csv_worker.rb
@@ -12,7 +12,7 @@ class ImportIssuesCsvWorker
@project = Project.find(project_id)
@upload = Upload.find(upload_id)
- importer = Issues::ImportCsvService.new(@user, @project, @upload.build_uploader)
+ importer = Issues::ImportCsvService.new(@user, @project, @upload.retrieve_uploader)
importer.execute
@upload.destroy
diff --git a/app/workers/object_storage/background_move_worker.rb b/app/workers/object_storage/background_move_worker.rb
index 8dff65e46e3..19ccae7739c 100644
--- a/app/workers/object_storage/background_move_worker.rb
+++ b/app/workers/object_storage/background_move_worker.rb
@@ -22,7 +22,7 @@ module ObjectStorage
def build_uploader(subject, mount_point)
case subject
- when Upload then subject.build_uploader(mount_point)
+ when Upload then subject.retrieve_uploader(mount_point)
else
subject.send(mount_point) # rubocop:disable GitlabSecurity/PublicSend
end
diff --git a/app/workers/object_storage/migrate_uploads_worker.rb b/app/workers/object_storage/migrate_uploads_worker.rb
index 55ac7cd9b3c..c9fd19cf9d7 100644
--- a/app/workers/object_storage/migrate_uploads_worker.rb
+++ b/app/workers/object_storage/migrate_uploads_worker.rb
@@ -119,7 +119,7 @@ module ObjectStorage
end
def build_uploaders(uploads)
- uploads.map { |upload| upload.build_uploader(@mounted_as) }
+ uploads.map { |upload| upload.retrieve_uploader(@mounted_as) }
end
def migrate(uploads)
diff --git a/changelogs/unreleased/ac-pull-mirror-branch-prefix.yml b/changelogs/unreleased/ac-pull-mirror-branch-prefix.yml
new file mode 100644
index 00000000000..b39308ea38a
--- /dev/null
+++ b/changelogs/unreleased/ac-pull-mirror-branch-prefix.yml
@@ -0,0 +1,5 @@
+---
+title: Add pull_mirror_branch_prefix column on projects table
+merge_request: 17368
+author:
+type: added
diff --git a/changelogs/unreleased/add-sorting-to-packages-list.yml b/changelogs/unreleased/add-sorting-to-packages-list.yml
new file mode 100644
index 00000000000..8eab37326a1
--- /dev/null
+++ b/changelogs/unreleased/add-sorting-to-packages-list.yml
@@ -0,0 +1,5 @@
+---
+title: Adds sorting of packages at the project level
+merge_request: 15448
+author:
+type: added
diff --git a/changelogs/unreleased/bvl-fix-view-mr-deleted-repo.yml b/changelogs/unreleased/bvl-fix-view-mr-deleted-repo.yml
new file mode 100644
index 00000000000..ffd7135eec1
--- /dev/null
+++ b/changelogs/unreleased/bvl-fix-view-mr-deleted-repo.yml
@@ -0,0 +1,5 @@
+---
+title: Fix viewing merge reqeust from a fork that's being deleted
+merge_request: 17894
+author:
+type: fixed
diff --git a/changelogs/unreleased/pages-1-11-0.yml b/changelogs/unreleased/pages-1-11-0.yml
new file mode 100644
index 00000000000..da798340ee2
--- /dev/null
+++ b/changelogs/unreleased/pages-1-11-0.yml
@@ -0,0 +1,5 @@
+---
+title: Update Pages to v1.11.0
+merge_request: 18010
+author:
+type: other
diff --git a/com/lib/com/gitlab/patch/draw_route.rb b/com/lib/com/gitlab/patch/draw_route.rb
new file mode 100644
index 00000000000..8626ff06c28
--- /dev/null
+++ b/com/lib/com/gitlab/patch/draw_route.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module Com
+ module Gitlab
+ module Patch
+ module DrawRoute
+ extend ::Gitlab::Utils::Override
+
+ override :draw_com
+ def draw_com(routes_name)
+ draw_route(route_path("com/config/routes/#{routes_name}.rb"))
+ end
+ end
+ end
+ end
+end
diff --git a/com/spec/lib/gitlab/patch/draw_route_spec.rb b/com/spec/lib/gitlab/patch/draw_route_spec.rb
new file mode 100644
index 00000000000..823bebd5c0d
--- /dev/null
+++ b/com/spec/lib/gitlab/patch/draw_route_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'com_spec_helper'
+
+describe Gitlab::Patch::DrawRoute do
+ subject do
+ Class.new do
+ include Gitlab::Patch::DrawRoute
+
+ def route_path(route_name)
+ File.expand_path("../../../../../#{route_name}", __dir__)
+ end
+ end.new
+ end
+
+ before do
+ allow(subject).to receive(:instance_eval)
+ end
+
+ it 'raises an error when nothing is drawn' do
+ expect { subject.draw(:non_existing) }
+ .to raise_error(described_class::RoutesNotFound)
+ end
+end
diff --git a/config/application.rb b/config/application.rb
index 5d7c52c5d81..192e836594a 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -22,6 +22,7 @@ module Gitlab
require_dependency Rails.root.join('lib/gitlab/current_settings')
require_dependency Rails.root.join('lib/gitlab/middleware/read_only')
require_dependency Rails.root.join('lib/gitlab/middleware/basic_health_check')
+ require_dependency Rails.root.join('config/light_settings')
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
@@ -62,6 +63,15 @@ module Gitlab
config.paths['app/views'].unshift "#{config.root}/ee/app/views"
end
+ if LightSettings.com?
+ com_paths = config.eager_load_paths.each_with_object([]) do |path, memo|
+ com_path = config.root.join('com', Pathname.new(path).relative_path_from(config.root))
+ memo << com_path.to_s
+ end
+
+ config.eager_load_paths.push(*com_paths)
+ end
+
# Rake tasks ignore the eager loading settings, so we need to set the
# autoload paths explicitly
config.autoload_paths = config.eager_load_paths.dup
diff --git a/config/initializers/0_inject_com_module.rb b/config/initializers/0_inject_com_module.rb
new file mode 100644
index 00000000000..9802eb37ec3
--- /dev/null
+++ b/config/initializers/0_inject_com_module.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'active_support/inflector'
+
+module InjectComModule
+ def prepend_if_com(constant, with_descendants: false)
+ return unless Gitlab.com?
+
+ com_module = constant.constantize
+ prepend(com_module)
+
+ if with_descendants
+ descendants.each { |descendant| descendant.prepend(com_module) }
+ end
+ end
+
+ def extend_if_com(constant)
+ extend(constant.constantize) if Gitlab.com?
+ end
+
+ def include_if_com(constant)
+ include(constant.constantize) if Gitlab.com?
+ end
+end
+
+Module.prepend(InjectComModule)
diff --git a/config/light_settings.rb b/config/light_settings.rb
new file mode 100644
index 00000000000..aa0dd04b3fa
--- /dev/null
+++ b/config/light_settings.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+class LightSettings
+ GL_HOST ||= 'gitlab.com'
+ GL_SUBDOMAIN_REGEX ||= %r{\A[a-z0-9]+\.gitlab\.com\z}.freeze
+
+ class << self
+ def com?
+ return Thread.current[:is_com] unless Thread.current[:is_com].nil?
+
+ Thread.current[:is_com] = host == GL_HOST || gl_subdomain?
+ end
+
+ private
+
+ def config
+ YAML.safe_load(File.read(settings_path), aliases: true)[Rails.env]
+ end
+
+ def settings_path
+ Rails.root.join('config', 'gitlab.yml')
+ end
+
+ def host
+ config['gitlab']['host']
+ end
+
+ def gl_subdomain?
+ GL_SUBDOMAIN_REGEX === host
+ end
+ end
+end
diff --git a/db/migrate/20190924124627_add_pull_mirror_branch_prefix_to_projects.rb b/db/migrate/20190924124627_add_pull_mirror_branch_prefix_to_projects.rb
new file mode 100644
index 00000000000..b9f729d7d66
--- /dev/null
+++ b/db/migrate/20190924124627_add_pull_mirror_branch_prefix_to_projects.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddPullMirrorBranchPrefixToProjects < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def change
+ add_column :projects, :pull_mirror_branch_prefix, :string, limit: 50
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index f5eb39d2087..8c22fe80381 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -2922,6 +2922,7 @@ ActiveRecord::Schema.define(version: 2019_09_27_074328) do
t.boolean "emails_disabled"
t.integer "max_pages_size"
t.integer "max_artifacts_size"
+ t.string "pull_mirror_branch_prefix", limit: 50
t.index "lower((name)::text)", name: "index_projects_on_lower_name"
t.index ["archived", "pending_delete", "merge_requests_require_code_owner_approval"], name: "projects_requiring_code_owner_approval", where: "((pending_delete = false) AND (archived = false) AND (merge_requests_require_code_owner_approval = true))"
t.index ["created_at"], name: "index_projects_on_created_at"
diff --git a/lib/gitlab.rb b/lib/gitlab.rb
index b337f5cbf2c..43b3642fd6b 100644
--- a/lib/gitlab.rb
+++ b/lib/gitlab.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'pathname'
+require_relative '../config/light_settings'
module Gitlab
def self.root
@@ -37,24 +38,18 @@ module Gitlab
COM_URL = 'https://gitlab.com'
APP_DIRS_PATTERN = %r{^/?(app|config|ee|lib|spec|\(\w*\))}.freeze
- SUBDOMAIN_REGEX = %r{\Ahttps://[a-z0-9]+\.gitlab\.com\z}.freeze
VERSION = File.read(root.join("VERSION")).strip.freeze
INSTALLATION_TYPE = File.read(root.join("INSTALLATION_TYPE")).strip.freeze
HTTP_PROXY_ENV_VARS = %w(http_proxy https_proxy HTTP_PROXY HTTPS_PROXY).freeze
def self.com?
- # Check `gl_subdomain?` as well to keep parity with gitlab.com
- Gitlab.config.gitlab.url == COM_URL || gl_subdomain?
+ LightSettings.com?
end
def self.org?
Gitlab.config.gitlab.url == 'https://dev.gitlab.org'
end
- def self.gl_subdomain?
- SUBDOMAIN_REGEX === Gitlab.config.gitlab.url
- end
-
def self.dev_env_org_or_com?
dev_env_or_com? || org?
end
@@ -79,6 +74,10 @@ module Gitlab
yield if ee?
end
+ def self.com
+ yield if com?
+ end
+
def self.http_proxy_env?
HTTP_PROXY_ENV_VARS.any? { |name| ENV[name] }
end
diff --git a/lib/gitlab/background_migration/legacy_upload_mover.rb b/lib/gitlab/background_migration/legacy_upload_mover.rb
index 051c1176edb..c9e47f210be 100644
--- a/lib/gitlab/background_migration/legacy_upload_mover.rb
+++ b/lib/gitlab/background_migration/legacy_upload_mover.rb
@@ -92,7 +92,7 @@ module Gitlab
def legacy_file_uploader
strong_memoize(:legacy_file_uploader) do
- uploader = upload.build_uploader
+ uploader = upload.retrieve_uploader
uploader.retrieve_from_store!(File.basename(upload.path))
uploader
end
diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml
index 12a9f72b8cb..141e73e6a47 100644
--- a/lib/gitlab/import_export/import_export.yml
+++ b/lib/gitlab/import_export/import_export.yml
@@ -139,6 +139,7 @@ excluded_attributes:
- :mirror_trigger_builds
- :only_mirror_protected_branches
- :pull_mirror_available_overridden
+ - :pull_mirror_branch_prefix
- :mirror_overwrites_diverged_branches
- :packages_enabled
- :mirror_last_update_at
diff --git a/lib/gitlab/import_export/uploads_manager.rb b/lib/gitlab/import_export/uploads_manager.rb
index e232198150a..dca8e3a7449 100644
--- a/lib/gitlab/import_export/uploads_manager.rb
+++ b/lib/gitlab/import_export/uploads_manager.rb
@@ -68,7 +68,7 @@ module Gitlab
yield(@project.avatar)
else
project_uploads_except_avatar(avatar_path).find_each(batch_size: UPLOADS_BATCH_SIZE) do |upload|
- yield(upload.build_uploader)
+ yield(upload.retrieve_uploader)
end
end
end
diff --git a/lib/gitlab/patch/draw_route.rb b/lib/gitlab/patch/draw_route.rb
index 4c8ca015974..fc9d7ae805f 100644
--- a/lib/gitlab/patch/draw_route.rb
+++ b/lib/gitlab/patch/draw_route.rb
@@ -6,11 +6,12 @@ module Gitlab
module Patch
module DrawRoute
prepend_if_ee('EE::Gitlab::Patch::DrawRoute') # rubocop: disable Cop/InjectEnterpriseEditionModule
+ prepend_if_com('Com::Gitlab::Patch::DrawRoute')
RoutesNotFound = Class.new(StandardError)
def draw(routes_name)
- drawn_any = draw_ce(routes_name) | draw_ee(routes_name)
+ drawn_any = draw_ce(routes_name) | draw_ee(routes_name) | draw_com(routes_name)
drawn_any || raise(RoutesNotFound.new("Cannot find #{routes_name}"))
end
@@ -23,6 +24,10 @@ module Gitlab
true
end
+ def draw_com(_)
+ false
+ end
+
def route_path(routes_name)
Rails.root.join(routes_name)
end
diff --git a/lib/gitlab/sanitizers/exif.rb b/lib/gitlab/sanitizers/exif.rb
index 2f3d14ecebd..5eeb8b00ff3 100644
--- a/lib/gitlab/sanitizers/exif.rb
+++ b/lib/gitlab/sanitizers/exif.rb
@@ -68,7 +68,7 @@ module Gitlab
}
relation.find_each(find_params) do |upload|
- clean(upload.build_uploader, dry_run: dry_run)
+ clean(upload.retrieve_uploader, dry_run: dry_run)
sleep sleep_time if sleep_time
rescue => err
logger.error "failed to sanitize #{upload_ref(upload)}: #{err.message}"
diff --git a/lib/gitlab/verify/uploads.rb b/lib/gitlab/verify/uploads.rb
index 875e8a120e9..afcdbd087d2 100644
--- a/lib/gitlab/verify/uploads.rb
+++ b/lib/gitlab/verify/uploads.rb
@@ -32,7 +32,7 @@ module Gitlab
end
def remote_object_exists?(upload)
- upload.build_uploader.file.exists?
+ upload.retrieve_uploader.file.exists?
end
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 8a00584894b..0c7ddc1e07e 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2421,6 +2421,9 @@ msgstr ""
msgid "Branch not loaded - %{branchId}"
msgstr ""
+msgid "Branch prefix"
+msgstr ""
+
msgid "BranchSwitcherPlaceholder|Search branches"
msgstr ""
@@ -3351,6 +3354,9 @@ msgstr ""
msgid "ClusterIntegration|Choose a prefix to be used for your namespaces. Defaults to your project path."
msgstr ""
+msgid "ClusterIntegration|Choose the %{startLink}subnets%{endLink} in your VPC where your worker nodes will run."
+msgstr ""
+
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster. Helm Tiller is required to install any of the following applications."
msgstr ""
@@ -3390,9 +3396,15 @@ msgstr ""
msgid "ClusterIntegration|Copy Service Token"
msgstr ""
+msgid "ClusterIntegration|Could not load VPCs for the selected region"
+msgstr ""
+
msgid "ClusterIntegration|Could not load regions from your AWS account"
msgstr ""
+msgid "ClusterIntegration|Could not load subnets for the selected VPC"
+msgstr ""
+
msgid "ClusterIntegration|Create Kubernetes cluster"
msgstr ""
@@ -3579,6 +3591,12 @@ msgstr ""
msgid "ClusterIntegration|Loading Regions"
msgstr ""
+msgid "ClusterIntegration|Loading VPCs"
+msgstr ""
+
+msgid "ClusterIntegration|Loading subnets"
+msgstr ""
+
msgid "ClusterIntegration|Machine type"
msgstr ""
@@ -3591,6 +3609,9 @@ msgstr ""
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
+msgid "ClusterIntegration|No VPCs found"
+msgstr ""
+
msgid "ClusterIntegration|No machine types matched your search"
msgstr ""
@@ -3603,6 +3624,9 @@ msgstr ""
msgid "ClusterIntegration|No region found"
msgstr ""
+msgid "ClusterIntegration|No subnet found"
+msgstr ""
+
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
@@ -3672,6 +3696,9 @@ msgstr ""
msgid "ClusterIntegration|Search IAM Roles"
msgstr ""
+msgid "ClusterIntegration|Search VPCs"
+msgstr ""
+
msgid "ClusterIntegration|Search machine types"
msgstr ""
@@ -3681,12 +3708,24 @@ msgstr ""
msgid "ClusterIntegration|Search regions"
msgstr ""
+msgid "ClusterIntegration|Search subnets"
+msgstr ""
+
msgid "ClusterIntegration|Search zones"
msgstr ""
msgid "ClusterIntegration|See and edit the details for your Kubernetes cluster"
msgstr ""
+msgid "ClusterIntegration|Select a VPC to choose a subnet"
+msgstr ""
+
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services%{endLink}."
+msgstr ""
+
+msgid "ClusterIntegration|Select a region to choose a VPC"
+msgstr ""
+
msgid "ClusterIntegration|Select machine type"
msgstr ""
@@ -3735,6 +3774,9 @@ msgstr ""
msgid "ClusterIntegration|Specifying a domain will allow you to use Auto Review Apps and Auto Deploy stages for %{auto_devops_start}Auto DevOps%{auto_devops_end}. The domain should have a wildcard DNS configured matching the domain."
msgstr ""
+msgid "ClusterIntegration|Subnet"
+msgstr ""
+
msgid "ClusterIntegration|The Kubernetes certificate used to authenticate to the cluster."
msgstr ""
@@ -3783,6 +3825,9 @@ msgstr ""
msgid "ClusterIntegration|Uses the Cloud Run, Istio, and HTTP Load Balancing addons for this cluster."
msgstr ""
+msgid "ClusterIntegration|VPC"
+msgstr ""
+
msgid "ClusterIntegration|Validating project billing status"
msgstr ""
@@ -3831,9 +3876,15 @@ msgstr ""
msgid "ClusterIntegration|sign up"
msgstr ""
+msgid "ClusterIntergation|Select a VPC"
+msgstr ""
+
msgid "ClusterIntergation|Select a region"
msgstr ""
+msgid "ClusterIntergation|Select a subnet"
+msgstr ""
+
msgid "ClusterIntergation|Select role name"
msgstr ""
@@ -8640,6 +8691,9 @@ msgstr ""
msgid "Introducing Your Conversational Development Index"
msgstr ""
+msgid "Invalid Git ref"
+msgstr ""
+
msgid "Invalid Insights config file detected"
msgstr ""
@@ -10120,6 +10174,9 @@ msgstr ""
msgid "Mirror user"
msgstr ""
+msgid "Mirrored branches will have this prefix. If you enabled 'Only mirror protected branches' you need to include this prefix on protected branches in this project or nothing will be mirrored."
+msgstr ""
+
msgid "Mirrored repositories"
msgstr ""
@@ -14890,6 +14947,12 @@ msgstr ""
msgid "SortOptions|Start soon"
msgstr ""
+msgid "SortOptions|Type"
+msgstr ""
+
+msgid "SortOptions|Version"
+msgstr ""
+
msgid "SortOptions|Weight"
msgstr ""
diff --git a/spec/com_spec_helper.rb b/spec/com_spec_helper.rb
new file mode 100644
index 00000000000..f71ccde9509
--- /dev/null
+++ b/spec/com_spec_helper.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+Settings.gitlab[:url] = "https://test.gitlab.com"
diff --git a/spec/factories/uploads.rb b/spec/factories/uploads.rb
index bfe02c6010b..ef464d3d6e0 100644
--- a/spec/factories/uploads.rb
+++ b/spec/factories/uploads.rb
@@ -2,7 +2,7 @@
FactoryBot.define do
factory :upload do
- model { build(:project) }
+ model { create(:project) }
size { 100.kilobytes }
uploader { "AvatarUploader" }
mount_point { :avatar }
@@ -11,23 +11,27 @@ FactoryBot.define do
# we should build a mount agnostic upload by default
transient do
- filename { 'myfile.jpg' }
+ filename { 'avatar.jpg' }
end
- # this needs to comply with RecordsUpload::Concern#upload_path
- path { File.join("uploads/-/system", model.class.underscore, mount_point.to_s, 'avatar.jpg') }
+ path do
+ uploader_instance = Object.const_get(uploader.to_s).new(model, mount_point)
+ File.join(uploader_instance.store_dir, filename)
+ end
trait :personal_snippet_upload do
- uploader { "PersonalFileUploader" }
+ model { create(:personal_snippet) }
path { File.join(secret, filename) }
- model { build(:personal_snippet) }
+ uploader { "PersonalFileUploader" }
secret { SecureRandom.hex }
+ mount_point { nil }
end
trait :issuable_upload do
uploader { "FileUploader" }
path { File.join(secret, filename) }
secret { SecureRandom.hex }
+ mount_point { nil }
end
trait :with_file do
@@ -42,22 +46,23 @@ FactoryBot.define do
end
trait :namespace_upload do
- model { build(:group) }
+ model { create(:group) }
path { File.join(secret, filename) }
uploader { "NamespaceFileUploader" }
secret { SecureRandom.hex }
+ mount_point { nil }
end
trait :favicon_upload do
- model { build(:appearance) }
- path { File.join(secret, filename) }
+ model { create(:appearance) }
uploader { "FaviconUploader" }
secret { SecureRandom.hex }
+ mount_point { :favicon }
end
trait :attachment_upload do
mount_point { :attachment }
- model { build(:note) }
+ model { create(:note) }
uploader { "AttachmentUploader" }
end
end
diff --git a/spec/fast_spec_helper.rb b/spec/fast_spec_helper.rb
index f5a487b4d57..a7810d72671 100644
--- a/spec/fast_spec_helper.rb
+++ b/spec/fast_spec_helper.rb
@@ -5,10 +5,12 @@ ENV['IN_MEMORY_APPLICATION_SETTINGS'] = 'true'
require 'active_support/dependencies'
require_relative '../config/initializers/0_inject_enterprise_edition_module'
+require_relative '../config/initializers/0_inject_com_module'
require_relative '../config/settings'
require_relative 'support/rspec'
require 'active_support/all'
ActiveSupport::Dependencies.autoload_paths << 'lib'
ActiveSupport::Dependencies.autoload_paths << 'ee/lib'
+ActiveSupport::Dependencies.autoload_paths << 'com/lib'
ActiveSupport::XmlMini.backend = 'Nokogiri'
diff --git a/spec/features/merge_request/user_views_merge_request_from_deleted_fork_spec.rb b/spec/features/merge_request/user_views_merge_request_from_deleted_fork_spec.rb
new file mode 100644
index 00000000000..26984a1fb5e
--- /dev/null
+++ b/spec/features/merge_request/user_views_merge_request_from_deleted_fork_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+# This is a feature spec because the problems arrise when rendering the view for
+# an actual project for which the repository is removed but the cached not
+# updated.
+# This can occur when the fork a merge request is created from is in the process
+# of being destroyed.
+describe 'User views merged merge request from deleted fork' do
+ include ProjectForksHelper
+
+ let(:project) { create(:project, :repository) }
+ let(:source_project) { fork_project(project, nil, repository: true) }
+ let(:user) { project.owner }
+ let!(:merge_request) { create(:merge_request, :merged, source_project: source_project, target_project: project) }
+
+ before do
+ sign_in user
+
+ fork_owner = source_project.namespace.owners.first
+ # Place the source_project in the weird in between state
+ source_project.update_attribute(:pending_delete, true)
+ Projects::DestroyService.new(source_project, fork_owner, {}).__send__(:trash_repositories!)
+ end
+
+ it 'correctly shows the merge request' do
+ visit(merge_request_path(merge_request))
+
+ expect(page).to have_content(merge_request.title)
+ end
+end
diff --git a/spec/frontend/commit/__snapshots__/commit_pipeline_status_component_spec.js.snap b/spec/frontend/commit/__snapshots__/commit_pipeline_status_component_spec.js.snap
deleted file mode 100644
index 9199db69fed..00000000000
--- a/spec/frontend/commit/__snapshots__/commit_pipeline_status_component_spec.js.snap
+++ /dev/null
@@ -1,39 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Commit pipeline status component when polling is not successful renders not found CI icon without loader 1`] = `
-<div
- class="ci-status-link"
->
- <a>
- <ciicon-stub
- aria-label="Pipeline: not found"
- cssclasses=""
- data-container="body"
- data-original-title="Pipeline: not found"
- size="24"
- status="[object Object]"
- title=""
- />
- </a>
-</div>
-`;
-
-exports[`Commit pipeline status component when polling is successful renders CI icon without loader 1`] = `
-<div
- class="ci-status-link"
->
- <a
- href="/frontend-fixtures/pipelines-project/pipelines/47"
- >
- <ciicon-stub
- aria-label="Pipeline: pending"
- cssclasses=""
- data-container="body"
- data-original-title="Pipeline: pending"
- size="24"
- status="[object Object]"
- title=""
- />
- </a>
-</div>
-`;
diff --git a/spec/frontend/commit/commit_pipeline_status_component_spec.js b/spec/frontend/commit/commit_pipeline_status_component_spec.js
index 1768fd745c9..1736d1d0df8 100644
--- a/spec/frontend/commit/commit_pipeline_status_component_spec.js
+++ b/spec/frontend/commit/commit_pipeline_status_component_spec.js
@@ -2,6 +2,7 @@ import Visibility from 'visibilityjs';
import { GlLoadingIcon } from '@gitlab/ui';
import Poll from '~/lib/utils/poll';
import flash from '~/flash';
+import CiIcon from '~/vue_shared/components/ci_icon.vue';
import CommitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue';
import { shallowMount } from '@vue/test-utils';
import { getJSONFixture } from '../helpers/fixtures';
@@ -36,6 +37,10 @@ describe('Commit pipeline status component', () => {
});
};
+ const findLoader = () => wrapper.find(GlLoadingIcon);
+ const findLink = () => wrapper.find('a');
+ const findCiIcon = () => findLink().find(CiIcon);
+
afterEach(() => {
wrapper.destroy();
wrapper = null;
@@ -111,14 +116,14 @@ describe('Commit pipeline status component', () => {
it('shows the loading icon at start', () => {
createComponent();
- expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
+ expect(findLoader().exists()).toBe(true);
pollConfig.successCallback({
data: { pipelines: [] },
});
return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
+ expect(findLoader().exists()).toBe(false);
});
});
@@ -130,8 +135,17 @@ describe('Commit pipeline status component', () => {
return wrapper.vm.$nextTick();
});
- it('renders CI icon without loader', () => {
- expect(wrapper.element).toMatchSnapshot();
+ it('does not render loader', () => {
+ expect(findLoader().exists()).toBe(false);
+ });
+
+ it('renders link with href', () => {
+ expect(findLink().attributes('href')).toEqual(mockCiStatus.details_path);
+ });
+
+ it('renders CI icon', () => {
+ expect(findCiIcon().attributes('data-original-title')).toEqual('Pipeline: pending');
+ expect(findCiIcon().props('status')).toEqual(mockCiStatus);
});
});
@@ -140,8 +154,21 @@ describe('Commit pipeline status component', () => {
pollConfig.errorCallback();
});
- it('renders not found CI icon without loader', () => {
- expect(wrapper.element).toMatchSnapshot();
+ it('does not render loader', () => {
+ expect(findLoader().exists()).toBe(false);
+ });
+
+ it('renders link with href', () => {
+ expect(findLink().attributes('href')).toBeUndefined();
+ });
+
+ it('renders not found CI icon', () => {
+ expect(findCiIcon().attributes('data-original-title')).toEqual('Pipeline: not found');
+ expect(findCiIcon().props('status')).toEqual({
+ text: 'not found',
+ icon: 'status_notfound',
+ group: 'notfound',
+ });
});
it('displays flash error message', () => {
diff --git a/spec/frontend/create_cluster/eks_cluster/components/eks_cluster_configuration_form_spec.js b/spec/frontend/create_cluster/eks_cluster/components/eks_cluster_configuration_form_spec.js
index 1bd16d356b9..cc7c6735a80 100644
--- a/spec/frontend/create_cluster/eks_cluster/components/eks_cluster_configuration_form_spec.js
+++ b/spec/frontend/create_cluster/eks_cluster/components/eks_cluster_configuration_form_spec.js
@@ -4,6 +4,7 @@ import Vue from 'vue';
import EksClusterConfigurationForm from '~/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue';
import RegionDropdown from '~/create_cluster/eks_cluster/components/region_dropdown.vue';
+import eksClusterFormState from '~/create_cluster/eks_cluster/store/state';
import clusterDropdownStoreState from '~/create_cluster/eks_cluster/store/cluster_dropdown/state';
const localVue = createLocalVue();
@@ -12,29 +13,59 @@ localVue.use(Vuex);
describe('EksClusterConfigurationForm', () => {
let store;
let actions;
+ let state;
let regionsState;
+ let vpcsState;
+ let subnetsState;
+ let vpcsActions;
let regionsActions;
+ let subnetsActions;
let vm;
beforeEach(() => {
+ state = eksClusterFormState();
actions = {
setRegion: jest.fn(),
setVpc: jest.fn(),
+ setSubnet: jest.fn(),
};
regionsActions = {
fetchItems: jest.fn(),
};
+ vpcsActions = {
+ fetchItems: jest.fn(),
+ };
+ subnetsActions = {
+ fetchItems: jest.fn(),
+ };
regionsState = {
...clusterDropdownStoreState(),
};
+ vpcsState = {
+ ...clusterDropdownStoreState(),
+ };
+ subnetsState = {
+ ...clusterDropdownStoreState(),
+ };
store = new Vuex.Store({
+ state,
actions,
modules: {
+ vpcs: {
+ namespaced: true,
+ state: vpcsState,
+ actions: vpcsActions,
+ },
regions: {
namespaced: true,
state: regionsState,
actions: regionsActions,
},
+ subnets: {
+ namespaced: true,
+ state: subnetsState,
+ actions: subnetsActions,
+ },
},
});
});
@@ -51,6 +82,8 @@ describe('EksClusterConfigurationForm', () => {
});
const findRegionDropdown = () => vm.find(RegionDropdown);
+ const findVpcDropdown = () => vm.find('[field-id="eks-vpc"]');
+ const findSubnetDropdown = () => vm.find('[field-id="eks-subnet"]');
describe('when mounted', () => {
it('fetches available regions', () => {
@@ -62,16 +95,72 @@ describe('EksClusterConfigurationForm', () => {
regionsState.isLoadingItems = true;
return Vue.nextTick().then(() => {
- expect(findRegionDropdown().props('loading')).toEqual(regionsState.isLoadingItems);
+ expect(findRegionDropdown().props('loading')).toBe(regionsState.isLoadingItems);
});
});
it('sets regions to RegionDropdown regions property', () => {
- expect(findRegionDropdown().props('regions')).toEqual(regionsState.items);
+ expect(findRegionDropdown().props('regions')).toBe(regionsState.items);
});
it('sets loadingRegionsError to RegionDropdown error property', () => {
- expect(findRegionDropdown().props('error')).toEqual(regionsState.loadingItemsError);
+ expect(findRegionDropdown().props('error')).toBe(regionsState.loadingItemsError);
+ });
+
+ it('disables VpcDropdown when no region is selected', () => {
+ expect(findVpcDropdown().props('disabled')).toBe(true);
+ });
+
+ it('enables VpcDropdown when no region is selected', () => {
+ state.selectedRegion = { name: 'west-1 ' };
+
+ return Vue.nextTick().then(() => {
+ expect(findVpcDropdown().props('disabled')).toBe(false);
+ });
+ });
+
+ it('sets isLoadingVpcs to VpcDropdown loading property', () => {
+ vpcsState.isLoadingItems = true;
+
+ return Vue.nextTick().then(() => {
+ expect(findVpcDropdown().props('loading')).toBe(vpcsState.isLoadingItems);
+ });
+ });
+
+ it('sets vpcs to VpcDropdown items property', () => {
+ expect(findVpcDropdown().props('items')).toBe(vpcsState.items);
+ });
+
+ it('sets loadingVpcsError to VpcDropdown hasErrors property', () => {
+ expect(findVpcDropdown().props('hasErrors')).toBe(vpcsState.loadingItemsError);
+ });
+
+ it('disables SubnetDropdown when no vpc is selected', () => {
+ expect(findSubnetDropdown().props('disabled')).toBe(true);
+ });
+
+ it('enables SubnetDropdown when a vpc is selected', () => {
+ state.selectedVpc = { name: 'vpc-1 ' };
+
+ return Vue.nextTick().then(() => {
+ expect(findSubnetDropdown().props('disabled')).toBe(false);
+ });
+ });
+
+ it('sets isLoadingSubnets to SubnetDropdown loading property', () => {
+ subnetsState.isLoadingItems = true;
+
+ return Vue.nextTick().then(() => {
+ expect(findSubnetDropdown().props('loading')).toBe(subnetsState.isLoadingItems);
+ });
+ });
+
+ it('sets subnets to SubnetDropdown items property', () => {
+ expect(findSubnetDropdown().props('items')).toBe(subnetsState.items);
+ });
+
+ it('sets loadingSubnetsError to SubnetDropdown hasErrors property', () => {
+ expect(findSubnetDropdown().props('hasErrors')).toBe(subnetsState.loadingItemsError);
});
describe('when region is selected', () => {
@@ -84,5 +173,37 @@ describe('EksClusterConfigurationForm', () => {
it('dispatches setRegion action', () => {
expect(actions.setRegion).toHaveBeenCalledWith(expect.anything(), { region }, undefined);
});
+
+ it('fetches available vpcs', () => {
+ expect(vpcsActions.fetchItems).toHaveBeenCalledWith(expect.anything(), { region }, undefined);
+ });
+ });
+
+ describe('when vpc is selected', () => {
+ const vpc = { name: 'vpc-1' };
+
+ beforeEach(() => {
+ findVpcDropdown().vm.$emit('input', vpc);
+ });
+
+ it('dispatches setVpc action', () => {
+ expect(actions.setVpc).toHaveBeenCalledWith(expect.anything(), { vpc }, undefined);
+ });
+
+ it('dispatches fetchSubnets action', () => {
+ expect(subnetsActions.fetchItems).toHaveBeenCalledWith(expect.anything(), { vpc }, undefined);
+ });
+ });
+
+ describe('when a subnet is selected', () => {
+ const subnet = { name: 'subnet-1' };
+
+ beforeEach(() => {
+ findSubnetDropdown().vm.$emit('input', subnet);
+ });
+
+ it('dispatches setSubnet action', () => {
+ expect(actions.setSubnet).toHaveBeenCalledWith(expect.anything(), { subnet }, undefined);
+ });
});
});
diff --git a/spec/frontend/create_cluster/eks_cluster/store/actions_spec.js b/spec/frontend/create_cluster/eks_cluster/store/actions_spec.js
index 3744ddb3dc6..893c657e699 100644
--- a/spec/frontend/create_cluster/eks_cluster/store/actions_spec.js
+++ b/spec/frontend/create_cluster/eks_cluster/store/actions_spec.js
@@ -1,17 +1,28 @@
import testAction from 'helpers/vuex_action_helper';
import createState from '~/create_cluster/eks_cluster/store/state';
-import * as types from '~/create_cluster/eks_cluster/store/mutation_types';
import * as actions from '~/create_cluster/eks_cluster/store/actions';
+import { SET_REGION, SET_VPC, SET_SUBNET } from '~/create_cluster/eks_cluster/store/mutation_types';
describe('EKS Cluster Store Actions', () => {
- describe('setRegion', () => {
- it(`commits ${types.SET_REGION} mutation`, () => {
- const region = { name: 'west-1' };
+ let region;
+ let vpc;
+ let subnet;
- testAction(actions.setRegion, { region }, createState(), [
- { type: types.SET_REGION, payload: { region } },
- ]);
- });
+ beforeEach(() => {
+ region = { name: 'regions-1' };
+ vpc = { name: 'vpc-1' };
+ subnet = { name: 'subnet-1' };
+ });
+
+ it.each`
+ action | mutation | payload | payloadDescription
+ ${'setRegion'} | ${SET_REGION} | ${{ region }} | ${'region'}
+ ${'setVpc'} | ${SET_VPC} | ${{ vpc }} | ${'vpc'}
+ ${'setSubnet'} | ${SET_SUBNET} | ${{ subnet }} | ${'subnet'}
+ `(`$action commits $mutation with $payloadDescription payload`, data => {
+ const { action, mutation, payload } = data;
+
+ testAction(actions[action], payload, createState(), [{ type: mutation, payload }]);
});
});
diff --git a/spec/frontend/create_cluster/eks_cluster/store/mutations_spec.js b/spec/frontend/create_cluster/eks_cluster/store/mutations_spec.js
index 99f05b0f449..38199471f79 100644
--- a/spec/frontend/create_cluster/eks_cluster/store/mutations_spec.js
+++ b/spec/frontend/create_cluster/eks_cluster/store/mutations_spec.js
@@ -1,19 +1,26 @@
-import { SET_REGION } from '~/create_cluster/eks_cluster/store/mutation_types';
+import { SET_REGION, SET_VPC, SET_SUBNET } from '~/create_cluster/eks_cluster/store/mutation_types';
import createState from '~/create_cluster/eks_cluster/store/state';
import mutations from '~/create_cluster/eks_cluster/store/mutations';
describe('Create EKS cluster store mutations', () => {
let state;
let region;
+ let vpc;
+ let subnet;
beforeEach(() => {
region = { name: 'regions-1' };
+ vpc = { name: 'vpc-1' };
+ subnet = { name: 'subnet-1' };
+
state = createState();
});
it.each`
mutation | mutatedProperty | payload | expectedValue | expectedValueDescription
${SET_REGION} | ${'selectedRegion'} | ${{ region }} | ${region} | ${'selected region payload'}
+ ${SET_VPC} | ${'selectedVpc'} | ${{ vpc }} | ${vpc} | ${'selected vpc payload'}
+ ${SET_SUBNET} | ${'selectedSubnet'} | ${{ subnet }} | ${subnet} | ${'selected sybnet payload'}
`(`$mutation sets $mutatedProperty to $expectedValueDescription`, data => {
const { mutation, mutatedProperty, payload, expectedValue } = data;
diff --git a/spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb b/spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb
index 7d67dc0251d..c1eaf1d3433 100644
--- a/spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb
+++ b/spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb
@@ -32,7 +32,7 @@ describe Gitlab::BackgroundMigration::LegacyUploadMover do
if with_file
upload = create(:upload, :with_file, :attachment_upload, params)
- model.update(attachment: upload.build_uploader)
+ model.update(attachment: upload.retrieve_uploader)
model.attachment.upload
else
create(:upload, :attachment_upload, params)
diff --git a/spec/lib/gitlab/background_migration/legacy_uploads_migrator_spec.rb b/spec/lib/gitlab/background_migration/legacy_uploads_migrator_spec.rb
index ed8cbfeb11f..cabca3dbef9 100644
--- a/spec/lib/gitlab/background_migration/legacy_uploads_migrator_spec.rb
+++ b/spec/lib/gitlab/background_migration/legacy_uploads_migrator_spec.rb
@@ -24,7 +24,7 @@ describe Gitlab::BackgroundMigration::LegacyUploadsMigrator do
if with_file
upload = create(:upload, :with_file, :attachment_upload, params)
- model.update(attachment: upload.build_uploader)
+ model.update(attachment: upload.retrieve_uploader)
model.attachment.upload
else
create(:upload, :attachment_upload, params)
diff --git a/spec/lib/gitlab/import_export/uploads_manager_spec.rb b/spec/lib/gitlab/import_export/uploads_manager_spec.rb
index 792117e1df1..f13f639d6b7 100644
--- a/spec/lib/gitlab/import_export/uploads_manager_spec.rb
+++ b/spec/lib/gitlab/import_export/uploads_manager_spec.rb
@@ -83,7 +83,7 @@ describe Gitlab::ImportExport::UploadsManager do
it 'restores the file' do
manager.restore
- expect(project.uploads.map { |u| u.build_uploader.filename }).to include('dummy.txt')
+ expect(project.uploads.map { |u| u.retrieve_uploader.filename }).to include('dummy.txt')
end
end
end
diff --git a/spec/lib/gitlab/import_export/uploads_restorer_spec.rb b/spec/lib/gitlab/import_export/uploads_restorer_spec.rb
index 6072f18b8c7..e2e8204b2fa 100644
--- a/spec/lib/gitlab/import_export/uploads_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/uploads_restorer_spec.rb
@@ -27,7 +27,7 @@ describe Gitlab::ImportExport::UploadsRestorer do
it 'copies the uploads to the project path' do
subject.restore
- expect(project.uploads.map { |u| u.build_uploader.filename }).to include('dummy.txt')
+ expect(project.uploads.map { |u| u.retrieve_uploader.filename }).to include('dummy.txt')
end
end
@@ -43,7 +43,7 @@ describe Gitlab::ImportExport::UploadsRestorer do
it 'copies the uploads to the project path' do
subject.restore
- expect(project.uploads.map { |u| u.build_uploader.filename }).to include('dummy.txt')
+ expect(project.uploads.map { |u| u.retrieve_uploader.filename }).to include('dummy.txt')
end
end
end
diff --git a/spec/lib/gitlab/sanitizers/exif_spec.rb b/spec/lib/gitlab/sanitizers/exif_spec.rb
index f882dbbdb5c..11e430e0be4 100644
--- a/spec/lib/gitlab/sanitizers/exif_spec.rb
+++ b/spec/lib/gitlab/sanitizers/exif_spec.rb
@@ -58,7 +58,7 @@ describe Gitlab::Sanitizers::Exif do
end
describe '#clean' do
- let(:uploader) { create(:upload, :with_file, :issuable_upload).build_uploader }
+ let(:uploader) { create(:upload, :with_file, :issuable_upload).retrieve_uploader }
context "no dry run" do
it "removes exif from the image" do
diff --git a/spec/lib/gitlab_spec.rb b/spec/lib/gitlab_spec.rb
index ccb5cb3aa43..7e318017a05 100644
--- a/spec/lib/gitlab_spec.rb
+++ b/spec/lib/gitlab_spec.rb
@@ -71,26 +71,30 @@ describe Gitlab do
end
describe '.com?' do
+ before do
+ Thread.current[:is_com] = nil
+ end
+
it 'is true when on GitLab.com' do
- stub_config_setting(url: 'https://gitlab.com')
+ allow(LightSettings).to receive(:host).and_return('gitlab.com')
expect(described_class.com?).to eq true
end
it 'is true when on staging' do
- stub_config_setting(url: 'https://staging.gitlab.com')
+ allow(LightSettings).to receive(:host).and_return('staging.gitlab.com')
expect(described_class.com?).to eq true
end
it 'is true when on other gitlab subdomain' do
- stub_config_setting(url: 'https://example.gitlab.com')
+ allow(LightSettings).to receive(:host).and_return('example.gitlab.com')
expect(described_class.com?).to eq true
end
it 'is false when not on GitLab.com' do
- stub_config_setting(url: 'http://example.com')
+ allow(LightSettings).to receive(:host).and_return('example.com')
expect(described_class.com?).to eq false
end
diff --git a/spec/models/commit_collection_spec.rb b/spec/models/commit_collection_spec.rb
index a8957bbfdd0..d49b71db5f8 100644
--- a/spec/models/commit_collection_spec.rb
+++ b/spec/models/commit_collection_spec.rb
@@ -149,6 +149,17 @@ describe CommitCollection do
collection.enrich!
end
+
+ it 'returns the original commit if the commit could not be lazy loaded' do
+ collection = described_class.new(project, [hash_commit])
+ unexisting_lazy_commit = Commit.lazy(project, Gitlab::Git::BLANK_SHA)
+
+ expect(Commit).to receive(:lazy).with(project, hash_commit.id).and_return(unexisting_lazy_commit)
+
+ collection.enrich!
+
+ expect(collection.commits).to contain_exactly(hash_commit)
+ end
end
end
diff --git a/spec/models/upload_spec.rb b/spec/models/upload_spec.rb
index d97bb8cfb90..03434c95218 100644
--- a/spec/models/upload_spec.rb
+++ b/spec/models/upload_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
describe Upload do
- describe 'assocations' do
+ describe 'associations' do
it { is_expected.to belong_to(:model) }
end
@@ -107,6 +107,52 @@ describe Upload do
end
end
+ describe '#build_uploader' do
+ it 'returns a uploader object with current upload associated with it' do
+ subject = build(:upload)
+ uploader = subject.build_uploader
+
+ expect(uploader.upload).to eq(subject)
+ expect(uploader.mounted_as).to eq(subject.send(:mount_point))
+ expect(uploader.file).to be_nil
+ end
+ end
+
+ describe '#retrieve_uploader' do
+ it 'returns a uploader object with current uploader associated with and cache retrieved' do
+ subject = build(:upload)
+ uploader = subject.retrieve_uploader
+
+ expect(uploader.upload).to eq(subject)
+ expect(uploader.mounted_as).to eq(subject.send(:mount_point))
+ expect(uploader.file).not_to be_nil
+ end
+ end
+
+ describe '#needs_checksum?' do
+ context 'with local storage' do
+ it 'returns true when no checksum exists' do
+ subject = create(:upload, :with_file, checksum: nil)
+
+ expect(subject.needs_checksum?).to be_truthy
+ end
+
+ it 'returns false when checksum is already present' do
+ subject = create(:upload, :with_file, checksum: 'something')
+
+ expect(subject.needs_checksum?).to be_falsey
+ end
+ end
+
+ context 'with remote storage' do
+ subject { build(:upload, :object_storage) }
+
+ it 'returns false' do
+ expect(subject.needs_checksum?).to be_falsey
+ end
+ end
+ end
+
describe '#exist?' do
it 'returns true when the file exists' do
upload = described_class.new(path: __FILE__, store: ObjectStorage::Store::LOCAL)
diff --git a/spec/models/uploads/fog_spec.rb b/spec/models/uploads/fog_spec.rb
index 4a44cf5ab0f..b93d9449da9 100644
--- a/spec/models/uploads/fog_spec.rb
+++ b/spec/models/uploads/fog_spec.rb
@@ -44,7 +44,7 @@ describe Uploads::Fog do
subject { data_store.delete_keys(keys) }
before do
- uploads.each { |upload| upload.build_uploader.migrate!(2) }
+ uploads.each { |upload| upload.retrieve_uploader.migrate!(2) }
end
it 'deletes multiple data' do
diff --git a/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb b/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
index 4bc22861d58..0b4ab9941fc 100644
--- a/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
@@ -104,7 +104,7 @@ shared_examples 'handle uploads' do
context "when neither the uploader nor the model exists" do
before do
- allow_any_instance_of(Upload).to receive(:build_uploader).and_return(nil)
+ allow_any_instance_of(Upload).to receive(:retrieve_uploader).and_return(nil)
allow(controller).to receive(:find_model).and_return(nil)
end
diff --git a/spec/support/shared_examples/models/with_uploads_shared_examples.rb b/spec/support/shared_examples/models/with_uploads_shared_examples.rb
index eb1ade03017..822836c771e 100644
--- a/spec/support/shared_examples/models/with_uploads_shared_examples.rb
+++ b/spec/support/shared_examples/models/with_uploads_shared_examples.rb
@@ -41,7 +41,8 @@ shared_examples_for 'model with uploads' do |supports_fileuploads|
end
it 'deletes remote files' do
- expect_any_instance_of(Uploads::Fog).to receive(:delete_keys).with(uploads.map(&:path))
+ expected_array = array_including(*uploads.map(&:path))
+ expect_any_instance_of(Uploads::Fog).to receive(:delete_keys).with(expected_array)
model_object.destroy
end
diff --git a/spec/uploaders/file_uploader_spec.rb b/spec/uploaders/file_uploader_spec.rb
index 04206de3dc6..3c14edc7e0e 100644
--- a/spec/uploaders/file_uploader_spec.rb
+++ b/spec/uploaders/file_uploader_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe FileUploader do
let(:group) { create(:group, name: 'awesome') }
let(:project) { create(:project, :legacy_storage, namespace: group, name: 'project') }
- let(:uploader) { described_class.new(project) }
+ let(:uploader) { described_class.new(project, :avatar) }
let(:upload) { double(model: project, path: 'secret/foo.jpg') }
subject { uploader }
@@ -184,6 +184,14 @@ describe FileUploader do
end
end
+ describe '#replace_file_without_saving!' do
+ let(:replacement) { Tempfile.create('replacement.jpg') }
+
+ it 'replaces an existing file without changing its metadata' do
+ expect { subject.replace_file_without_saving! CarrierWave::SanitizedFile.new(replacement) }.not_to change { subject.upload }
+ end
+ end
+
context 'when remote file is used' do
let(:temp_file) { Tempfile.new("test") }
diff --git a/spec/uploaders/gitlab_uploader_spec.rb b/spec/uploaders/gitlab_uploader_spec.rb
index 3bee4875348..4425dd947c0 100644
--- a/spec/uploaders/gitlab_uploader_spec.rb
+++ b/spec/uploaders/gitlab_uploader_spec.rb
@@ -69,6 +69,16 @@ describe GitlabUploader do
end
end
+ describe '#replace_file_without_saving!' do
+ it 'allows file to be replaced without triggering any callbacks' do
+ new_file = CarrierWave::SanitizedFile.new(Tempfile.new)
+
+ expect(subject).not_to receive(:with_callbacks)
+
+ subject.replace_file_without_saving!(new_file)
+ end
+ end
+
describe '#open' do
context 'when trace is stored in File storage' do
context 'when file exists' do
diff --git a/spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb b/spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb
index 6c2544d2efd..97e8a43f7fd 100644
--- a/spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb
+++ b/spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb
@@ -42,33 +42,23 @@ describe ObjectStorage::MigrateUploadsWorker, :sidekiq do
end
describe '.sanity_check!' do
- shared_examples 'raises a SanityCheckError' do
+ shared_examples 'raises a SanityCheckError' do |expected_message|
let(:mount_point) { nil }
it do
expect { described_class.sanity_check!(uploads, model_class, mount_point) }
- .to raise_error(described_class::SanityCheckError)
+ .to raise_error(described_class::SanityCheckError).with_message(expected_message)
end
end
- before do
- stub_const("WrongModel", Class.new)
- end
-
context 'uploader types mismatch' do
let!(:outlier) { create(:upload, uploader: 'GitlabUploader') }
- include_examples 'raises a SanityCheckError'
- end
-
- context 'model types mismatch' do
- let!(:outlier) { create(:upload, model_type: 'WrongModel') }
-
- include_examples 'raises a SanityCheckError'
+ include_examples 'raises a SanityCheckError', /Multiple uploaders found/
end
context 'mount point not found' do
- include_examples 'raises a SanityCheckError' do
+ include_examples 'raises a SanityCheckError', /Mount point [a-z:]+ not found in/ do
let(:mount_point) { :potato }
end
end