Skip to content
代码片段 群组 项目
提交 a4341683 编辑于 作者: Lin Jen-Shin's avatar Lin Jen-Shin
浏览文件

Add a script to generate the auth section for CODEOWNER

上级 0b1972a0
No related branches found
No related tags found
无相关合并请求
# frozen_string_literal: true
require_relative '../../../../tooling/lib/tooling/find_codeowners'
RSpec.describe Tooling::FindCodeowners do
describe '#run' do
before do
allow(described_class).to receive(:git_ls_files).and_return(<<~LINES)
dir/0/0/0
dir/0/0/2
dir/0/1
dir/1
dir/2
LINES
find_results = {
'dir/0/0' => "dir/0/0\ndir/0/0/0\ndir/0/0/2\n",
'dir/0' => "dir/0\ndir/0/0/0\ndir/0/0/2\ndir/0/1\n",
'dir' => "dir\ndir/0/0/0\ndir/0/0/2\ndir/0/1\ndir/1\ndir/2\n"
}
allow(described_class).to receive(:find_dir_maxdepth_1) do |dir|
find_results[dir]
end
allow(described_class).to receive(:load_config).and_return(
'[Section name]': {
'@group': {
allow: {
keywords: ['dir'],
patterns: ['/%{keyword}/**/*']
},
deny: {
keywords: ['1'],
patterns: ['**/%{keyword}']
}
}
}
)
end
it 'prints CODEOWNERS as configured' do
expect { described_class.run }.to output(<<~CODEOWNERS).to_stdout
[Section name]
/dir/0/0 @group
/dir/2 @group
CODEOWNERS
end
end
describe '#load_definitions' do
it 'expands the allow and deny list with keywords and patterns' do
described_class.load_definitions.each do |section, group_defintions|
group_defintions.each do |group, definitions|
expect(definitions[:allow]).to be_an(Array)
expect(definitions[:deny]).to be_an(Array)
end
end
end
it 'expands the auth group' do
auth = described_class.load_definitions.dig(
:'[Authentication and Authorization]',
:'@gitlab-org/manage/authentication-and-authorization')
expect(auth).to eq(
allow: %w[
/{,ee/}app/**/*password*{/**/*,}
/{,ee/}config/**/*password*{/**/*,}
/{,ee/}lib/**/*password*{/**/*,}
/{,ee/}app/**/*auth*{/**/*,}
/{,ee/}config/**/*auth*{/**/*,}
/{,ee/}lib/**/*auth*{/**/*,}
/{,ee/}app/**/*token*{/**/*,}
/{,ee/}config/**/*token*{/**/*,}
/{,ee/}lib/**/*token*{/**/*,}
],
deny: %w[
**/*author.*{/**/*,}
**/*author_*{/**/*,}
**/*authored*{/**/*,}
**/*authoring*{/**/*,}
**/*.png*{/**/*,}
**/*.svg*{/**/*,}
**/*deploy_token*{/**/*,}
**/*runner{,s}_token*{/**/*,}
**/*job_token*{/**/*,}
**/*tokenizer*{/**/*,}
**/*filtered_search*{/**/*,}
]
)
end
end
describe '#load_config' do
it 'loads the config with symbolized keys' do
config = described_class.load_config
expect_hash_keys_to_be_symbols(config)
end
def expect_hash_keys_to_be_symbols(object)
if object.is_a?(Hash)
object.each do |key, value|
expect(key).to be_a(Symbol)
expect_hash_keys_to_be_symbols(value)
end
end
end
end
describe '#path_matches?' do
let(:pattern) { 'pattern' }
let(:path) { 'path' }
it 'passes flags we are expecting to File.fnmatch?' do
expected_flags =
::File::FNM_DOTMATCH | ::File::FNM_PATHNAME | ::File::FNM_EXTGLOB
expect(File).to receive(:fnmatch?).with(pattern, path, expected_flags)
described_class.path_matches?(pattern, path)
end
end
describe '#consolidate_paths' do
before do
allow(described_class).to receive(:find_dir_maxdepth_1).and_return(<<~LINES)
dir
dir/0
dir/2
dir/3
dir/1
LINES
end
context 'when the directory has the same number of entries' do
let(:input_paths) { %W[dir/0\n dir/1\n dir/2\n dir/3\n] }
it 'consolidates into the directory' do
paths = described_class.consolidate_paths(input_paths)
expect(paths).to eq(["dir\n"])
end
end
context 'when the directory has different number of entries' do
let(:input_paths) { %W[dir/0\n dir/1\n dir/2\n] }
it 'returns the original paths' do
paths = described_class.consolidate_paths(input_paths)
expect(paths).to eq(input_paths)
end
end
end
end
#!/usr/bin/env ruby
# frozen_string_literal: true
require_relative '../lib/tooling/find_codeowners'
Tooling::FindCodeowners.run
# This is supposed to be used with:
# tooling/bin/find_codeowners tooling/config/CODEOWNERS.yml
# And paste the contents into .gitlab/CODEOWNERS
'[Authentication and Authorization]':
'@gitlab-org/manage/authentication-and-authorization':
allow:
keywords:
- password
- auth
- token
patterns:
- '/{,ee/}app/**/*%{keyword}*{/**/*,}'
- '/{,ee/}config/**/*%{keyword}*{/**/*,}'
- '/{,ee/}lib/**/*%{keyword}*{/**/*,}'
deny:
keywords:
- author.
- author_
- authored
- authoring
- .png
- .svg
- deploy_token
- runner{,s}_token
- job_token
- tokenizer
- filtered_search
patterns:
- '**/*%{keyword}*{/**/*,}'
# frozen_string_literal: true
require 'yaml'
module Tooling
module FindCodeowners
module_function
def run
ls_files = git_ls_files
load_definitions.each do |section, group_defintions|
puts section
group_defintions.each do |group, allow:, deny:|
matched_files = ls_files.each_line.select do |line|
allow.find do |pattern|
path = "/#{line.chomp}"
path_matches?(pattern, path) &&
deny.none? { |pattern| path_matches?(pattern, path) }
end
end
consolidated = consolidate_paths(matched_files)
consolidated_again = consolidate_paths(consolidated)
while consolidated_again.size < consolidated.size
consolidated = consolidated_again
consolidated_again = consolidate_paths(consolidated)
end
consolidated.each do |file|
puts "/#{file.chomp} #{group}"
end
end
end
end
def load_definitions
result = load_config
result.each do |section, group_defintions|
group_defintions.each do |group, definitions|
definitions.transform_values! do |keywords:, patterns:|
keywords.flat_map do |keyword|
patterns.map do |pattern|
pattern % { keyword: keyword }
end
end
end
end
end
result
end
def load_config
config_path = "#{__dir__}/../../config/CODEOWNERS.yml"
if YAML.respond_to?(:safe_load_file) # Ruby 3.0+
YAML.safe_load_file(config_path, symbolize_names: true)
else
YAML.safe_load(File.read(config_path), symbolize_names: true)
end
end
# Copied and modified from ee/lib/gitlab/code_owners/file.rb
def path_matches?(pattern, path)
# `FNM_DOTMATCH` makes sure we also match files starting with a `.`
# `FNM_PATHNAME` makes sure ** matches path separators
flags = ::File::FNM_DOTMATCH | ::File::FNM_PATHNAME
# BEGIN extension
flags |= ::File::FNM_EXTGLOB
# END extension
::File.fnmatch?(pattern, path, flags)
end
def consolidate_paths(matched_files)
matched_files.group_by(&File.method(:dirname)).flat_map do |dir, files|
# First line is the dir itself
if find_dir_maxdepth_1(dir).lines.drop(1).sort == files.sort
"#{dir}\n"
else
files
end
end.sort
end
def git_ls_files
`git ls-files`
end
def find_dir_maxdepth_1(dir)
`find #{dir} -maxdepth 1`
end
end
end
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册