pipedream 0.1.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.cody/buildspec.yml +9 -0
- data/.cody/project.rb +4 -0
- data/.gitignore +16 -11
- data/.gitmodules +9 -0
- data/.rspec +1 -1
- data/CHANGELOG.md +34 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +112 -0
- data/Guardfile +19 -0
- data/LICENSE.txt +18 -17
- data/README.md +55 -21
- data/Rakefile +10 -2
- data/exe/pipe +14 -0
- data/exe/pipedream +14 -0
- data/lib/pipedream/autoloader.rb +21 -0
- data/lib/pipedream/aws_services/helpers.rb +71 -0
- data/lib/pipedream/aws_services.rb +20 -0
- data/lib/pipedream/build.rb +13 -0
- data/lib/pipedream/cli.rb +60 -0
- data/lib/pipedream/command.rb +82 -0
- data/lib/pipedream/completer/script.rb +6 -0
- data/lib/pipedream/completer/script.sh +10 -0
- data/lib/pipedream/completer.rb +159 -0
- data/lib/pipedream/core.rb +63 -0
- data/lib/pipedream/create.rb +12 -0
- data/lib/pipedream/delete.rb +27 -0
- data/lib/pipedream/deploy.rb +40 -0
- data/lib/pipedream/dsl/pipeline/approve.rb +34 -0
- data/lib/pipedream/dsl/pipeline/codebuild.rb +57 -0
- data/lib/pipedream/dsl/pipeline/github.rb +42 -0
- data/lib/pipedream/dsl/pipeline.rb +37 -0
- data/lib/pipedream/dsl/role.rb +50 -0
- data/lib/pipedream/dsl/schedule.rb +30 -0
- data/lib/pipedream/dsl/sns.rb +15 -0
- data/lib/pipedream/dsl/ssm.rb +22 -0
- data/lib/pipedream/dsl/webhook.rb +27 -0
- data/lib/pipedream/evaluate.rb +47 -0
- data/lib/pipedream/help/completion.md +22 -0
- data/lib/pipedream/help/completion_script.md +3 -0
- data/lib/pipedream/help/deploy.md +54 -0
- data/lib/pipedream/help/start.md +20 -0
- data/lib/pipedream/help.rb +9 -0
- data/lib/pipedream/init.rb +68 -0
- data/lib/pipedream/pipeline/s3_bucket.rb +88 -0
- data/lib/pipedream/pipeline.rb +61 -0
- data/lib/pipedream/role.rb +181 -0
- data/lib/pipedream/schedule.rb +99 -0
- data/lib/pipedream/sequence.rb +66 -0
- data/lib/pipedream/setting.rb +82 -0
- data/lib/pipedream/sns.rb +43 -0
- data/lib/pipedream/stack.rb +95 -0
- data/lib/pipedream/start.rb +84 -0
- data/lib/pipedream/update.rb +12 -0
- data/lib/pipedream/version.rb +1 -1
- data/lib/pipedream/webhook.rb +60 -0
- data/lib/pipedream.rb +18 -1
- data/lib/template/.pipedream/pipeline.rb.tt +40 -0
- data/lib/template/.pipedream/schedule.rb +3 -0
- data/lib/template/.pipedream/settings.yml +9 -0
- data/lib/template/.pipedream/sns.rb +14 -0
- data/pipedream.gemspec +25 -14
- data/vendor/aws_data/CHANGELOG.md +7 -0
- data/vendor/aws_data/Gemfile +4 -0
- data/vendor/aws_data/Gemfile.lock +48 -0
- data/vendor/aws_data/LICENSE.txt +21 -0
- data/vendor/aws_data/README.md +42 -0
- data/vendor/aws_data/Rakefile +6 -0
- data/vendor/aws_data/aws_data.gemspec +30 -0
- data/{bin → vendor/aws_data/bin}/console +1 -1
- data/{bin → vendor/aws_data/bin}/setup +0 -0
- data/vendor/aws_data/lib/aws_data/version.rb +3 -0
- data/vendor/aws_data/lib/aws_data.rb +91 -0
- data/vendor/aws_data/spec/aws_data_spec.rb +5 -0
- data/vendor/aws_data/spec/spec_helper.rb +14 -0
- data/vendor/cfn-status/Gemfile +4 -0
- data/vendor/cfn-status/Gemfile.lock +49 -0
- data/vendor/cfn-status/LICENSE.txt +21 -0
- data/vendor/cfn-status/README.md +56 -0
- data/vendor/cfn-status/Rakefile +6 -0
- data/vendor/cfn-status/bin/console +14 -0
- data/vendor/cfn-status/bin/setup +8 -0
- data/vendor/cfn-status/cfn-status.gemspec +30 -0
- data/vendor/cfn-status/lib/cfn/aws_service.rb +56 -0
- data/vendor/cfn-status/lib/cfn/status/version.rb +5 -0
- data/vendor/cfn-status/lib/cfn/status.rb +220 -0
- data/vendor/cfn-status/spec/cfn/status_spec.rb +81 -0
- data/vendor/cfn-status/spec/fixtures/cfn/stack-events-complete.json +1080 -0
- data/vendor/cfn-status/spec/fixtures/cfn/stack-events-in-progress.json +1080 -0
- data/vendor/cfn-status/spec/fixtures/cfn/stack-events-update-rollback-complete.json +1086 -0
- data/vendor/cfn-status/spec/spec_helper.rb +14 -0
- data/vendor/cfn_camelizer/CHANGELOG.md +10 -0
- data/vendor/cfn_camelizer/Gemfile +4 -0
- data/vendor/cfn_camelizer/LICENSE.txt +21 -0
- data/vendor/cfn_camelizer/README.md +40 -0
- data/vendor/cfn_camelizer/Rakefile +6 -0
- data/vendor/cfn_camelizer/bin/console +14 -0
- data/vendor/cfn_camelizer/bin/setup +8 -0
- data/vendor/cfn_camelizer/cfn_camelizer.gemspec +32 -0
- data/vendor/cfn_camelizer/lib/camelizer.yml +27 -0
- data/vendor/cfn_camelizer/lib/cfn_camelizer/version.rb +3 -0
- data/vendor/cfn_camelizer/lib/cfn_camelizer.rb +92 -0
- data/vendor/cfn_camelizer/spec/cfn_camelizer_spec.rb +79 -0
- data/vendor/cfn_camelizer/spec/spec_helper.rb +14 -0
- metadata +295 -23
- data/.travis.yml +0 -7
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'thor'
|
3
|
+
|
4
|
+
module Pipedream
|
5
|
+
class Sequence < Thor::Group
|
6
|
+
include AwsServices
|
7
|
+
include Thor::Actions
|
8
|
+
|
9
|
+
add_runtime_options! # force, pretend, quiet, skip options
|
10
|
+
# https://github.com/erikhuda/thor/blob/master/lib/thor/actions.rb#L49
|
11
|
+
|
12
|
+
def self.source_paths
|
13
|
+
[File.expand_path("../../template", __FILE__)]
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def override_source_paths(*paths)
|
18
|
+
# Using string with instance_eval because block doesnt have access to
|
19
|
+
# path at runtime.
|
20
|
+
self.class.instance_eval %{
|
21
|
+
def self.source_paths
|
22
|
+
#{paths.flatten.inspect}
|
23
|
+
end
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def sync_template_repo
|
28
|
+
unless git_installed?
|
29
|
+
abort "Unable to detect git installation on your system. Git needs to be installed in order to use the --template option."
|
30
|
+
end
|
31
|
+
|
32
|
+
template_path = "#{ENV['HOME']}/.pipedream/templates/#{full_repo_name}"
|
33
|
+
if File.exist?(template_path)
|
34
|
+
sh("cd #{template_path} && git pull")
|
35
|
+
else
|
36
|
+
FileUtils.mkdir_p(File.dirname(template_path))
|
37
|
+
sh("git clone #{repo_url} #{template_path}")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def full_repo_name
|
42
|
+
full_repo = options[:template].split("/")[-2..-1].join("/")
|
43
|
+
full_repo = full_repo.split(":").last
|
44
|
+
full_repo.sub(".git", "")
|
45
|
+
end
|
46
|
+
|
47
|
+
# normalize repo_url
|
48
|
+
def repo_url
|
49
|
+
template = options[:template]
|
50
|
+
if template.include?('github.com')
|
51
|
+
template # leave as is, user has provided full github url
|
52
|
+
else
|
53
|
+
"https://github.com/#{template}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def git_installed?
|
58
|
+
system("type git > /dev/null")
|
59
|
+
end
|
60
|
+
|
61
|
+
def sh(command)
|
62
|
+
puts "=> #{command}"
|
63
|
+
system(command)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'render_me_pretty'
|
3
|
+
|
4
|
+
module Pipedream
|
5
|
+
class Setting
|
6
|
+
extend Memoist
|
7
|
+
def initialize(check_codepipeline_project=true)
|
8
|
+
@check_codepipeline_project = check_codepipeline_project
|
9
|
+
end
|
10
|
+
|
11
|
+
# data contains the settings.yml config. The order or precedence for settings
|
12
|
+
# is the project ufo/settings.yml and then the ~/.pipedream/settings.yml.
|
13
|
+
def data
|
14
|
+
Pipedream.check_codepipeline_project! if @check_codepipeline_project
|
15
|
+
return {} unless File.exist?(project_settings_path)
|
16
|
+
|
17
|
+
# project based settings files
|
18
|
+
project = load_file(project_settings_path)
|
19
|
+
|
20
|
+
user_file = "#{ENV['HOME']}/.pipedream/settings.yml"
|
21
|
+
user = File.exist?(user_file) ? YAML.load_file(user_file) : {}
|
22
|
+
|
23
|
+
default_file = File.expand_path("default/settings.yml", __dir__)
|
24
|
+
default = load_file(default_file)
|
25
|
+
|
26
|
+
all_envs = default.deep_merge(user.deep_merge(project))
|
27
|
+
all_envs = merge_base(all_envs)
|
28
|
+
data = all_envs[pipe_env] || all_envs["base"] || {}
|
29
|
+
data.deep_symbolize_keys
|
30
|
+
end
|
31
|
+
memoize :data
|
32
|
+
|
33
|
+
# Resolves infinite problem since Pipedream.env can be determined from PIPE_ENV or settings.yml files.
|
34
|
+
# When ufo is determined from settings it should not called Pipedream.env since that in turn calls
|
35
|
+
# Settings.new.data which can then cause an infinite loop.
|
36
|
+
def pipe_env
|
37
|
+
path = "#{cb_root}/.pipedream/settings.yml"
|
38
|
+
if File.exist?(path)
|
39
|
+
settings = YAML.load_file(path)
|
40
|
+
env = settings.find do |_env, section|
|
41
|
+
section ||= {}
|
42
|
+
ENV['AWS_PROFILE'] && ENV['AWS_PROFILE'] == section['aws_profile']
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
pipe_env = env.first if env
|
47
|
+
pipe_env = ENV['PIPE_ENV'] if ENV['PIPE_ENV'] # highest precedence
|
48
|
+
pipe_env || 'development'
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
def load_file(path)
|
53
|
+
return Hash.new({}) unless File.exist?(path)
|
54
|
+
|
55
|
+
content = RenderMePretty.result(path)
|
56
|
+
data = YAML.load(content)
|
57
|
+
# If key is is accidentally set to nil it screws up the merge_base later.
|
58
|
+
# So ensure that all keys with nil value are set to {}
|
59
|
+
data.each do |env, _setting|
|
60
|
+
data[env] ||= {}
|
61
|
+
end
|
62
|
+
data
|
63
|
+
end
|
64
|
+
|
65
|
+
# automatically add base settings to the rest of the environments
|
66
|
+
def merge_base(all_envs)
|
67
|
+
base = all_envs["base"] || {}
|
68
|
+
all_envs.each do |env, settings|
|
69
|
+
all_envs[env] = base.merge(settings) unless env == "base"
|
70
|
+
end
|
71
|
+
all_envs
|
72
|
+
end
|
73
|
+
|
74
|
+
def project_settings_path
|
75
|
+
"#{cb_root}/.pipedream/settings.yml"
|
76
|
+
end
|
77
|
+
|
78
|
+
def cb_root
|
79
|
+
ENV["CODEPIPELINE_ROOT"] || Dir.pwd
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Pipedream
|
2
|
+
class Sns
|
3
|
+
include Pipedream::Dsl::Sns
|
4
|
+
include Evaluate
|
5
|
+
|
6
|
+
def initialize(options={})
|
7
|
+
@options = options
|
8
|
+
@sns_path = options[:sns_path] || get_sns_path
|
9
|
+
@properties = default_properties
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
evaluate(@sns_path) if File.exist?(@sns_path)
|
14
|
+
|
15
|
+
resource = {
|
16
|
+
sns_topic: {
|
17
|
+
type: "AWS::SNS::Topic",
|
18
|
+
properties: @properties
|
19
|
+
}
|
20
|
+
}
|
21
|
+
CfnCamelizer.transform(resource)
|
22
|
+
end
|
23
|
+
|
24
|
+
def default_properties
|
25
|
+
display_name = "#{@options[:full_pipeline_name]} pipeline"
|
26
|
+
{
|
27
|
+
display_name: display_name,
|
28
|
+
# kms_master_key_id: "string",
|
29
|
+
# subscription: [{
|
30
|
+
# endpoint: '',
|
31
|
+
# protocol: ','
|
32
|
+
# }],
|
33
|
+
# topic_name: "string", # Not setting because update requires: Replacement. Dont want 2 pipelines to collide
|
34
|
+
}
|
35
|
+
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sns-subscription.html
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def get_sns_path
|
40
|
+
lookup_codepipeline_file("sns.rb")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require "aws-sdk-cloudformation"
|
2
|
+
|
3
|
+
module Pipedream
|
4
|
+
class Stack
|
5
|
+
include AwsServices
|
6
|
+
|
7
|
+
def initialize(options)
|
8
|
+
@options = options
|
9
|
+
@pipeline_name = @options[:pipeline_name] || inferred_pipeline_name
|
10
|
+
@stack_name = options[:stack_name] || inferred_stack_name(@pipeline_name)
|
11
|
+
|
12
|
+
@full_pipeline_name = pipeline_name_convention(@pipeline_name)
|
13
|
+
@template = {
|
14
|
+
"Description" => "CodePipeline Project: #{@full_pipeline_name}",
|
15
|
+
"Resources" => {}
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
options = @options.merge(
|
21
|
+
pipeline_name: @pipeline_name,
|
22
|
+
full_pipeline_name: @full_pipeline_name,
|
23
|
+
)
|
24
|
+
|
25
|
+
pipeline_builder = Pipeline.new(options)
|
26
|
+
unless pipeline_builder.exist?
|
27
|
+
puts "ERROR: pipeline does not exist: #{pipeline_builder.pipeline_path}".color(:red)
|
28
|
+
exit 1
|
29
|
+
return
|
30
|
+
end
|
31
|
+
pipeline = pipeline_builder.run
|
32
|
+
@template["Resources"].merge!(pipeline)
|
33
|
+
|
34
|
+
if pipeline["Pipeline"]["Properties"]["RoleArn"] == {"Fn::GetAtt"=>"IamRole.Arn"}
|
35
|
+
role = Role.new(options).run
|
36
|
+
@template["Resources"].merge!(role)
|
37
|
+
end
|
38
|
+
|
39
|
+
if sns_topic?(pipeline)
|
40
|
+
role = Sns.new(options).run
|
41
|
+
@template["Resources"].merge!(role)
|
42
|
+
end
|
43
|
+
|
44
|
+
webhook = Webhook.new(options).run
|
45
|
+
@template["Resources"].merge!(webhook) if webhook
|
46
|
+
|
47
|
+
schedule = Schedule.new(options).run
|
48
|
+
@template["Resources"].merge!(schedule) if schedule
|
49
|
+
|
50
|
+
template_path = "/tmp/codepipeline.yml"
|
51
|
+
FileUtils.mkdir_p(File.dirname(template_path))
|
52
|
+
IO.write(template_path, YAML.dump(@template))
|
53
|
+
puts "Generated CloudFormation template at #{template_path.color(:green)}"
|
54
|
+
return if @options[:noop]
|
55
|
+
puts "Deploying stack #{@stack_name.color(:green)} with CodePipeline project #{@full_pipeline_name.color(:green)}"
|
56
|
+
|
57
|
+
begin
|
58
|
+
perform
|
59
|
+
url_info
|
60
|
+
return unless @options[:wait]
|
61
|
+
status.wait
|
62
|
+
exit 2 unless status.success?
|
63
|
+
rescue Aws::CloudFormation::Errors::ValidationError => e
|
64
|
+
if e.message.include?("No updates") # No updates are to be performed.
|
65
|
+
puts "WARN: #{e.message}".color(:yellow)
|
66
|
+
else
|
67
|
+
puts "ERROR ValidationError: #{e.message}".color(:red)
|
68
|
+
exit 1
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
def sns_topic?(template)
|
75
|
+
stages = template['Pipeline']['Properties']['Stages']
|
76
|
+
stages.detect do |stage|
|
77
|
+
stage['Actions'].detect do |action|
|
78
|
+
action['Configuration']['NotificationArn'] == {'Ref'=>'SnsTopic'}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def url_info
|
84
|
+
stack = cfn.describe_stacks(stack_name: @stack_name).stacks.first
|
85
|
+
region = `aws configure get region`.strip rescue "us-east-1"
|
86
|
+
url = "https://console.aws.amazon.com/cloudformation/home?region=#{region}#/stacks"
|
87
|
+
puts "Stack name #{@stack_name.color(:yellow)} status #{stack["stack_status"].color(:yellow)}"
|
88
|
+
puts "Here's the CloudFormation url to check for more details #{url}"
|
89
|
+
end
|
90
|
+
|
91
|
+
def status
|
92
|
+
@status ||= Cfn::Status.new(@stack_name)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Pipedream
|
2
|
+
class Start
|
3
|
+
extend Memoist
|
4
|
+
include AwsServices
|
5
|
+
|
6
|
+
def initialize(options)
|
7
|
+
@options = options
|
8
|
+
@pipeline_name = options[:pipeline_name] || inferred_pipeline_name
|
9
|
+
@full_pipeline_name = pipeline_name_convention(@pipeline_name)
|
10
|
+
@stack_name = options[:stack_name] || inferred_stack_name(@pipeline_name)
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
check_pipeline_exists!
|
15
|
+
redeploy
|
16
|
+
resp = codepipeline.start_pipeline_execution(name: pipeline_name)
|
17
|
+
codepipeline_info(resp.pipeline_execution_id)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Pipedreamline does not currently support specifying a different branch starting an execution.
|
21
|
+
# Workaround this limitation by updating the pipeline and then starting the execution.
|
22
|
+
def redeploy
|
23
|
+
return unless different_branch?
|
24
|
+
puts "Different branch detected."
|
25
|
+
puts " Current pipeline branch: #{current_pipeline_branch}"
|
26
|
+
puts " Requested branch: #{@options[:branch]}"
|
27
|
+
puts "Updating pipeline with new branch.".color(:green)
|
28
|
+
Deploy.new(@options).run
|
29
|
+
end
|
30
|
+
|
31
|
+
def different_branch?
|
32
|
+
return false unless @options[:branch]
|
33
|
+
current_pipeline_branch != @options[:branch]
|
34
|
+
end
|
35
|
+
|
36
|
+
# Actual branch on current pipeline
|
37
|
+
def current_pipeline_branch
|
38
|
+
resp = codepipeline.get_pipeline(name: pipeline_name)
|
39
|
+
source_stage = resp.pipeline.stages.find { |s| s.name == "Source" }
|
40
|
+
action = source_stage.actions.first
|
41
|
+
action.configuration['Branch']
|
42
|
+
end
|
43
|
+
memoize :current_pipeline_branch
|
44
|
+
|
45
|
+
def check_pipeline_exists!
|
46
|
+
pipeline_name
|
47
|
+
end
|
48
|
+
|
49
|
+
def pipeline_name
|
50
|
+
if pipeline_exists?(@full_pipeline_name)
|
51
|
+
@full_pipeline_name
|
52
|
+
elsif stack_exists?(@stack_name) # allow `cb start STACK_NAME` to work too
|
53
|
+
resp = cfn.describe_stack_resources(stack_name: @stack_name)
|
54
|
+
resource = resp.stack_resources.find do |r|
|
55
|
+
r.logical_resource_id == "CodePipeline"
|
56
|
+
end
|
57
|
+
resource.physical_resource_id # codepipeline project name
|
58
|
+
else
|
59
|
+
puts "ERROR: Unable to find the codepipeline project with either full_pipeline_name: #{@full_pipeline_name} or stack name: #{@stack_name}".color(:red)
|
60
|
+
exit 1
|
61
|
+
end
|
62
|
+
end
|
63
|
+
memoize :pipeline_name
|
64
|
+
|
65
|
+
private
|
66
|
+
def codepipeline_info(execution_id)
|
67
|
+
region = `aws configure get region`.strip rescue "us-east-1"
|
68
|
+
url = "https://#{region}.console.aws.amazon.com/codesuite/codepipeline/pipelines/#{pipeline_name}/view"
|
69
|
+
cli = "aws codepipeline get-pipeline-execution --pipeline-execution-id #{execution_id} --pipeline-name #{pipeline_name}"
|
70
|
+
|
71
|
+
puts "Pipeline started: #{pipeline_name}"
|
72
|
+
puts "Please check the CodePipeline console for the status."
|
73
|
+
puts "CodePipeline Console: #{url}"
|
74
|
+
puts "Pipeline cli: #{cli}"
|
75
|
+
end
|
76
|
+
|
77
|
+
def pipeline_exists?(name)
|
78
|
+
codepipeline.get_pipeline(name: name)
|
79
|
+
true
|
80
|
+
rescue Aws::CodePipeline::Errors::PipelineNotFoundException
|
81
|
+
false
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Pipedream
|
2
|
+
class Update < Stack
|
3
|
+
def perform
|
4
|
+
cfn.update_stack(
|
5
|
+
stack_name: @stack_name,
|
6
|
+
template_body: YAML.dump(@template),
|
7
|
+
capabilities: ["CAPABILITY_IAM"]
|
8
|
+
)
|
9
|
+
puts "Updating stack #{@stack_name}. Check CloudFormation console for status."
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/pipedream/version.rb
CHANGED
@@ -0,0 +1,60 @@
|
|
1
|
+
module Pipedream
|
2
|
+
class Webhook
|
3
|
+
include Pipedream::Dsl::Webhook
|
4
|
+
include Evaluate
|
5
|
+
|
6
|
+
def initialize(options={})
|
7
|
+
@options = options
|
8
|
+
@webhook_path = options[:webhook_path] || get_webhook_path
|
9
|
+
@properties = default_properties
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
return unless File.exist?(@webhook_path)
|
14
|
+
|
15
|
+
old_properties = @properties.clone
|
16
|
+
evaluate(@webhook_path)
|
17
|
+
set_secret_token!
|
18
|
+
return if old_properties == @properties # empty webhook.rb file
|
19
|
+
|
20
|
+
resource = {
|
21
|
+
webhook: {
|
22
|
+
type: "AWS::CodePipeline::Webhook",
|
23
|
+
properties: @properties
|
24
|
+
}
|
25
|
+
}
|
26
|
+
CfnCamelizer.transform(resource)
|
27
|
+
end
|
28
|
+
|
29
|
+
def default_properties
|
30
|
+
{
|
31
|
+
authentication: 'GITHUB_HMAC', # GITHUB_HMAC, IP and UNAUTHENTICATED
|
32
|
+
authentication_configuration: {
|
33
|
+
secret_token: @secret_token,
|
34
|
+
},
|
35
|
+
filters: [{
|
36
|
+
json_path: "$.ref",
|
37
|
+
match_equals: "refs/heads/{Branch}",
|
38
|
+
}],
|
39
|
+
# name: '', # optional
|
40
|
+
register_with_third_party: 'true', # optional
|
41
|
+
target_action: 'Source',
|
42
|
+
target_pipeline: {ref: "Pipeline"},
|
43
|
+
target_pipeline_version: {"Fn::GetAtt": "Pipeline.Version"},
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def set_secret_token!
|
48
|
+
@properties.merge!(
|
49
|
+
authentication_configuration: {
|
50
|
+
secret_token: @secret_token
|
51
|
+
}
|
52
|
+
)
|
53
|
+
end
|
54
|
+
private
|
55
|
+
|
56
|
+
def get_webhook_path
|
57
|
+
lookup_codepipeline_file("webhook.rb")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/pipedream.rb
CHANGED
@@ -1,6 +1,23 @@
|
|
1
|
+
$:.unshift(File.expand_path("../", __FILE__))
|
1
2
|
require "pipedream/version"
|
3
|
+
require "rainbow/ext/string"
|
4
|
+
require "memoist"
|
5
|
+
require "active_support/core_ext/hash"
|
6
|
+
|
7
|
+
require "pipedream/autoloader"
|
8
|
+
Pipedream::Autoloader.setup
|
9
|
+
|
10
|
+
gem_root = File.dirname(__dir__)
|
11
|
+
$:.unshift("#{gem_root}/vendor/aws_data/lib")
|
12
|
+
require "aws_data"
|
13
|
+
$:.unshift("#{gem_root}/vendor/cfn_camelizer/lib")
|
14
|
+
require "cfn_camelizer"
|
15
|
+
$:.unshift("#{gem_root}/vendor/cfn-status/lib")
|
16
|
+
require "cfn/status"
|
2
17
|
|
3
18
|
module Pipedream
|
4
19
|
class Error < StandardError; end
|
5
|
-
|
20
|
+
extend Core
|
6
21
|
end
|
22
|
+
|
23
|
+
Pipedream.set_aws_profile!
|
@@ -0,0 +1,40 @@
|
|
1
|
+
stage "Source" do
|
2
|
+
github(
|
3
|
+
source: "<%= project_github_repo %>",
|
4
|
+
# branch: "master", # branch defaults to "master" or the `pipe deploy --branch` option
|
5
|
+
auth_token: ssm("/codepipeline/github/token") # example ssm name
|
6
|
+
)
|
7
|
+
end
|
8
|
+
|
9
|
+
# IMPORANT: A valid pipeline requires at least 2 stages befre you are able to run
|
10
|
+
#
|
11
|
+
# pipe deploy
|
12
|
+
#
|
13
|
+
# Here are some possible examples below. If you need help creating a CodeBuild project one, check out
|
14
|
+
# https://pipedream.run/docs/examples/codebuild-project/
|
15
|
+
|
16
|
+
# stage "Build" do
|
17
|
+
# codebuild "demo"
|
18
|
+
# end
|
19
|
+
|
20
|
+
# stage "MoreBuilds" do
|
21
|
+
# codebuild "project1"
|
22
|
+
# codebuild "project2", "project3" # runs in parallel
|
23
|
+
# codebuild "project4"
|
24
|
+
# end
|
25
|
+
|
26
|
+
# stage "Approve" do
|
27
|
+
# # Existing SNS Topic
|
28
|
+
# # approve(
|
29
|
+
# # notification_arn: "arn:aws:sns:us-west-2:536766270177:hello-topic",
|
30
|
+
# # custom_data: "Approve deployment",
|
31
|
+
# # )
|
32
|
+
#
|
33
|
+
# # OR
|
34
|
+
# # CodePipeline will create and managed the SNS Topoic
|
35
|
+
# approve("Approve deployment")
|
36
|
+
# end
|
37
|
+
|
38
|
+
# stage "Deploy" do
|
39
|
+
# codebuild "project5"
|
40
|
+
# end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# If user has specified their own existing SNS topic ARN, then this SNS Topic managed by the codepipeline
|
2
|
+
# tool will not get created. Also, only gets created if there's an approval action in the pipeline.
|
3
|
+
#
|
4
|
+
# Example properties:
|
5
|
+
#
|
6
|
+
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sns-topic.html
|
7
|
+
#
|
8
|
+
# display_name "my display_name"
|
9
|
+
# kms_master_key_id "String"
|
10
|
+
# subscription([{
|
11
|
+
# endpoint: '',
|
12
|
+
# protocol: ','
|
13
|
+
# }])
|
14
|
+
# topic_name "string", # Recommend not setting because update requires: Replacement. Allow CloudFormation to set it so 2 pipelines dont have same SNS Topic name that collides
|
data/pipedream.gemspec
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
4
|
require "pipedream/version"
|
4
5
|
|
@@ -7,25 +8,35 @@ Gem::Specification.new do |spec|
|
|
7
8
|
spec.version = Pipedream::VERSION
|
8
9
|
spec.authors = ["Tung Nguyen"]
|
9
10
|
spec.email = ["tongueroo@gmail.com"]
|
10
|
-
|
11
|
-
spec.summary = "Tool"
|
11
|
+
spec.summary = "A beautiful and powerful DSL to create and manage AWS CodePipeline pipelines"
|
12
12
|
spec.homepage = "https://github.com/tongueroo/pipedream"
|
13
13
|
spec.license = "MIT"
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
# Specify which files should be added to the gem when it is released.
|
20
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
21
|
-
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
22
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
15
|
+
vendor_files = Dir.glob("vendor/**/*")
|
16
|
+
gem_files = `git -C "#{File.dirname(__FILE__)}" ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features|docs)/})
|
23
18
|
end
|
19
|
+
spec.files = gem_files + vendor_files
|
24
20
|
spec.bindir = "exe"
|
25
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
26
23
|
spec.require_paths = ["lib"]
|
27
24
|
|
28
|
-
spec.
|
29
|
-
spec.
|
30
|
-
spec.
|
25
|
+
spec.add_dependency "activesupport"
|
26
|
+
spec.add_dependency "aws-sdk-cloudformation"
|
27
|
+
spec.add_dependency "aws-sdk-codepipeline"
|
28
|
+
spec.add_dependency "aws-sdk-s3"
|
29
|
+
spec.add_dependency "aws-sdk-ssm"
|
30
|
+
spec.add_dependency "cfn_camelizer"
|
31
|
+
spec.add_dependency "memoist"
|
32
|
+
spec.add_dependency "rainbow"
|
33
|
+
spec.add_dependency "render_me_pretty"
|
34
|
+
spec.add_dependency "thor"
|
35
|
+
spec.add_dependency "zeitwerk"
|
36
|
+
|
37
|
+
spec.add_development_dependency "bundler"
|
38
|
+
spec.add_development_dependency "byebug"
|
39
|
+
spec.add_development_dependency "cli_markdown"
|
40
|
+
spec.add_development_dependency "rake"
|
41
|
+
spec.add_development_dependency "rspec"
|
31
42
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
aws_data (0.1.0)
|
5
|
+
aws-sdk-core
|
6
|
+
memoist
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
aws-eventstream (1.0.3)
|
12
|
+
aws-partitions (1.176.0)
|
13
|
+
aws-sdk-core (3.56.0)
|
14
|
+
aws-eventstream (~> 1.0, >= 1.0.2)
|
15
|
+
aws-partitions (~> 1.0)
|
16
|
+
aws-sigv4 (~> 1.1)
|
17
|
+
jmespath (~> 1.0)
|
18
|
+
aws-sigv4 (1.1.0)
|
19
|
+
aws-eventstream (~> 1.0, >= 1.0.2)
|
20
|
+
diff-lcs (1.3)
|
21
|
+
jmespath (1.4.0)
|
22
|
+
memoist (0.16.0)
|
23
|
+
rake (10.5.0)
|
24
|
+
rspec (3.8.0)
|
25
|
+
rspec-core (~> 3.8.0)
|
26
|
+
rspec-expectations (~> 3.8.0)
|
27
|
+
rspec-mocks (~> 3.8.0)
|
28
|
+
rspec-core (3.8.1)
|
29
|
+
rspec-support (~> 3.8.0)
|
30
|
+
rspec-expectations (3.8.4)
|
31
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
32
|
+
rspec-support (~> 3.8.0)
|
33
|
+
rspec-mocks (3.8.1)
|
34
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
35
|
+
rspec-support (~> 3.8.0)
|
36
|
+
rspec-support (3.8.2)
|
37
|
+
|
38
|
+
PLATFORMS
|
39
|
+
ruby
|
40
|
+
|
41
|
+
DEPENDENCIES
|
42
|
+
aws_data!
|
43
|
+
bundler (~> 2.0)
|
44
|
+
rake (~> 10.0)
|
45
|
+
rspec (~> 3.0)
|
46
|
+
|
47
|
+
BUNDLED WITH
|
48
|
+
2.0.1
|