From 7d8cc770b14b41fbe40181d447042dccdc45bff8 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 29 Mar 2023 03:12:19 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- tooling/bin/graphql_base_type_mappings | 9 ++ .../tooling/mappings/graphql_base_type_mappings.rb | 119 +++++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100755 tooling/bin/graphql_base_type_mappings create mode 100644 tooling/lib/tooling/mappings/graphql_base_type_mappings.rb (limited to 'tooling') diff --git a/tooling/bin/graphql_base_type_mappings b/tooling/bin/graphql_base_type_mappings new file mode 100755 index 00000000000..2fc06ab639f --- /dev/null +++ b/tooling/bin/graphql_base_type_mappings @@ -0,0 +1,9 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require_relative '../lib/tooling/mappings/graphql_base_type_mappings' + +changes_file = ARGV.shift +matching_tests_paths = ARGV.shift + +Tooling::Mappings::GraphqlBaseTypeMappings.new(changes_file, matching_tests_paths).execute diff --git a/tooling/lib/tooling/mappings/graphql_base_type_mappings.rb b/tooling/lib/tooling/mappings/graphql_base_type_mappings.rb new file mode 100644 index 00000000000..cd8b55d5820 --- /dev/null +++ b/tooling/lib/tooling/mappings/graphql_base_type_mappings.rb @@ -0,0 +1,119 @@ +# frozen_string_literal: true + +require 'active_support/inflector' + +require_relative 'base' +require_relative '../../../../lib/gitlab_edition' + +# If a GraphQL type class changed, we try to identify the other GraphQL types that potentially include this type. +module Tooling + module Mappings + class GraphqlBaseTypeMappings < Base + # Checks for the implements keyword, and graphql_base_types the class name + GRAPHQL_IMPLEMENTS_REGEXP = /implements[( ]([\w:]+)[)]?$/ + + # GraphQL types are a bit scattered in the codebase based on the edition. + # + # Also, a higher edition is able to include lower editions. + # e.g. EE can include FOSS GraphQL types, and JH can include all GraphQL types + GRAPHQL_TYPES_FOLDERS_FOSS = ['app/graphql/types'].freeze + GRAPHQL_TYPES_FOLDERS_EE = GRAPHQL_TYPES_FOLDERS_FOSS + ['ee/app/graphql/types', 'ee/app/graphql/ee/types'] + GRAPHQL_TYPES_FOLDERS_JH = GRAPHQL_TYPES_FOLDERS_EE + ['jh/app/graphql/types', 'jh/app/graphql/jh/types'] + GRAPHQL_TYPES_FOLDERS = { + nil => GRAPHQL_TYPES_FOLDERS_FOSS, + 'ee' => GRAPHQL_TYPES_FOLDERS_EE, + 'jh' => GRAPHQL_TYPES_FOLDERS_JH + }.freeze + + def initialize(changes_file, matching_tests_paths) + @matching_tests_paths = matching_tests_paths + @changed_files = read_array_from_file(changes_file) + end + + def execute + # We go through the available editions when searching for base types + # + # `nil` is the FOSS edition + matching_graphql_tests = ([nil] + ::GitlabEdition.extensions).flat_map do |edition| + hierarchy = types_hierarchies[edition] + + filter_files.flat_map do |graphql_file| + children_types = hierarchy[filename_to_class_name(graphql_file)] + next if children_types.empty? + + # We find the specs for the children GraphQL types that are implementing the current GraphQL Type + children_types.map { |filename| filename_to_spec_filename(filename) } + end + end.compact.uniq + + write_array_to_file(matching_tests_paths, matching_graphql_tests) + end + + def filter_files + changed_files.select do |filename| + filename.start_with?(*GRAPHQL_TYPES_FOLDERS.values.flatten.uniq) && + filename.end_with?('.rb') && + File.exist?(filename) + end + end + + # Regroup all GraphQL types (by edition) that are implementing another GraphQL type. + # + # The key is the type that is being implemented (e.g. NoteableInterface, TodoableInterface below) + # The value is an array of GraphQL type files that are implementing those types. + # + # Example output: + # + # { + # nil => { + # "NoteableInterface" => [ + # "app/graphql/types/alert_management/alert_type.rb", + # "app/graphql/types/design_management/design_type.rb" + # , "TodoableInterface" => [...] + # }, + # "ee" => { + # "NoteableInterface" => [ + # "app/graphql/types/alert_management/alert_type.rb", + # "app/graphql/types/design_management/design_type.rb", + # "ee/app/graphql/types/epic_type.rb"], + # "TodoableInterface"=> [...] + # } + # } + def types_hierarchies + return @types_hierarchies if @types_hierarchies + + @types_hierarchies = {} + GRAPHQL_TYPES_FOLDERS.each_key do |edition| + @types_hierarchies[edition] = Hash.new { |h, k| h[k] = [] } + + graphql_files_for_edition_glob = File.join("{#{GRAPHQL_TYPES_FOLDERS[edition].join(',')}}", '**', '*.rb') + Dir[graphql_files_for_edition_glob].each do |graphql_file| + graphql_base_types = File.read(graphql_file).scan(GRAPHQL_IMPLEMENTS_REGEXP) + next if graphql_base_types.empty? + + graphql_base_classes = graphql_base_types.flatten.map { |class_name| class_name.split('::').last } + graphql_base_classes.each do |graphql_base_class| + @types_hierarchies[edition][graphql_base_class] += [graphql_file] + end + end + end + + @types_hierarchies + end + + def filename_to_class_name(filename) + File.basename(filename, '.*').camelize + end + + def filename_to_spec_filename(filename) + spec_file = filename.sub('app', 'spec').sub('.rb', '_spec.rb') + + return spec_file if File.exist?(spec_file) + end + + private + + attr_reader :changed_files, :matching_tests_paths + end + end +end -- cgit v1.2.1