diff --git a/lib/tasks/gitlab/tw/codeowners.rake b/lib/tasks/gitlab/tw/codeowners.rake index 8d9aa4b03044e9fcd5c8e864ce9ed941a93b0e23..90a739e34d5f6b4d8b9b06520802316241bcdbf6 100644 --- a/lib/tasks/gitlab/tw/codeowners.rake +++ b/lib/tasks/gitlab/tw/codeowners.rake @@ -33,7 +33,7 @@ module TwCodeowners CodeOwnerRule.new('Composition Analysis', '@rdickenson'), CodeOwnerRule.new('Container Registry', '@z_painter'), CodeOwnerRule.new('Contributor Experience', '@eread'), - CodeOwnerRule.new('Custom Models', '@jglassman1'), + CodeOwnerRule.new('Custom Models', '@fneill'), # CodeOwnerRule.new('Database Frameworks', ''), # CodeOwnerRule.new('Database Operations', ''), # CodeOwnerRule.new('DataOps', ''), @@ -155,6 +155,151 @@ namespace :tw do task :codeowners do require 'yaml' + CodeOwnerRule = Struct.new(:category, :writer) + DocumentOwnerMapping = Struct.new(:path, :writer) do + def writer_owns_directory?(mappings) + dir_mappings = mappings.select { |mapping| mapping.directory == directory } + + dir_mappings.count { |mapping| mapping.writer == writer } / dir_mappings.length.to_f > 0.5 + end + + def directory + @directory ||= "#{File.dirname(path)}/" + end + end + + # For groups without an assigned TW, comment out the line. + CODE_OWNER_RULES = [ + # CodeOwnerRule.new('Activation', ''), + # CodeOwnerRule.new('Acquisition', ''), + CodeOwnerRule.new('Agent Foundations', '@sselhorn'), + CodeOwnerRule.new('AI Framework', '@sselhorn'), + # CodeOwnerRule.new('Analytics Instrumentation', ''), + CodeOwnerRule.new('Authentication', '@idurham'), + CodeOwnerRule.new('Authorization', '@idurham'), + CodeOwnerRule.new('Build', '@axil @eread'), + CodeOwnerRule.new('Cells Infrastructure', '@emily.sahlani'), + CodeOwnerRule.new('Code Creation', '@scawood'), + CodeOwnerRule.new('Code Review', '@aqualls'), + # CodeOwnerRule.new('Compliance', ''), + CodeOwnerRule.new('Composition Analysis', '@rdickenson'), + CodeOwnerRule.new('Container Registry', '@z_painter'), + CodeOwnerRule.new('Contributor Experience', '@eread'), + CodeOwnerRule.new('Custom Models', '@fneill'), + # CodeOwnerRule.new('Database Frameworks', ''), + # CodeOwnerRule.new('Database Operations', ''), + # CodeOwnerRule.new('DataOps', ''), + # CodeOwnerRule.new('Delivery', ''), + CodeOwnerRule.new('Durability', '@axil'), + CodeOwnerRule.new('Duo Chat', '@jglassman1'), + CodeOwnerRule.new('Dynamic Analysis', '@phillipwells'), + CodeOwnerRule.new('Editor Extensions', '@scawood'), + CodeOwnerRule.new('Engagement', '@kpaizee'), + # CodeOwnerRule.new('Environment Automation', ''), + # CodeOwnerRule.new('Environments', ''), + # CodeOwnerRule.new('Fulfillment Platform', ''), + CodeOwnerRule.new('Fuzz Testing', '@rdickenson'), + CodeOwnerRule.new('Geo', '@axil'), + CodeOwnerRule.new('Gitaly', '@eread'), + CodeOwnerRule.new('Global Search', '@ashrafkhamis'), + CodeOwnerRule.new('Remote Development', '@brendan777'), + CodeOwnerRule.new('Import', '@ashrafkhamis'), + CodeOwnerRule.new('Knowledge', '@msedlakjakubowski'), + # CodeOwnerRule.new('MLOps', ''), + # CodeOwnerRule.new('Mobile Devops', ''), + CodeOwnerRule.new('Optimize', '@lciutacu'), + CodeOwnerRule.new('Organizations', '@z_painter'), + CodeOwnerRule.new('Organization', '@lciutacu'), + CodeOwnerRule.new('Package Registry', '@z_painter'), + CodeOwnerRule.new('Pipeline Authoring', '@marcel.amirault'), + CodeOwnerRule.new('Pipeline Execution', '@lyspin'), + CodeOwnerRule.new('Pipeline Security', '@marcel.amirault'), + # CodeOwnerRule.new('Platform Insights', ''), + CodeOwnerRule.new('Product Planning', '@msedlakjakubowski'), + CodeOwnerRule.new('Project Management', '@msedlakjakubowski'), + CodeOwnerRule.new('Provision', '@lciutacu'), + CodeOwnerRule.new('Redirect', 'Redirect'), + # CodeOwnerRule.new('Respond', ''), + CodeOwnerRule.new('Runner', '@rsarangadharan'), + CodeOwnerRule.new('Hosted Runners', '@rsarangadharan'), + CodeOwnerRule.new('Seat Management', '@lciutacu'), + # CodeOwnerRule.new('Security Infrastructure', ''), + CodeOwnerRule.new('Security Platform Management', '@rlehmann1'), + CodeOwnerRule.new('Security Policies', '@rlehmann1'), + CodeOwnerRule.new('Secret Detection', '@phillipwells'), + CodeOwnerRule.new('Security Insights', '@rlehmann1'), + CodeOwnerRule.new('Operate', '@axil @eread'), + CodeOwnerRule.new('Solutions Architecture', '@jfullam @Darwinjs @sbrightwell'), + CodeOwnerRule.new('Source Code', '@brendan777'), + CodeOwnerRule.new('Static Analysis', '@rdickenson'), + CodeOwnerRule.new('Subscription Management', '@lciutacu'), + CodeOwnerRule.new('Switchboard', '@lyspin'), + CodeOwnerRule.new('Testing', '@eread'), + CodeOwnerRule.new('Tutorials', '@gl-docsteam'), + # CodeOwnerRule.new('US Public Sector Services', ''), + CodeOwnerRule.new('Utilization', '@lciutacu') + # CodeOwnerRule.new('Vulnerability Research', '') + ].freeze + + CONTRIBUTOR_DOCS_PATH = '/doc/development/' + CONTRIBUTOR_DOCS_CODE_OWNER_RULES = [ + CodeOwnerRule.new('AI Framework', '@gitlab-org/ai-powered'), + CodeOwnerRule.new('Analytics Instrumentation', + '@gitlab-org/analytics-section/product-analytics/engineers/frontend ' \ + '@gitlab-org/analytics-section/analytics-instrumentation/engineers'), + CodeOwnerRule.new('Authentication', '@gitlab-org/software-supply-chain-security/authentication/approvers'), + CodeOwnerRule.new('Authorization', '@gitlab-org/software-supply-chain-security/authorization/approvers'), + CodeOwnerRule.new('Build', '@gitlab-org/distribution'), + CodeOwnerRule.new('Cells Infrastructure', '@OmarQunsulGitlab @bmarjanovic'), + CodeOwnerRule.new('Compliance', + '@gitlab-org/govern/security-policies-frontend @gitlab-org/govern/threat-insights-frontend-team ' \ + '@gitlab-org/govern/threat-insights-backend-team'), + CodeOwnerRule.new('Composition Analysis', + '@gitlab-org/secure/composition-analysis-be @gitlab-org/secure/static-analysis'), + CodeOwnerRule.new('Documentation Guidelines', '@fneill @sselhorn'), + CodeOwnerRule.new('Duo Workflow', '@gitlab-org/ai-powered'), + CodeOwnerRule.new('Engineering Productivity', '@gl-dx/pipeline-maintainers'), + CodeOwnerRule.new('Engagement', '@gitlab-org/growth'), + CodeOwnerRule.new('Gitaly', '@proglottis @toon'), + CodeOwnerRule.new('Global Search', '@gitlab-org/search-team/migration-maintainers'), + CodeOwnerRule.new('Remote Development', + '@gitlab-org/maintainers/remote-development/backend @gitlab-org/maintainers/remote-development/frontend'), + CodeOwnerRule.new('Pipeline Authoring', '@gitlab-org/maintainers/cicd-verify'), + CodeOwnerRule.new('Pipeline Execution', '@gitlab-org/maintainers/cicd-verify'), + CodeOwnerRule.new('Platform Insights', '@gitlab-org/analytics-section/product-analytics/engineers/frontend'), + CodeOwnerRule.new('Organizations', '@abdwdd @alexpooley'), + CodeOwnerRule.new('Operate', '@gitlab-org/distribution'), + CodeOwnerRule.new('Threat Insights', '@gitlab-org/govern/threat-insights-frontend-team') + ].freeze + + ERRORS_EXCLUDED_FILES = [ + '/doc/architecture' + ].freeze + + CODEOWNERS_BLOCK_BEGIN = "# Begin rake-managed-docs-block" + CODEOWNERS_BLOCK_END = "# End rake-managed-docs-block" + + Document = Struct.new(:group, :redirect) do + def has_a_valid_group? + group && !redirect + end + + def missing_metadata? + !group && !redirect + end + end + + def self.writer_for_group(category, path) + rules = path.start_with?(CONTRIBUTOR_DOCS_PATH) ? CONTRIBUTOR_DOCS_CODE_OWNER_RULES : CODE_OWNER_RULES + writer = rules.find { |rule| rule.category == category }&.writer + + if writer.is_a?(String) || writer.nil? + writer + else + writer.call(path) + end + end + errors = [] mappings = []