Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stricter linter #125

Merged
merged 9 commits into from
May 13, 2024
2 changes: 1 addition & 1 deletion .buildkite/pipeline.deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ steps:
- label: ":hammer: Linting"
command:
- cd app && bundle install
- rubocop -l
- rubocop
plugins:
- docker#v5.10.0:
image: ruby:3.3.1
Expand Down
2 changes: 1 addition & 1 deletion .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ steps:
- label: ":hammer: Linting"
command:
- cd app && bundle install
- rubocop -l
- rubocop
plugins:
- docker#v5.10.0:
image: ruby:3.3.1
Expand Down
17 changes: 17 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# EditorConfig is awesome: https://EditorConfig.org

# top-most EditorConfig file
root = true

# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
trim_trailing_whitespace = true

# Matches multiple files with brace expansion notation
# Set default charset
[*.rb]
indent_style = space
indent_size = 2
7 changes: 6 additions & 1 deletion app/.rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
AllCops:
TargetRubyVersion: 3.2
TargetRubyVersion: 3.3
NewCops: enable

Style/HashSyntax:
Expand All @@ -8,6 +8,11 @@ Style/HashSyntax:
Naming/BlockForwarding:
EnforcedStyle: explicit

# TODO: solve this
Metrics/BlockLength:
Exclude:
- spec/**/*.rb

Metrics/MethodLength:
CountAsOne: [ 'array', 'hash', 'heredoc' ]

Expand Down
39 changes: 39 additions & 0 deletions app/lib/bk/compat/parsers/bitbucket/clone.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# frozen_string_literal: true

require_relative '../../pipeline/step'
require_relative '../../pipeline/plugin'

module BK
module Compat
module BitBucketSteps
# Translatio of clone options
class Step
def translate_clone(opts)
sparse_checkout = opts.delete('sparse-checkout')
enabled = opts.delete('enabled')
msg = '# repository interactions (clone options) should be configured in the agent itself'

# nothing specified
return [] if sparse_checkout.nil? && enabled.nil? && opts.empty?

BK::Compat::CommandStep.new(commands: msg).tap do |cmd|
cmd.env['BUILKITE_REPO'] = '' unless enabled.nil? || enabled
cmd << sparse_checkout_plugin(sparse_checkout)
end
end

def sparse_checkout_plugin(conf)
return [] if conf.nil? || !conf.fetch('enabled', true)

BK::Compat::Plugin.new(
name: 'sparse-checkout',
config: {
'paths' => conf['patterns'],
'no-cone' => !conf.fetch('cone-mode', true)
}
)
end
end
end
end
end
28 changes: 1 addition & 27 deletions app/lib/bk/compat/parsers/bitbucket/steps.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# frozen_string_literal: true

require_relative '../../pipeline/step'
require_relative '../../pipeline/plugin'

require_relative 'caches'
require_relative 'clone'
require_relative 'image'
require_relative 'services'
require_relative 'shared'
Expand Down Expand Up @@ -97,32 +97,6 @@ def translate_oidc(enabled)
]
end

def translate_clone(opts)
sparse_checkout = opts.delete('sparse-checkout')
enabled = opts.delete('enabled')
msg = '# repository interactions (clone options) should be configured in the agent itself'

# nothing specified
return [] if sparse_checkout.nil? && enabled.nil? && opts.empty?

BK::Compat::CommandStep.new(commands: msg).tap do |cmd|
cmd.env['BUILKITE_REPO'] = '' unless enabled.nil? || enabled
cmd << sparse_checkout_plugin(sparse_checkout)
end
end

def sparse_checkout_plugin(conf)
return [] if conf.nil? || !conf.fetch('enabled', true)

BK::Compat::Plugin.new(
name: 'sparse-checkout',
config: {
'paths' => conf['patterns'],
'no-cone' => !conf.fetch('cone-mode', true)
}
)
end

def translate_agents(conf)
{}.tap do |h|
h[:size] = conf['size'] if conf.include?('size')
Expand Down
94 changes: 94 additions & 0 deletions app/lib/bk/compat/parsers/circleci/docker.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# frozen_string_literal: true

require_relative '../../pipeline/plugin'
require_relative '../../pipeline/step'

module BK
module Compat
# CircleCI translation of workflows
class CircleCI
private

def executor_docker(config)
first, *rest = config # split first configuration

BK::Compat::CircleCISteps::CircleCIStep.new.tap do |step|
step.agents['executor_type'] = 'docker'
step << executor_docker_auth_plugin(first.fetch('auth', {}))
step << executor_docker_aws_auth(first.fetch('aws-auth', {}))

step << (rest.empty? ? executor_docker_plugin(first) : executor_docker_compose_plugin(first, *rest))
end
end

def executor_docker_auth_plugin(auth_config)
return [] if auth_config.empty?

BK::Compat::Plugin.new(
name: 'docker-login',
config: {
'username' => auth_config['username'],
'password-env' => auth_config['password'].ltrim('$')
}
)
end

def executor_docker_aws_auth(config)
return [] if config.empty?

url_regex = '^(?:[^/]+//)?(?<account-ids>\d+).dkr.ecr.(?<region>[^.]+).amazonaws.com'
cfg = config['image'].match(url_regex).named_captures

cfg[:login] = true
cfg['assume-role'] = { 'role-arn' => config['oidc_role_arn'] } if config.include?('oidc_role_arn')

BK::Compat::CircleCISteps::CircleCIStep.new(
plugins: [BK::Compat::Plugin.new(name: 'ecr', config: cfg)]
).tap do |step|
if config.include?('aws_access_key_id')
step.add_commands('# Configure the agent to have the appropriate credentials for ECR auth')
end
end
end

def executor_docker_plugin(config)
plugin_config = config.slice('image', 'entrypoint', 'user', 'command', 'environment')
plugin_config['add-host'] = "${config['name']}:127.0.0.1" if config.include?('name')

BK::Compat::Plugin.new(
name: 'docker',
config: plugin_config
)
end

def executor_docker_compose_plugin(*apps)
containers = {}
apps.each_with_index do |app, i|
config = app.slice('image', 'entrypoint', 'user', 'command', 'environment')
name = config.fetch('name', "service#{i}")

containers[name] = config
end

conf = { 'services' => containers }
cmds = [
'# to make multiple images work, add the following composefile to your repository',
"cat > compose.yaml << EOF\n#{conf.to_yaml}\nEOF"
]
plugin_config = { 'run' => apps[0].fetch('name', 'service0') }

BK::Compat::CircleCISteps::CircleCIStep.new(
key: 'docker compose',
commands: cmds,
agents: { 'executor_type' => 'docker_compose' },
plugins: [
BK::Compat::Plugin.new(
name: 'docker-compose',
config: plugin_config
)
]
)
end
end
end
end
90 changes: 4 additions & 86 deletions app/lib/bk/compat/parsers/circleci/executors.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# frozen_string_literal: true

require_relative 'steps'
require_relative '../../pipeline/plugin'
require_relative '../../pipeline/step'

require_relative 'docker'

module BK
module Compat
Expand Down Expand Up @@ -43,91 +46,6 @@ def parse_executor(type: nil, conf: {}, working_directory: nil, shell: nil, reso
end
end

def executor_docker(config)
first, *rest = config # split first configuration

BK::Compat::CircleCISteps::CircleCIStep.new.tap do |step|
step.agents['executor_type'] = 'docker'
step << executor_docker_auth_plugin(first.fetch('auth', {}))
step << executor_docker_aws_auth(first.fetch('aws-auth', {}))

step << (rest.empty? ? executor_docker_plugin(first) : executor_docker_compose_plugin(first, *rest))
end
end

def executor_docker_auth_plugin(auth_config)
return [] if auth_config.empty?

BK::Compat::Plugin.new(
name: 'docker-login',
config: {
'username' => auth_config['username'],
'password-env' => auth_config['password'].ltrim('$')
}
)
end

def executor_docker_aws_auth(config)
return [] if config.empty?

BK::Compat::CircleCISteps::CircleCIStep.new.tap do |step|
if config.include?('aws_access_key_id')
step.add_commands('# Configure the agent to have the appropriate credentials for ECR auth')
end

url_regex = '^(?:[^/]+//)?(\d+).dkr.ecr.([^.]+).amazonaws.com'
account_id, region = config['image'].match(url_regex).captures
cfg = {
'login' => true,
'account-ids' => account_id,
'region' => region
}

cfg['assume-role'] = { 'role-arn' => config['oidc_role_arn'] } if config.include?('oidc_role_arn')

step << BK::Compat::Plugin.new(name: 'ecr', config: cfg)
end
end

def executor_docker_plugin(config)
plugin_config = config.slice('image', 'entrypoint', 'user', 'command', 'environment')
plugin_config['add-host'] = "${config['name']}:127.0.0.1" if config.include?('name')

BK::Compat::Plugin.new(
name: 'docker',
config: plugin_config
)
end

def executor_docker_compose_plugin(*apps)
containers = {}
apps.each_with_index do |app, i|
config = app.slice('image', 'entrypoint', 'user', 'command', 'environment')
name = config.fetch('name', "service#{i}")

containers[name] = config
end

conf = { 'services' => containers }
cmds = [
'# to make multiple images work, add the following composefile to your repository',
"cat > compose.yaml << EOF\n#{conf.to_yaml}\nEOF"
]
plugin_config = { 'run' => apps[0].fetch('name', 'service0') }

BK::Compat::CircleCISteps::CircleCIStep.new(
key: 'docker compose',
commands: cmds,
agents: { 'executor_type' => 'docker_compose' },
plugins: [
BK::Compat::Plugin.new(
name: 'docker-compose',
config: plugin_config
)
]
)
end

def executor_machine(config)
config = { 'image' => 'self-hosted' } if config == true
BK::Compat::CircleCISteps::CircleCIStep.new.tap do |step|
Expand Down
8 changes: 4 additions & 4 deletions app/lib/bk/compat/parsers/gha/jobs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ class GitHubActions
def parse_job(name, config)
bk_step = generate_base_step(name, config)
bk_step << translate_concurrency(config['concurrency'])
bk_step.matrix = generate_matrix(config['strategy']&.fetch('matrix'))
config['steps'].each { |step| bk_step << @translator.translate_step(step) }
bk_step.agents.update(config.slice('runs-on'))
bk_step.conditional = generate_if(config['if'])

# these two should be last because they need to execute commands at the end
bk_step << translate_outputs(config['outputs'], name)
Expand All @@ -31,7 +28,10 @@ def generate_base_step(name, config)
depends_on: Array(config['needs']),
env: config.fetch('env', {}),
timeout_in_minutes: config['timeout-minutes'],
soft_fail: config['continue-on-error']
soft_fail: config['continue-on-error'],
conditional: generate_if(config['if']),
agents: config.slice('runs-on'),
matrix: generate_matrix(config['strategy']&.fetch('matrix'))
)
end

Expand Down
19 changes: 11 additions & 8 deletions app/lib/bk/compat/parsers/gha/steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,20 @@ def translator(step)
private

def generate_command_string(commands: [], env: {}, workdir: nil, id: nil)
cwd = "cd '#{workdir}'" unless workdir.nil?
vars = env.map { |k, v| "#{k}=\"#{v}\"" }
cmds = commands.lines(chomp: true)
step_id = "#{BK::Compat.var_name(id, 'GHA_STEP')}=\"$$?\"" unless id.nil?

avoid_parens = vars.empty? && workdir.nil? && (id.nil? || cmds.one?)
[
avoid_parens ? nil : '(',
workdir.nil? ? nil : "cd '#{workdir}'",
vars.empty? ? nil : vars,
cmds,
avoid_parens ? nil : ')',
id.nil? ? nil : "#{BK::Compat.var_name(id, 'GHA_STEP')}=\"$$?\""
].compact

ret = parens(avoid_parens, [cwd, vars, cmds]) + [step_id]

ret.flatten.compact
end

def parens(skip, arr)
skip ? arr : ['('] + arr + [')']
end
end

Expand Down
Loading