# typed: strict module CodeOwnership module Private module Validations class GithubCodeownersUpToDate extend T::Sig extend T::Helpers include Interface sig { override.params(files: T::Array[String], autocorrect: T::Boolean, stage_changes: T::Boolean).returns(T::Array[String]) } def validation_errors(files:, autocorrect: true, stage_changes: true) return [] if Private.configuration.skip_codeowners_validation codeowners_filepath = Pathname.pwd.join('.github/CODEOWNERS') FileUtils.mkdir_p(codeowners_filepath.dirname) if !codeowners_filepath.dirname.exist? header = <<~HEADER # STOP! - DO NOT EDIT THIS FILE MANUALLY # This file was automatically generated by "bin/codeownership validate". # # CODEOWNERS is used for GitHub to suggest code/file owners to various GitHub # teams. This is useful when developers create Pull Requests since the # code/file owner is notified. Reference GitHub docs for more details: # https://help.github.com/en/articles/about-code-owners HEADER contents = [ header, *codeowners_file_lines, nil, # For end-of-file newline ].join("\n") codeowners_up_to_date = codeowners_filepath.exist? && codeowners_filepath.read == contents errors = T.let([], T::Array[String]) if !codeowners_up_to_date if autocorrect codeowners_filepath.write(contents) if stage_changes `git add #{codeowners_filepath}` end else errors << "CODEOWNERS out of date. Ensure pre-commit hook is set up correctly and used. You can also run bin/codeownership validate to update the CODEOWNERS file\n" end end errors end private # Generate the contents of a CODEOWNERS file that GitHub can use to # automatically assign reviewers # https://help.github.com/articles/about-codeowners/ sig { returns(T::Array[String]) } def codeowners_file_lines github_team_map = Teams.all.each_with_object({}) do |team, map| team_github = TeamPlugins::Github.for(team).github next if team_github.do_not_add_to_codeowners_file map[team.name] = team_github.team end Private.mappers.flat_map do |mapper| codeowners_lines = mapper.codeowners_lines_to_owners.filter_map do |line, team| team_mapping = github_team_map[team&.name] next unless team_mapping "/#{line} #{team_mapping}" end next [] if codeowners_lines.empty? [ '', "# #{mapper.description}", *codeowners_lines.sort, ] end end end end end end