├── docs
├── CNAME
├── Gemfile
├── .gitignore
├── _includes
│ ├── reference.md
│ ├── example.html
│ ├── google_analytics.html
│ ├── js.html
│ ├── content.html
│ ├── edit-on-github.html
│ ├── prev_next.md
│ ├── tutorials.md
│ ├── nav.html
│ ├── head.html
│ ├── subnav.html
│ ├── footer.html
│ └── commands.html
├── img
│ ├── logos
│ │ ├── boltops-logo.png
│ │ ├── project-logo.png
│ │ ├── boltops-logo-full.png
│ │ └── pipedream-with-text.png
│ └── docs
│ │ ├── codepipeline-output.png
│ │ └── multiple-codebuild-projects-pipeline.png
├── vendor
│ ├── font-awesome
│ │ ├── fonts
│ │ │ ├── FontAwesome.otf
│ │ │ ├── fontawesome-webfont.eot
│ │ │ ├── fontawesome-webfont.ttf
│ │ │ ├── fontawesome-webfont.woff
│ │ │ └── fontawesome-webfont.woff2
│ │ ├── less
│ │ │ ├── screen-reader.less
│ │ │ ├── fixed-width.less
│ │ │ ├── larger.less
│ │ │ ├── list.less
│ │ │ ├── core.less
│ │ │ ├── stacked.less
│ │ │ ├── font-awesome.less
│ │ │ ├── bordered-pulled.less
│ │ │ ├── rotated-flipped.less
│ │ │ ├── path.less
│ │ │ ├── animated.less
│ │ │ └── mixins.less
│ │ └── scss
│ │ │ ├── _fixed-width.scss
│ │ │ ├── _screen-reader.scss
│ │ │ ├── _larger.scss
│ │ │ ├── _list.scss
│ │ │ ├── _core.scss
│ │ │ ├── font-awesome.scss
│ │ │ ├── _stacked.scss
│ │ │ ├── _bordered-pulled.scss
│ │ │ ├── _rotated-flipped.scss
│ │ │ ├── _path.scss
│ │ │ ├── _animated.scss
│ │ │ └── _mixins.scss
│ ├── simple-line-icons
│ │ └── fonts
│ │ │ ├── Simple-Line-Icons.eot
│ │ │ ├── Simple-Line-Icons.ttf
│ │ │ ├── Simple-Line-Icons.woff
│ │ │ └── Simple-Line-Icons.woff2
│ ├── jquery-easing
│ │ ├── jquery.easing.compatibility.js
│ │ ├── jquery.easing.min.js
│ │ └── jquery.easing.js
│ └── bootstrap
│ │ └── css
│ │ ├── bootstrap-reboot.min.css.map
│ │ └── bootstrap-reboot.min.css
├── bin
│ └── web
├── _layouts
│ └── default.html
├── _reference
│ ├── pipe-version.md
│ ├── pipe-completion_script.md
│ ├── pipe-delete.md
│ ├── pipe-init.md
│ ├── pipe-completion.md
│ ├── pipe-start.md
│ └── pipe-deploy.md
├── _sass
│ ├── _table.scss
│ ├── _download.scss
│ ├── _variables.scss
│ ├── _bootstrap-overrides.scss
│ ├── _cta.scss
│ ├── _footer.scss
│ ├── _features.scss
│ ├── _contact.scss
│ ├── _global.scss
│ ├── _mixins.scss
│ ├── _masthead.scss
│ ├── _navbar.scss
│ ├── _syntax.scss
│ └── _timeline.scss
├── reference.md
├── new-age.scss
├── support.md
├── _docs
│ ├── next-steps.md
│ ├── install.md
│ ├── examples
│ │ ├── codebuild-project.md
│ │ ├── different-branches.md
│ │ └── multiple-codebuild-projects.md
│ ├── structure.md
│ ├── dsl
│ │ ├── schedule.md
│ │ ├── webhook.md
│ │ ├── pipeline
│ │ │ ├── action.md
│ │ │ ├── approve.md
│ │ │ └── codebuild.md
│ │ ├── sns.md
│ │ ├── pipeline.md
│ │ └── role.md
│ ├── settings.md
│ ├── dsl.md
│ ├── start.md
│ ├── conventions.md
│ ├── ecs-deploy.md
│ └── deploy.md
├── js
│ ├── new-age.min.js
│ ├── nav.js
│ └── new-age.js
├── README.md
├── LICENSE
├── docs.md
├── index.html
├── _config.yml
└── quick-start.md
├── .github
└── FUNDING.yml
├── spec
├── fixtures
│ ├── app
│ │ └── .pipedream
│ │ │ ├── schedule.rb
│ │ │ ├── webhook.rb
│ │ │ └── pipeline.rb
│ └── pipelines
│ │ ├── approve.rb
│ │ └── approve_existing_sns.rb
├── lib
│ ├── role_spec.rb
│ ├── webhook_spec.rb
│ ├── pipeline_spec.rb
│ ├── schedule_spec.rb
│ ├── cli_spec.rb
│ └── pipeline
│ │ └── approve_spec.rb
└── spec_helper.rb
├── .rspec
├── lib
├── pipedream
│ ├── version.rb
│ ├── help
│ │ ├── completion_script.md
│ │ ├── completion.md
│ │ ├── start.md
│ │ └── deploy.md
│ ├── completer
│ │ ├── script.rb
│ │ └── script.sh
│ ├── build.rb
│ ├── help.rb
│ ├── dsl
│ │ ├── sns.rb
│ │ ├── schedule.rb
│ │ ├── ssm.rb
│ │ ├── webhook.rb
│ │ ├── pipeline.rb
│ │ ├── pipeline
│ │ │ ├── approve.rb
│ │ │ ├── codebuild.rb
│ │ │ └── github.rb
│ │ └── role.rb
│ ├── create.rb
│ ├── update.rb
│ ├── aws_services.rb
│ ├── autoloader.rb
│ ├── delete.rb
│ ├── deploy.rb
│ ├── sns.rb
│ ├── evaluate.rb
│ ├── pipeline.rb
│ ├── webhook.rb
│ ├── sequence.rb
│ ├── core.rb
│ ├── cli.rb
│ ├── init.rb
│ ├── pipeline
│ │ └── s3_bucket.rb
│ ├── command.rb
│ ├── aws_services
│ │ └── helpers.rb
│ ├── setting.rb
│ ├── schedule.rb
│ ├── start.rb
│ └── stack.rb
├── template
│ └── .pipedream
│ │ ├── schedule.rb
│ │ ├── settings.yml
│ │ ├── sns.rb
│ │ ├── README.md
│ │ └── pipeline.rb.tt
└── pipedream.rb
├── .cody
├── project.rb
└── buildspec.yml
├── Gemfile
├── .gitignore
├── exe
├── pipe
└── pipedream
├── .gitmodules
├── Rakefile
├── Guardfile
├── LICENSE.txt
├── CHANGELOG.md
├── pipedream.gemspec
└── README.md
/docs/CNAME:
--------------------------------------------------------------------------------
1 | pipedream.run
2 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: boltops-tools
2 |
--------------------------------------------------------------------------------
/spec/fixtures/app/.pipedream/schedule.rb:
--------------------------------------------------------------------------------
1 | rate "1 day"
--------------------------------------------------------------------------------
/spec/fixtures/app/.pipedream/webhook.rb:
--------------------------------------------------------------------------------
1 | github_token("fake")
--------------------------------------------------------------------------------
/docs/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "jekyll"
4 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --color
2 | --format documentation
3 | --require spec_helper
4 |
--------------------------------------------------------------------------------
/lib/pipedream/version.rb:
--------------------------------------------------------------------------------
1 | module Pipedream
2 | VERSION = "0.4.8"
3 | end
4 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | _site
2 | .sass-cache
3 | .jekyll-metadata
4 | Gemfile.lock
5 |
--------------------------------------------------------------------------------
/docs/_includes/reference.md:
--------------------------------------------------------------------------------
1 | Pipe Dream provides a DSL to make it easy create a CodePipeline pipeline.
2 |
--------------------------------------------------------------------------------
/docs/img/logos/boltops-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boltops-tools/pipedream/HEAD/docs/img/logos/boltops-logo.png
--------------------------------------------------------------------------------
/docs/img/logos/project-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boltops-tools/pipedream/HEAD/docs/img/logos/project-logo.png
--------------------------------------------------------------------------------
/lib/template/.pipedream/schedule.rb:
--------------------------------------------------------------------------------
1 | # rate "1 day"
2 | # or
3 | # cron("0 10 * * ? *") # Run at 10:00 am (UTC) every day
--------------------------------------------------------------------------------
/docs/img/docs/codepipeline-output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boltops-tools/pipedream/HEAD/docs/img/docs/codepipeline-output.png
--------------------------------------------------------------------------------
/docs/img/logos/boltops-logo-full.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boltops-tools/pipedream/HEAD/docs/img/logos/boltops-logo-full.png
--------------------------------------------------------------------------------
/docs/img/logos/pipedream-with-text.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boltops-tools/pipedream/HEAD/docs/img/logos/pipedream-with-text.png
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boltops-tools/pipedream/HEAD/docs/vendor/font-awesome/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/lib/pipedream/help/completion_script.md:
--------------------------------------------------------------------------------
1 | To use, add the following to your `~/.bashrc` or `~/.profile`
2 |
3 | eval $(pipe completion_script)
4 |
--------------------------------------------------------------------------------
/docs/img/docs/multiple-codebuild-projects-pipeline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boltops-tools/pipedream/HEAD/docs/img/docs/multiple-codebuild-projects-pipeline.png
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boltops-tools/pipedream/HEAD/docs/vendor/font-awesome/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boltops-tools/pipedream/HEAD/docs/vendor/font-awesome/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/.cody/project.rb:
--------------------------------------------------------------------------------
1 | github_url("https://github.com/tongueroo/pipedream")
2 | linux_image("aws/codebuild/ruby:2.5.3-1.7.0")
3 | triggers(webhook: true)
4 | local_cache(false)
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boltops-tools/pipedream/HEAD/docs/vendor/font-awesome/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boltops-tools/pipedream/HEAD/docs/vendor/font-awesome/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/docs/vendor/simple-line-icons/fonts/Simple-Line-Icons.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boltops-tools/pipedream/HEAD/docs/vendor/simple-line-icons/fonts/Simple-Line-Icons.eot
--------------------------------------------------------------------------------
/docs/vendor/simple-line-icons/fonts/Simple-Line-Icons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boltops-tools/pipedream/HEAD/docs/vendor/simple-line-icons/fonts/Simple-Line-Icons.ttf
--------------------------------------------------------------------------------
/docs/vendor/simple-line-icons/fonts/Simple-Line-Icons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boltops-tools/pipedream/HEAD/docs/vendor/simple-line-icons/fonts/Simple-Line-Icons.woff
--------------------------------------------------------------------------------
/docs/vendor/simple-line-icons/fonts/Simple-Line-Icons.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boltops-tools/pipedream/HEAD/docs/vendor/simple-line-icons/fonts/Simple-Line-Icons.woff2
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | # Specify your gem dependencies in codepipe.gemspec
4 | gemspec
5 |
6 | gem "codeclimate-test-reporter", group: :test, require: nil
7 |
--------------------------------------------------------------------------------
/docs/bin/web:
--------------------------------------------------------------------------------
1 | #!/bin/bash -ex
2 |
3 | # Usage:
4 | # bin/web
5 | # bin/web -P 8888
6 |
7 | bundle exec jekyll clean
8 | exec bundle exec jekyll serve --host 0.0.0.0 --trace "$@"
9 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/less/screen-reader.less:
--------------------------------------------------------------------------------
1 | // Screen Readers
2 | // -------------------------
3 |
4 | .sr-only { .sr-only(); }
5 | .sr-only-focusable { .sr-only-focusable(); }
6 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/less/fixed-width.less:
--------------------------------------------------------------------------------
1 | // Fixed Width Icons
2 | // -------------------------
3 | .@{fa-css-prefix}-fw {
4 | width: (18em / 14);
5 | text-align: center;
6 | }
7 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/scss/_fixed-width.scss:
--------------------------------------------------------------------------------
1 | // Fixed Width Icons
2 | // -------------------------
3 | .#{$fa-css-prefix}-fw {
4 | width: (18em / 14);
5 | text-align: center;
6 | }
7 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/scss/_screen-reader.scss:
--------------------------------------------------------------------------------
1 | // Screen Readers
2 | // -------------------------
3 |
4 | .sr-only { @include sr-only(); }
5 | .sr-only-focusable { @include sr-only-focusable(); }
6 |
--------------------------------------------------------------------------------
/lib/pipedream/completer/script.rb:
--------------------------------------------------------------------------------
1 | class Pipedream::Completer::Script
2 | def self.generate
3 | bash_script = File.expand_path("script.sh", File.dirname(__FILE__))
4 | puts "source #{bash_script}"
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/lib/template/.pipedream/settings.yml:
--------------------------------------------------------------------------------
1 | base:
2 | # stack_naming:
3 | # append_env: true # default false
4 |
5 | development:
6 | # aws_profile: dev_profile
7 |
8 | production:
9 | # aws_profile: prod_profile
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.gem
2 | *.rbc
3 | .bundle
4 | .config
5 | .yardoc
6 | _yardoc
7 | coverage
8 | doc/
9 | InstalledFiles
10 | lib/bundler/man
11 | pkg
12 | rdoc
13 | spec/reports
14 | test/tmp
15 | test/version_tmp
16 | tmp
17 | Gemfile.lock
18 |
--------------------------------------------------------------------------------
/lib/pipedream/build.rb:
--------------------------------------------------------------------------------
1 | module Pipedream
2 | class Build
3 | def initialize(options)
4 | @options = options
5 | end
6 |
7 | def run
8 | options = @options
9 | Pipeline.new(options).run
10 | end
11 | end
12 | end
--------------------------------------------------------------------------------
/.cody/buildspec.yml:
--------------------------------------------------------------------------------
1 | version: 0.2
2 |
3 | phases:
4 | build:
5 | commands:
6 | - echo Build started on `date`
7 | - sed -i '/BUNDLED WITH/Q' Gemfile.lock # hack to fix bundler issue: allow different versions of bundler to work
8 | - bundle
9 | - bundle exec rspec
10 |
--------------------------------------------------------------------------------
/docs/_layouts/default.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {% include head.html %}
4 |
5 | {% include nav.html %}
6 |
7 | {% include content.html %}
8 |
9 | {% include footer.html %}
10 | {% include js.html %}
11 |
12 |
13 |
--------------------------------------------------------------------------------
/lib/pipedream/help.rb:
--------------------------------------------------------------------------------
1 | module Pipedream::Help
2 | class << self
3 | def text(namespaced_command)
4 | path = namespaced_command.to_s.gsub(':','/')
5 | path = File.expand_path("../help/#{path}.md", __FILE__)
6 | IO.read(path) if File.exist?(path)
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/exe/pipe:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # Trap ^C
4 | Signal.trap("INT") {
5 | puts "\nCtrl-C detected. Exiting..."
6 | sleep 0.1
7 | exit
8 | }
9 |
10 | $:.unshift(File.expand_path("../../lib", __FILE__))
11 | require "pipedream"
12 | require "pipedream/cli"
13 |
14 | Pipedream::CLI.start(ARGV)
15 |
--------------------------------------------------------------------------------
/exe/pipedream:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # Trap ^C
4 | Signal.trap("INT") {
5 | puts "\nCtrl-C detected. Exiting..."
6 | sleep 0.1
7 | exit
8 | }
9 |
10 | $:.unshift(File.expand_path("../../lib", __FILE__))
11 | require "pipedream"
12 | require "pipedream/cli"
13 |
14 | Pipedream::CLI.start(ARGV)
15 |
--------------------------------------------------------------------------------
/docs/_reference/pipe-version.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: pipe version
3 | reference: true
4 | ---
5 |
6 | ## Usage
7 |
8 | pipe version
9 |
10 | ## Description
11 |
12 | prints version
13 |
14 |
15 | ## Options
16 |
17 | ```
18 | [--verbose], [--no-verbose]
19 | [--noop], [--no-noop]
20 | ```
21 |
22 |
--------------------------------------------------------------------------------
/lib/pipedream/completer/script.sh:
--------------------------------------------------------------------------------
1 | _codepipe() {
2 | COMPREPLY=()
3 | local word="${COMP_WORDS[COMP_CWORD]}"
4 | local words=("${COMP_WORDS[@]}")
5 | unset words[0]
6 | local completion=$(codepipe completion ${words[@]})
7 | COMPREPLY=( $(compgen -W "$completion" -- "$word") )
8 | }
9 |
10 | complete -F _codepipe codepipe
11 |
--------------------------------------------------------------------------------
/lib/pipedream/dsl/sns.rb:
--------------------------------------------------------------------------------
1 | module Pipedream::Dsl
2 | module Sns
3 | PROPERTIES = %w[
4 | display_name
5 | kms_master_key_id
6 | subscription
7 | topic_name
8 | ]
9 | PROPERTIES.each do |prop|
10 | define_method(prop) do |v|
11 | @properties[prop.to_sym] = v
12 | end
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "vendor/cfn-status"]
2 | path = vendor/cfn-status
3 | url = https://github.com/tongueroo/cfn-status
4 | [submodule "vendor/cfn_camelizer"]
5 | path = vendor/cfn_camelizer
6 | url = https://github.com/tongueroo/cfn_camelizer
7 | [submodule "vendor/aws_data"]
8 | path = vendor/aws_data
9 | url = https://github.com/tongueroo/aws_data
10 |
--------------------------------------------------------------------------------
/lib/pipedream/create.rb:
--------------------------------------------------------------------------------
1 | module Pipedream
2 | class Create < Stack
3 | def perform
4 | cfn.create_stack(
5 | stack_name: @stack_name,
6 | template_body: YAML.dump(@template),
7 | capabilities: ["CAPABILITY_IAM"]
8 | )
9 | puts "Creating stack #{@stack_name}. Check CloudFormation console for status."
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/lib/pipedream/update.rb:
--------------------------------------------------------------------------------
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
13 |
--------------------------------------------------------------------------------
/spec/fixtures/app/.pipedream/pipeline.rb:
--------------------------------------------------------------------------------
1 | stage "Source" do
2 | github(
3 | source: "tongueroo/demo-cb",
4 | branch: "master",
5 | auth_token: "fake",
6 | )
7 | end
8 | stage "DeployStacks" do
9 | codebuild "demo1" # action declaration
10 | codebuild "demo2", "demo3" # will run in parallel. run_order=2
11 | codebuild "demo4" # action declaration
12 | end
13 |
--------------------------------------------------------------------------------
/spec/lib/role_spec.rb:
--------------------------------------------------------------------------------
1 | describe Pipedream::Role do
2 | let(:role) do
3 | Pipedream::Role.new(role_path: "spec/fixtures/app/.pipedream/role.rb")
4 | end
5 | context "general" do
6 | it "builds up the template in memory" do
7 | template = role.run
8 | expect(template.keys).to eq ["IamRole"]
9 | expect(template["IamRole"]).to be_a(Hash)
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require "bundler/gem_tasks"
2 | require "rspec/core/rake_task"
3 |
4 | task default: :spec
5 |
6 | RSpec::Core::RakeTask.new
7 |
8 | require_relative "lib/pipedream"
9 | require "cli_markdown"
10 | desc "Generates cli reference docs as markdown"
11 | task :docs do
12 | mkdir_p "docs/_includes"
13 | CliMarkdown::Creator.create_all(cli_class: Pipedream::CLI, cli_name: "pipe")
14 | end
15 |
--------------------------------------------------------------------------------
/spec/lib/webhook_spec.rb:
--------------------------------------------------------------------------------
1 | describe Pipedream::Webhook do
2 | let(:webhook) do
3 | Pipedream::Webhook.new(webhook_path: "spec/fixtures/app/.pipedream/webhook.rb")
4 | end
5 | context "general" do
6 | it "builds up the template in memory" do
7 | template = webhook.run
8 | expect(template.keys).to eq ["Webhook"]
9 | expect(template["Webhook"]).to be_a(Hash)
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/spec/lib/pipeline_spec.rb:
--------------------------------------------------------------------------------
1 | describe Pipedream::Pipeline do
2 | let(:pipeline) do
3 | Pipedream::Pipeline.new(pipeline_path: "spec/fixtures/app/.pipedream/pipeline.rb")
4 | end
5 | context "general" do
6 | it "builds up the template in memory" do
7 | template = pipeline.run
8 | expect(template.keys).to eq ["Pipeline"]
9 | expect(template["Pipeline"]).to be_a(Hash)
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/spec/lib/schedule_spec.rb:
--------------------------------------------------------------------------------
1 | describe Pipedream::Schedule do
2 | let(:schedule) do
3 | Pipedream::Schedule.new(schedule_path: "spec/fixtures/app/.pipedream/schedule.rb")
4 | end
5 | context "general" do
6 | it "builds up the template in memory" do
7 | template = schedule.run
8 | expect(template.keys).to eq ["EventsRule", "EventsRuleRole"]
9 | expect(template["EventsRule"]).to be_a(Hash)
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/less/larger.less:
--------------------------------------------------------------------------------
1 | // Icon Sizes
2 | // -------------------------
3 |
4 | /* makes the font 33% larger relative to the icon container */
5 | .@{fa-css-prefix}-lg {
6 | font-size: (4em / 3);
7 | line-height: (3em / 4);
8 | vertical-align: -15%;
9 | }
10 | .@{fa-css-prefix}-2x { font-size: 2em; }
11 | .@{fa-css-prefix}-3x { font-size: 3em; }
12 | .@{fa-css-prefix}-4x { font-size: 4em; }
13 | .@{fa-css-prefix}-5x { font-size: 5em; }
14 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/scss/_larger.scss:
--------------------------------------------------------------------------------
1 | // Icon Sizes
2 | // -------------------------
3 |
4 | /* makes the font 33% larger relative to the icon container */
5 | .#{$fa-css-prefix}-lg {
6 | font-size: (4em / 3);
7 | line-height: (3em / 4);
8 | vertical-align: -15%;
9 | }
10 | .#{$fa-css-prefix}-2x { font-size: 2em; }
11 | .#{$fa-css-prefix}-3x { font-size: 3em; }
12 | .#{$fa-css-prefix}-4x { font-size: 4em; }
13 | .#{$fa-css-prefix}-5x { font-size: 5em; }
14 |
--------------------------------------------------------------------------------
/docs/_includes/example.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Demo Pipeline
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/spec/lib/cli_spec.rb:
--------------------------------------------------------------------------------
1 | describe Pipedream::CLI do
2 | before(:all) do
3 | @args = "--noop"
4 | @old_root = Dir.pwd
5 | Dir.chdir("spec/fixtures/app")
6 | @pipe_bin = "../../../exe/pipe"
7 | end
8 | after(:all) do
9 | Dir.chdir(@old_root)
10 | end
11 |
12 | describe "pipe" do
13 | it "deploy" do
14 | out = execute("#{@pipe_bin} deploy #{@args}")
15 | expect(out).to include("Generated CloudFormation template")
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/less/list.less:
--------------------------------------------------------------------------------
1 | // List Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-ul {
5 | padding-left: 0;
6 | margin-left: @fa-li-width;
7 | list-style-type: none;
8 | > li { position: relative; }
9 | }
10 | .@{fa-css-prefix}-li {
11 | position: absolute;
12 | left: -@fa-li-width;
13 | width: @fa-li-width;
14 | top: (2em / 14);
15 | text-align: center;
16 | &.@{fa-css-prefix}-lg {
17 | left: (-@fa-li-width + (4em / 14));
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/scss/_list.scss:
--------------------------------------------------------------------------------
1 | // List Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-ul {
5 | padding-left: 0;
6 | margin-left: $fa-li-width;
7 | list-style-type: none;
8 | > li { position: relative; }
9 | }
10 | .#{$fa-css-prefix}-li {
11 | position: absolute;
12 | left: -$fa-li-width;
13 | width: $fa-li-width;
14 | top: (2em / 14);
15 | text-align: center;
16 | &.#{$fa-css-prefix}-lg {
17 | left: -$fa-li-width + (4em / 14);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/spec/fixtures/pipelines/approve.rb:
--------------------------------------------------------------------------------
1 | stage "Source" do
2 | github(
3 | source: "tongueroo/demo-test",
4 | branch: "master",
5 | auth_token: "fake",
6 | )
7 | end
8 |
9 | # codebuild_prefix "myprefix-"
10 |
11 | stage "Build" do
12 | codebuild "demo-build"
13 | end
14 |
15 | stage "Approve" do
16 | # not specifying the SNS topic arn so codepipeline will create one
17 | approve("Approve deployment")
18 | end
19 |
20 | stage "Deploy" do
21 | codebuild "demo-deploy"
22 | end
23 |
--------------------------------------------------------------------------------
/docs/_reference/pipe-completion_script.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: pipe completion_script
3 | reference: true
4 | ---
5 |
6 | ## Usage
7 |
8 | pipe completion_script
9 |
10 | ## Description
11 |
12 | Generates a script that can be eval to setup auto-completion.
13 |
14 | To use, add the following to your `~/.bashrc` or `~/.profile`
15 |
16 | eval $(pipe completion_script)
17 |
18 |
19 | ## Options
20 |
21 | ```
22 | [--verbose], [--no-verbose]
23 | [--noop], [--no-noop]
24 | ```
25 |
26 |
--------------------------------------------------------------------------------
/docs/_sass/_table.scss:
--------------------------------------------------------------------------------
1 | table {
2 | width: 100%;
3 | background-color: #ecf0f1;
4 | margin-bottom: 20px;
5 | }
6 |
7 | thead {
8 | }
9 |
10 | tr {
11 |
12 | }
13 |
14 | thead th {
15 | background-color: #000000;
16 | text-transform: uppercase;
17 | color: #cdcdce;
18 | }
19 |
20 | tbody {
21 | }
22 |
23 | tr {
24 | }
25 |
26 | tbody td {
27 | box-shadow: inset 0 1px 0 rgba(255,255,255,0.1);
28 | color: black;
29 | }
30 |
31 | th,
32 | td {
33 | padding: 10px;
34 | }
35 |
--------------------------------------------------------------------------------
/lib/pipedream/aws_services.rb:
--------------------------------------------------------------------------------
1 | require "aws-sdk-codepipeline"
2 | require "aws-sdk-cloudformation"
3 |
4 | require "aws_mfa_secure/ext/aws" # add MFA support
5 |
6 | module Pipedream
7 | module AwsServices
8 | include Helpers
9 |
10 | def codepipeline
11 | @codepipeline ||= Aws::CodePipeline::Client.new
12 | end
13 |
14 | def cfn
15 | @cfn ||= Aws::CloudFormation::Client.new
16 | end
17 |
18 | def s3
19 | @s3 ||= Aws::S3::Client.new
20 | end
21 | end
22 | end
--------------------------------------------------------------------------------
/lib/pipedream/help/completion.md:
--------------------------------------------------------------------------------
1 | Example:
2 |
3 | pipe completion
4 |
5 | Prints words for TAB auto-completion.
6 |
7 | Examples:
8 |
9 | pipe completion
10 | pipe completion hello
11 | pipe completion hello name
12 |
13 | To enable, TAB auto-completion add the following to your profile:
14 |
15 | eval $(pipe completion_script)
16 |
17 | Auto-completion example usage:
18 |
19 | pipe [TAB]
20 | pipe hello [TAB]
21 | pipe hello name [TAB]
22 | pipe hello name --[TAB]
23 |
--------------------------------------------------------------------------------
/Guardfile:
--------------------------------------------------------------------------------
1 | guard "bundler", cmd: "bundle" do
2 | watch("Gemfile")
3 | watch(/^.+\.gemspec/)
4 | end
5 |
6 | guard :rspec, cmd: "bundle exec rspec" do
7 | require "guard/rspec/dsl"
8 | dsl = Guard::RSpec::Dsl.new(self)
9 |
10 | # RSpec files
11 | rspec = dsl.rspec
12 | watch(rspec.spec_helper) { rspec.spec_dir }
13 | watch(rspec.spec_support) { rspec.spec_dir }
14 | watch(rspec.spec_files)
15 |
16 | # Ruby files
17 | ruby = dsl.ruby
18 | dsl.watch_spec_files_for(ruby.lib_files)
19 | end
20 |
--------------------------------------------------------------------------------
/docs/_includes/google_analytics.html:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/docs/reference.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: CLI Reference
3 | ---
4 | {% include reference.md %}
5 |
6 | * [pipe completion]({% link _reference/pipe-completion.md %})
7 | * [pipe completion_script]({% link _reference/pipe-completion_script.md %})
8 | * [pipe delete]({% link _reference/pipe-delete.md %})
9 | * [pipe deploy]({% link _reference/pipe-deploy.md %})
10 | * [pipe init]({% link _reference/pipe-init.md %})
11 | * [pipe start]({% link _reference/pipe-start.md %})
12 | * [pipe version]({% link _reference/pipe-version.md %})
13 |
--------------------------------------------------------------------------------
/docs/new-age.scss:
--------------------------------------------------------------------------------
1 | ---
2 | # this ensures Jekyll reads the file to be transformed into CSS later
3 | # only Main files contain this front matter, not partials.
4 | ---
5 |
6 | @import "variables";
7 | @import "mixins";
8 | @import "global";
9 | @import "navbar";
10 | @import "masthead";
11 | @import "download";
12 | @import "features";
13 | @import "cta";
14 | @import "contact";
15 | @import "footer";
16 | @import "bootstrap-overrides";
17 | @import "table";
18 | @import "main";
19 | @import "timeline";
20 | @import "syntax";
21 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/less/core.less:
--------------------------------------------------------------------------------
1 | // Base Class Definition
2 | // -------------------------
3 |
4 | .@{fa-css-prefix} {
5 | display: inline-block;
6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/scss/_core.scss:
--------------------------------------------------------------------------------
1 | // Base Class Definition
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix} {
5 | display: inline-block;
6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/spec/fixtures/pipelines/approve_existing_sns.rb:
--------------------------------------------------------------------------------
1 | stage "Source" do
2 | github(
3 | source: "tongueroo/demo-test",
4 | branch: "master",
5 | auth_token: "fake",
6 | )
7 | end
8 |
9 | # codebuild_prefix "myprefix-"
10 |
11 | stage "Build" do
12 | codebuild "demo-build"
13 | end
14 |
15 | stage "Approve" do
16 | approve(
17 | notification_arn: "arn:aws:sns:us-west-2:536766270177:hello-topic",
18 | custom_data: "Approve deployment",
19 | )
20 | end
21 |
22 | stage "Deploy" do
23 | codebuild "demo-deploy"
24 | end
25 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/scss/font-awesome.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
4 | */
5 |
6 | @import "variables";
7 | @import "mixins";
8 | @import "path";
9 | @import "core";
10 | @import "larger";
11 | @import "fixed-width";
12 | @import "list";
13 | @import "bordered-pulled";
14 | @import "animated";
15 | @import "rotated-flipped";
16 | @import "stacked";
17 | @import "icons";
18 | @import "screen-reader";
19 |
--------------------------------------------------------------------------------
/lib/pipedream/autoloader.rb:
--------------------------------------------------------------------------------
1 | require "zeitwerk"
2 |
3 | module Pipedream
4 | class Autoloader
5 | class Inflector < Zeitwerk::Inflector
6 | def camelize(basename, _abspath)
7 | map = { cli: "CLI", version: "VERSION" }
8 | map[basename.to_sym] || super
9 | end
10 | end
11 |
12 | class << self
13 | def setup
14 | loader = Zeitwerk::Loader.new
15 | loader.inflector = Inflector.new
16 | loader.push_dir(File.dirname(__dir__)) # lib
17 | loader.setup
18 | end
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/less/stacked.less:
--------------------------------------------------------------------------------
1 | // Stacked Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-stack {
5 | position: relative;
6 | display: inline-block;
7 | width: 2em;
8 | height: 2em;
9 | line-height: 2em;
10 | vertical-align: middle;
11 | }
12 | .@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x {
13 | position: absolute;
14 | left: 0;
15 | width: 100%;
16 | text-align: center;
17 | }
18 | .@{fa-css-prefix}-stack-1x { line-height: inherit; }
19 | .@{fa-css-prefix}-stack-2x { font-size: 2em; }
20 | .@{fa-css-prefix}-inverse { color: @fa-inverse; }
21 |
--------------------------------------------------------------------------------
/docs/_reference/pipe-delete.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: pipe delete
3 | reference: true
4 | ---
5 |
6 | ## Usage
7 |
8 | pipe delete
9 |
10 | ## Description
11 |
12 | Delete codebuild project.
13 |
14 |
15 | ## Options
16 |
17 | ```
18 | [--sure=SURE] # Bypass are you sure prompt
19 | [--stack-name=STACK_NAME] # Override the generated stack name. If you use this you must always specify it
20 | [--wait], [--no-wait] # Wait for operation to complete
21 | # Default: true
22 | [--verbose], [--no-verbose]
23 | [--noop], [--no-noop]
24 | ```
25 |
26 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/scss/_stacked.scss:
--------------------------------------------------------------------------------
1 | // Stacked Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-stack {
5 | position: relative;
6 | display: inline-block;
7 | width: 2em;
8 | height: 2em;
9 | line-height: 2em;
10 | vertical-align: middle;
11 | }
12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x {
13 | position: absolute;
14 | left: 0;
15 | width: 100%;
16 | text-align: center;
17 | }
18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; }
19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; }
20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; }
21 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/less/font-awesome.less:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
4 | */
5 |
6 | @import "variables.less";
7 | @import "mixins.less";
8 | @import "path.less";
9 | @import "core.less";
10 | @import "larger.less";
11 | @import "fixed-width.less";
12 | @import "list.less";
13 | @import "bordered-pulled.less";
14 | @import "animated.less";
15 | @import "rotated-flipped.less";
16 | @import "stacked.less";
17 | @import "icons.less";
18 | @import "screen-reader.less";
19 |
--------------------------------------------------------------------------------
/docs/_includes/js.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | {% if site.google_analytics and jekyll.environment == "production" %}
14 | {% include google_analytics.html %}
15 | {% endif %}
16 |
--------------------------------------------------------------------------------
/docs/support.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Support
3 | nav_order: 22
4 | ---
5 |
6 | ## Getting Help
7 |
8 | If you're looking for support for Pipe Dream, here are some options:
9 |
10 | * Read the [Documentation](https://pipedream.run)
11 |
12 | ## Report a bug
13 |
14 | If you think you've found a bug within the pipedream repository, [open an issue](https://github.com/tongueroo/pipedream/issues/new/choose).
15 |
16 | Happy Hackin' 😁
17 |
18 | ## Commercial Support
19 |
20 | If you would like professional help, [BoltOps](https://www.boltops.com/) provides consulting. Feel free to reach out: [contact page](https://www.boltops.com/contact)
21 |
22 | {% include prev_next.md %}
23 |
--------------------------------------------------------------------------------
/docs/_reference/pipe-init.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: pipe init
3 | reference: true
4 | ---
5 |
6 | ## Usage
7 |
8 | pipe init
9 |
10 | ## Description
11 |
12 | Set up initial .codepipline files.
13 |
14 |
15 | ## Options
16 |
17 | ```
18 | [--name=NAME] # CodePipeline project name.
19 | [--mode=MODE] # Modes: light or full
20 | [--force] # Bypass overwrite are you sure prompt for existing files.
21 | [--template=TEMPLATE] # Custom template to use.
22 | [--template-mode=TEMPLATE_MODE] # Template mode: replace or additive.
23 | [--verbose], [--no-verbose]
24 | [--noop], [--no-noop]
25 | ```
26 |
27 |
--------------------------------------------------------------------------------
/lib/pipedream/dsl/schedule.rb:
--------------------------------------------------------------------------------
1 | module Pipedream::Dsl
2 | module Schedule
3 | PROPERTIES = %w[
4 | description
5 | event_pattern
6 | name
7 | role_arn
8 | schedule_expression
9 | state
10 | targets
11 | ]
12 | PROPERTIES.each do |prop|
13 | define_method(prop) do |v|
14 | @properties[prop.to_sym] = v
15 | end
16 | end
17 |
18 | def rate(period)
19 | @schedule_expression = "rate(#{period})"
20 | end
21 |
22 | def cron(expression)
23 | @schedule_expression = "cron(#{expression})"
24 | end
25 |
26 | def rule_event(props={})
27 | @rule_event_props = props
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/lib/pipedream.rb:
--------------------------------------------------------------------------------
1 | $:.unshift(File.expand_path("../", __FILE__))
2 | require "pipedream/version"
3 | require "rainbow/ext/string"
4 | require "memoist"
5 | require "active_support"
6 | require "active_support/core_ext/hash"
7 |
8 | require "pipedream/autoloader"
9 | Pipedream::Autoloader.setup
10 |
11 | gem_root = File.dirname(__dir__)
12 | $:.unshift("#{gem_root}/vendor/aws_data/lib")
13 | require "aws_data"
14 | $:.unshift("#{gem_root}/vendor/cfn_camelizer/lib")
15 | require "cfn_camelizer"
16 | $:.unshift("#{gem_root}/vendor/cfn-status/lib")
17 | require "cfn/status"
18 |
19 | module Pipedream
20 | class Error < StandardError; end
21 | extend Core
22 | end
23 |
24 | Pipedream.set_aws_profile!
25 |
--------------------------------------------------------------------------------
/lib/template/.pipedream/sns.rb:
--------------------------------------------------------------------------------
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
15 |
--------------------------------------------------------------------------------
/lib/template/.pipedream/README.md:
--------------------------------------------------------------------------------
1 | # Pipedream Files
2 |
3 | The files in folder are used by pipedream to build AWS CodePipeline pipelines. For more info, check out the [pipedream docs](https://pipedream.run). Here's a quick start.
4 |
5 | ## Install Tool
6 |
7 | gem install pipedream
8 |
9 | This installs both the `pipe` and `pipedream` commands. They do the same thing, the `pipe` command is just shorter to type.
10 |
11 | ## Update Project
12 |
13 | To update the CodePipeline pipelines:
14 |
15 | pipedream deploy demo
16 |
17 | ## Start a Execution
18 |
19 | To start a CodePipeline execution:
20 |
21 | pipedream start demo
22 |
23 | To specify a branch:
24 |
25 | pipedream start demo -b feature
26 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/less/bordered-pulled.less:
--------------------------------------------------------------------------------
1 | // Bordered & Pulled
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-border {
5 | padding: .2em .25em .15em;
6 | border: solid .08em @fa-border-color;
7 | border-radius: .1em;
8 | }
9 |
10 | .@{fa-css-prefix}-pull-left { float: left; }
11 | .@{fa-css-prefix}-pull-right { float: right; }
12 |
13 | .@{fa-css-prefix} {
14 | &.@{fa-css-prefix}-pull-left { margin-right: .3em; }
15 | &.@{fa-css-prefix}-pull-right { margin-left: .3em; }
16 | }
17 |
18 | /* Deprecated as of 4.4.0 */
19 | .pull-right { float: right; }
20 | .pull-left { float: left; }
21 |
22 | .@{fa-css-prefix} {
23 | &.pull-left { margin-right: .3em; }
24 | &.pull-right { margin-left: .3em; }
25 | }
26 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/less/rotated-flipped.less:
--------------------------------------------------------------------------------
1 | // Rotated & Flipped Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); }
5 | .@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); }
6 | .@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); }
7 |
8 | .@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); }
9 | .@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); }
10 |
11 | // Hook for IE8-9
12 | // -------------------------
13 |
14 | :root .@{fa-css-prefix}-rotate-90,
15 | :root .@{fa-css-prefix}-rotate-180,
16 | :root .@{fa-css-prefix}-rotate-270,
17 | :root .@{fa-css-prefix}-flip-horizontal,
18 | :root .@{fa-css-prefix}-flip-vertical {
19 | filter: none;
20 | }
21 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/scss/_bordered-pulled.scss:
--------------------------------------------------------------------------------
1 | // Bordered & Pulled
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-border {
5 | padding: .2em .25em .15em;
6 | border: solid .08em $fa-border-color;
7 | border-radius: .1em;
8 | }
9 |
10 | .#{$fa-css-prefix}-pull-left { float: left; }
11 | .#{$fa-css-prefix}-pull-right { float: right; }
12 |
13 | .#{$fa-css-prefix} {
14 | &.#{$fa-css-prefix}-pull-left { margin-right: .3em; }
15 | &.#{$fa-css-prefix}-pull-right { margin-left: .3em; }
16 | }
17 |
18 | /* Deprecated as of 4.4.0 */
19 | .pull-right { float: right; }
20 | .pull-left { float: left; }
21 |
22 | .#{$fa-css-prefix} {
23 | &.pull-left { margin-right: .3em; }
24 | &.pull-right { margin-left: .3em; }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/pipedream/dsl/ssm.rb:
--------------------------------------------------------------------------------
1 | require "aws-sdk-ssm"
2 |
3 | module Pipedream::Dsl
4 | module Ssm
5 | # This method grabs the ssm parameter store value at "compile" time vs
6 | # CloudFormation run time. In case we need it as part of the DSL compile phase.
7 | def ssm(name)
8 | resp = ssm_client.get_parameter(name: name)
9 | if resp.parameter.type == "SecureString"
10 | resp = ssm_client.get_parameter(name: name, with_decryption: true)
11 | end
12 |
13 | resp.parameter.value
14 | rescue Aws::SSM::Errors::ParameterNotFound
15 | puts "WARN: #{name} found on AWS SSM.".color(:yellow)
16 | end
17 |
18 | def ssm_client
19 | @ssm_client ||= Aws::SSM::Client.new
20 | end
21 | end
22 | end
--------------------------------------------------------------------------------
/lib/pipedream/dsl/webhook.rb:
--------------------------------------------------------------------------------
1 | module Pipedream::Dsl
2 | module Webhook
3 | include Ssm
4 |
5 | # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codepipeline-webhook.html
6 | PROPERTIES = %w[
7 | authentication
8 | authentication_configuration
9 | filters
10 | name
11 | register_with_third_party
12 | target_action
13 | target_pipeline
14 | target_pipeline_version
15 | ]
16 | PROPERTIES.each do |prop|
17 | define_method(prop) do |v|
18 | @properties[prop.to_sym] = v
19 | end
20 | end
21 |
22 | def secret_token(v)
23 | @secret_token = v
24 | end
25 | alias_method :github_token, :secret_token
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/scss/_rotated-flipped.scss:
--------------------------------------------------------------------------------
1 | // Rotated & Flipped Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); }
5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); }
6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); }
7 |
8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); }
9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); }
10 |
11 | // Hook for IE8-9
12 | // -------------------------
13 |
14 | :root .#{$fa-css-prefix}-rotate-90,
15 | :root .#{$fa-css-prefix}-rotate-180,
16 | :root .#{$fa-css-prefix}-rotate-270,
17 | :root .#{$fa-css-prefix}-flip-horizontal,
18 | :root .#{$fa-css-prefix}-flip-vertical {
19 | filter: none;
20 | }
21 |
--------------------------------------------------------------------------------
/docs/_sass/_download.scss:
--------------------------------------------------------------------------------
1 | // Styling for the download section
2 | section.download {
3 | color: white;
4 | position: relative;
5 | padding: 80px 0;
6 | h2 {
7 | font-size: 50px;
8 | margin-top: 0;
9 | }
10 | .badges {
11 | .badge-link {
12 | display: block;
13 | margin-bottom: 25px;
14 | &:last-child {
15 | margin-bottom: 0;
16 | }
17 | img {
18 | height: 60px;
19 | }
20 | @media(min-width: 768px) {
21 | display: inline-block;
22 | margin-bottom: 0;
23 | }
24 | }
25 | }
26 | @media(min-width: 768px) {
27 | h2 {
28 | font-size: 70px;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/docs/_sass/_variables.scss:
--------------------------------------------------------------------------------
1 | // Variables
2 |
3 | // Gray and Brand Colors for use across theme
4 |
5 | $theme-primary: #777;
6 | $theme-secondary: #7b4397;
7 | $theme-tertiary: #dc2430;
8 |
9 | $gray-base: #000;
10 | $gray-darker: lighten($gray-base, 13.5%); // #222
11 | $gray-dark: lighten($gray-base, 20%); // #333
12 | $gray: lighten($gray-base, 33.5%); // #555
13 | $gray-light: lighten($gray-base, 46.7%); // #777
14 | $gray-lighter: lighten($gray-base, 93.5%); // #eee
15 |
16 | $brand-twitter: #1da1f2;
17 | $brand-facebook: #3b5998;
18 | $brand-google-plus: #dd4b39;
19 |
20 | $site-color-primary: #3972c7;
21 | $site-color-primary-rgb: #18FF9C;
22 | $site-color-secondary: #2c3e50;
23 | $site-color-secondary-dark: #233140;
24 | $site-color-links: #a3c8ff;
25 |
--------------------------------------------------------------------------------
/lib/pipedream/delete.rb:
--------------------------------------------------------------------------------
1 | module Pipedream
2 | class Delete
3 | include AwsServices
4 |
5 | def initialize(options)
6 | @options = options
7 | @pipeline_name = options[:pipeline_name] || inferred_pipeline_name
8 | @stack_name = options[:stack_name] || inferred_stack_name(@pipeline_name)
9 | end
10 |
11 | def run
12 | message = "Deleted #{@stack_name} stack."
13 | if @options[:noop]
14 | puts "NOOP #{message}"
15 | else
16 | are_you_sure?(@stack_name, :delete)
17 |
18 | if stack_exists?(@stack_name)
19 | cfn.delete_stack(stack_name: @stack_name)
20 | puts message
21 | else
22 | puts "#{@stack_name.inspect} stack does not exist".color(:red)
23 | end
24 | end
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/docs/_includes/content.html:
--------------------------------------------------------------------------------
1 | {% if page.subnav == false %}
2 |
3 | {{ content }}
4 |
5 | {% else %}
6 |
7 |
8 |
9 |
10 | {% if page.reference %}
11 |
14 | {% endif %}
15 |
16 |
{{ page.title }}
17 | {{ content }}
18 | {% include edit-on-github.html %}
19 |
20 | {% include subnav.html %}
21 |
22 |
23 |
24 |
25 | {% endif %}
26 |
--------------------------------------------------------------------------------
/docs/_includes/edit-on-github.html:
--------------------------------------------------------------------------------
1 |
2 |
Edit this page
3 |
See a typo or an error? You can improve this page. This website is available on GitHub , and contributions are encouraged and welcomed. We love pull requests from you!
4 |
9 |
10 |
--------------------------------------------------------------------------------
/docs/_reference/pipe-completion.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: pipe completion
3 | reference: true
4 | ---
5 |
6 | ## Usage
7 |
8 | pipe completion *PARAMS
9 |
10 | ## Description
11 |
12 | Prints words for auto-completion.
13 |
14 | Example:
15 |
16 | pipe completion
17 |
18 | Prints words for TAB auto-completion.
19 |
20 | Examples:
21 |
22 | pipe completion
23 | pipe completion hello
24 | pipe completion hello name
25 |
26 | To enable, TAB auto-completion add the following to your profile:
27 |
28 | eval $(pipe completion_script)
29 |
30 | Auto-completion example usage:
31 |
32 | pipe [TAB]
33 | pipe hello [TAB]
34 | pipe hello name [TAB]
35 | pipe hello name --[TAB]
36 |
37 |
38 | ## Options
39 |
40 | ```
41 | [--verbose], [--no-verbose]
42 | [--noop], [--no-noop]
43 | ```
44 |
45 |
--------------------------------------------------------------------------------
/docs/_docs/next-steps.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Next Steps
3 | nav_order: 23
4 | ---
5 |
6 | Hopefully, you have a good feel for how Pipe Dream works now. From here, there are a few resources that can help you continue along:
7 |
8 | * Check out the [pipedream](https://github.com/tongueroo/pipedream) repo on GitHub
9 | * ⭐️ the pipedream project on GitHub
10 | * Write a blog post about pipedream
11 | * Post on your favorite discussion about pipedream
12 | * Contribute a pull request
13 |
14 | Everyone can contribute to making pipedream better, including the documentation. These docs are the pipedream repo located the [docs folder](https://github.com/tongueroo/pipedream/tree/master/docs). Please fork the project and open a pull request! We love your pull requests. Contributions are encouraged and welcomed!
15 |
16 | {% include prev_next.md %}
17 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/less/path.less:
--------------------------------------------------------------------------------
1 | /* FONT PATH
2 | * -------------------------- */
3 |
4 | @font-face {
5 | font-family: 'FontAwesome';
6 | src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}');
7 | src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'),
8 | url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'),
9 | url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'),
10 | url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'),
11 | url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg');
12 | // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
13 | font-weight: normal;
14 | font-style: normal;
15 | }
16 |
--------------------------------------------------------------------------------
/docs/_docs/install.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Installation
3 | nav_order: 3
4 | ---
5 |
6 | ## RubyGems
7 |
8 | Install pipedream via RubyGems.
9 |
10 | gem install pipedream
11 |
12 | The [Quick Start]({% link quick-start.md %}) provides a guide on how to use the codebuild tool. The [DSL Docs]({% link _docs/dsl.md %}) provide more detail on the syntax.
13 |
14 | ## AWS CLI
15 |
16 | AWS access is required. Though you can set up acess with `AWS_*` environment variables, the AWS CLI is strongly recommended. It'll allow the use of AWS Profiles. You can install the [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/installing.html) via pip.
17 |
18 | pip install awscli --upgrade --user
19 |
20 | Then [configure it](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html).
21 |
22 | aws configure
23 |
24 | {% include prev_next.md %}
25 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/scss/_path.scss:
--------------------------------------------------------------------------------
1 | /* FONT PATH
2 | * -------------------------- */
3 |
4 | @font-face {
5 | font-family: 'FontAwesome';
6 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}');
7 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'),
8 | url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'),
9 | url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'),
10 | url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'),
11 | url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg');
12 | // src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
13 | font-weight: normal;
14 | font-style: normal;
15 | }
16 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/less/animated.less:
--------------------------------------------------------------------------------
1 | // Animated Icons
2 | // --------------------------
3 |
4 | .@{fa-css-prefix}-spin {
5 | -webkit-animation: fa-spin 2s infinite linear;
6 | animation: fa-spin 2s infinite linear;
7 | }
8 |
9 | .@{fa-css-prefix}-pulse {
10 | -webkit-animation: fa-spin 1s infinite steps(8);
11 | animation: fa-spin 1s infinite steps(8);
12 | }
13 |
14 | @-webkit-keyframes fa-spin {
15 | 0% {
16 | -webkit-transform: rotate(0deg);
17 | transform: rotate(0deg);
18 | }
19 | 100% {
20 | -webkit-transform: rotate(359deg);
21 | transform: rotate(359deg);
22 | }
23 | }
24 |
25 | @keyframes fa-spin {
26 | 0% {
27 | -webkit-transform: rotate(0deg);
28 | transform: rotate(0deg);
29 | }
30 | 100% {
31 | -webkit-transform: rotate(359deg);
32 | transform: rotate(359deg);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/docs/js/new-age.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Start Bootstrap - New Age v4.0.0-alpha (http://startbootstrap.com/template-overviews/new-age)
3 | * Copyright 2013-2017 Start Bootstrap
4 | * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap-new-age/blob/master/LICENSE)
5 | */
6 | !function(a){"use strict";a('a[href*="#"]:not([href="#"])').click(function(){if(location.pathname.replace(/^\//,"")==this.pathname.replace(/^\//,"")&&location.hostname==this.hostname){var n=a(this.hash);if(n=n.length?n:a("[name="+this.hash.slice(1)+"]"),n.length)return a("html, body").animate({scrollTop:n.offset().top-48},1e3,"easeInOutExpo"),!1}}),a("body").scrollspy({target:"#mainNav",offset:54}),a(".navbar-collapse>ul>li>a").click(function(){a(".navbar-collapse").collapse("hide")}),a(window).scroll(function(){a("#mainNav").offset().top>100?a("#mainNav").addClass("navbar-shrink"):a("#mainNav").removeClass("navbar-shrink")})}(jQuery);
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/scss/_animated.scss:
--------------------------------------------------------------------------------
1 | // Spinning Icons
2 | // --------------------------
3 |
4 | .#{$fa-css-prefix}-spin {
5 | -webkit-animation: fa-spin 2s infinite linear;
6 | animation: fa-spin 2s infinite linear;
7 | }
8 |
9 | .#{$fa-css-prefix}-pulse {
10 | -webkit-animation: fa-spin 1s infinite steps(8);
11 | animation: fa-spin 1s infinite steps(8);
12 | }
13 |
14 | @-webkit-keyframes fa-spin {
15 | 0% {
16 | -webkit-transform: rotate(0deg);
17 | transform: rotate(0deg);
18 | }
19 | 100% {
20 | -webkit-transform: rotate(359deg);
21 | transform: rotate(359deg);
22 | }
23 | }
24 |
25 | @keyframes fa-spin {
26 | 0% {
27 | -webkit-transform: rotate(0deg);
28 | transform: rotate(0deg);
29 | }
30 | 100% {
31 | -webkit-transform: rotate(359deg);
32 | transform: rotate(359deg);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/docs/_docs/examples/codebuild-project.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Create CodeBuild Project
3 | nav_text: Create CodeBuild
4 | categories: examples
5 | nav_order: 18
6 | ---
7 |
8 | It is common to use CodeBuild as a Stage Action in the pipeline. Here's are instructions to quickly create a CodeBuild project.
9 |
10 | We'll use the [cody.run](https://cody.run) tool to help with this. Here are the commands.
11 |
12 | gem install cody # installs cody command
13 | cody init # generates starter .cody files including the buildspec.yml
14 | # edit and commit the .cody files
15 | git add .cody
16 | git commit -m 'add .cody files'
17 | git push
18 | cody deploy demo # creates a codebuild project
19 |
20 | There's also an example where we quickly create 4 test codebuild projects here: [Multiple CodeBuild Projects](https://pipedream.run/docs/examples/multiple-codebuild-projects/).
21 |
22 | {% include prev_next.md %}
23 |
--------------------------------------------------------------------------------
/docs/_includes/prev_next.md:
--------------------------------------------------------------------------------
1 | {% assign all_pages = site.pages | concat: site.docs | where_exp: "item", "item.nav_order" %}
2 | {% assign links = all_pages | sort: "nav_order" %}
3 | {% for link in links %}
4 | {% if link.url == page.url %}
5 | {% unless forloop.first %}
6 | {% assign prev = tmpprev %}
7 | {% endunless %}
8 | {% if forloop.last %}
9 | {% assign last = "/reference" %}
10 | {% else %}
11 | {% assign next = links[forloop.index] %}
12 | {% endif %}
13 | {% endif %}
14 | {% assign tmpprev = link %}
15 | {% endfor %}
16 |
17 | {% if prev %}Back {% endif %}{% if last %}Next Step {% endif %}
18 | {% if next %}Next Step {% endif %}
19 | Pro tip: Use the <- and -> arrow keys to move back and forward.
20 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Pipe Dream Documentation
2 |
3 | This project powers the Pipe Dream documementation website: [https://pipedream.run](https://pipedream.run). It is a static website generated by [Jekyll](https://jekyllrb.com/).
4 |
5 | ## Contributing
6 |
7 | For minor changes like typos, you can click **Suggest an edit to this page**, located at the bottom of each article. This will take you to the source file on GitHub, where you can submit a pull request for your change through the UI.
8 |
9 | ## Local Setup
10 |
11 | For larger fixes, you can run the site locally with the following:
12 |
13 | git clone https://github.com/tongueroo/pipedream.git
14 | cd pipedream/docs
15 | bundle
16 | bin/web
17 |
18 | You'll be able to view the site on [http://localhost:4000](http://localhost:4000).
19 |
20 | ## Rordering Site Nav
21 |
22 | To reorder the `nav_order` for links on the sidenav run:
23 |
24 | cd docs
25 | jekyll-sort reorder
26 |
--------------------------------------------------------------------------------
/lib/pipedream/help/start.md:
--------------------------------------------------------------------------------
1 | You can start a pipeline with the `pipe start` command. Here's an example:
2 |
3 | $ pipe start
4 | Pipeline started: demo
5 | Please check the CodePipeline console for the status.
6 | CodePipeline Console: https://us-west-2.console.aws.amazon.com/codesuite/codepipeline/pipelines/demo/view
7 | Pipeline cli: aws codepipeline get-pipeline-execution --pipeline-execution-id 02579d64-9271-4edc-aa45-bc9629d732bb --pipeline-name demo
8 | $
9 |
10 | ## Specifying Code Branch
11 |
12 | If you would like start a build using a specific code branch you can use the `--branch` or `-b` option. Example:
13 |
14 | pipe start -b feature-branch
15 |
16 | ## AWS CLI Equivalent
17 |
18 | The `pipe start` command is a simple wrapper to the AWS API with the ruby sdk. You can also start pipelines with the `aws codepipeline` cli. Here's the equivalent CLI command:
19 |
20 | aws codepipeline start-pipeline-execution --name demo
21 |
--------------------------------------------------------------------------------
/docs/_docs/structure.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Structure
3 | nav_order: 4
4 | ---
5 |
6 | The `pipe init` command generates the initial directory structure that looks like this:
7 |
8 | .pipedream
9 | ├── pipeline.rb
10 | ├── role.rb
11 | ├── schedule.rb
12 | ├── settings.yml
13 | └── webhook.rb
14 |
15 | The table below states the purpose of each file:
16 |
17 | File / Directory | Description
18 | ------------- | -------------
19 | pipeline.rb | The pipeline defintion. More info: [Pipeline DSL]({% link _docs/dsl/pipeline.md %})
20 | role.rb | The IAM role defintion. More info: [Role DSL]({% link _docs/dsl/role.md %})
21 | schedule.rb | The schedule defintion. More info: [Schedule DSL]({% link _docs/dsl/schedule.md %})
22 | settings.yml | Settings for pipedream. More info: [Settings]({% link _docs/settings.md %})
23 | webhook.rb | The webhook defintion. More info: [Webhook DSL]({% link _docs/dsl/webhook.md %})
24 |
25 | {% include prev_next.md %}
26 |
--------------------------------------------------------------------------------
/docs/_docs/dsl/schedule.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Schedule DSL
3 | nav_text: Schedule
4 | categories: dsl
5 | nav_order: 15
6 | ---
7 |
8 | Pipe Dream supports creating a CloudWatch scheduled event rule that will trigger the pipeline periodically. You define the schedule in `.pipedream/schedule.rb`. Here's an example of what that looks like:
9 |
10 | .pipedream/schedule.rb:
11 |
12 | ```ruby
13 | rate "1 day"
14 | # or
15 | # cron("0 10 * * ? *") # Run at 10:00 am (UTC) every day
16 | ```
17 |
18 | ## Full DSL
19 |
20 | The convenience methods merely wrap properties of the [AWS::Events::Rule](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-events-rule.html#cfn-events-rule-description). If you wanted to set the CloudFormation properties more directly, here's an example of using the Full DSL.
21 |
22 | .pipedream/schedule.rb:
23 |
24 | ```ruby
25 | description "my description"
26 | schedule_expression "rate(1 day)"
27 | ```
28 |
29 | {% include prev_next.md %}
30 |
--------------------------------------------------------------------------------
/docs/_sass/_bootstrap-overrides.scss:
--------------------------------------------------------------------------------
1 | // Bootstrap overrides for this template
2 | .bg-primary {
3 | // background: $theme-primary;
4 | // background: -webkit-linear-gradient($theme-primary, darken($theme-primary, 5%));
5 | // background: linear-gradient(#c70000, darken($theme-primary, 5%));
6 | background-color: #730c0c !important;
7 | }
8 |
9 | .text-primary {
10 | color: $theme-primary;
11 | }
12 |
13 | .no-gutter > [class*='col-'] {
14 | padding-right: 0;
15 | padding-left: 0;
16 | }
17 |
18 | .btn-outline {
19 | color: white;
20 | border: 1px solid;
21 | border-color: white;
22 | &:hover,
23 | &:focus,
24 | &:active,
25 | &.active {
26 | color: white;
27 | border-color: $theme-primary;
28 | background-color: $theme-primary;
29 | }
30 | }
31 |
32 | .btn {
33 | border-radius: 300px;
34 | @include alt-font;
35 | }
36 |
37 | .btn-xl {
38 | font-size: 11px;
39 | padding: 15px 45px;
40 | }
41 |
--------------------------------------------------------------------------------
/docs/_docs/dsl/webhook.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Webhook DSL
3 | nav_text: Webhook
4 | categories: dsl
5 | nav_order: 17
6 | ---
7 |
8 | The simplest way to declare a webhook is to use the `github_token` method. This single line is enough to configure and set up the webhook.
9 |
10 | .pipedream/webhook.rb:
11 |
12 | ```ruby
13 | github_token(ssm("/codepipeline/github/token"))
14 | ```
15 |
16 | ## Full DSL
17 |
18 | The convenience methods merely wrap properties of the [AWS::CodePipeline::Webhook](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codepipeline-webhook.html). If you wanted to set the CloudFormation properties more directly, here's an example of using the Full DSL.
19 |
20 | .pipedream/webhook.rb:
21 |
22 | ```ruby
23 | authentication "GITHUB_HMAC"
24 | authentication_configuration(secret_token: ssm("/codepipeline/github/token"))
25 | filters([{
26 | json_path: "$.ref",
27 | match_equals: "refs/heads/{Branch}",
28 | }])
29 | ```
30 |
31 | {% include prev_next.md %}
32 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | ENV["TEST"] = "1"
2 |
3 | # Ensures aws api never called. Fixture home folder does not contain ~/.aws/credentails
4 | ENV['HOME'] = File.join(Dir.pwd,'spec/fixtures/home')
5 |
6 | ENV['PIPE_ROOT'] = "spec/fixtures/app"
7 |
8 |
9 | # CodeClimate test coverage: https://docs.codeclimate.com/docs/configuring-test-coverage
10 | # require 'simplecov'
11 | # SimpleCov.start
12 |
13 | require "pp"
14 | require "byebug"
15 | root = File.expand_path("../", File.dirname(__FILE__))
16 | require "#{root}/lib/pipedream"
17 |
18 | module Helper
19 | def execute(cmd)
20 | puts "Running: #{cmd}" if show_command?
21 | out = `#{cmd}`
22 | puts out if show_command?
23 | out
24 | end
25 |
26 | # Added SHOW_COMMAND because DEBUG is also used by other libraries like
27 | # bundler and it shows its internal debugging logging also.
28 | def show_command?
29 | ENV['DEBUG'] || ENV['SHOW_COMMAND']
30 | end
31 | end
32 |
33 | RSpec.configure do |c|
34 | c.include Helper
35 | end
36 |
--------------------------------------------------------------------------------
/docs/_docs/dsl/pipeline/action.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Action General Method
3 | nav_text: Action
4 | categories: dsl-pipeline
5 | nav_order: 11
6 | ---
7 |
8 | The `action` method is a generalized way to add Actions to pipeline Stages. Generally, it is recommended to use the helper methods like [codebuild]({% link _docs/dsl/pipeline/codebuild.md %}) and [approve]({% link _docs/dsl/pipeline/approve.md %}) when possible to keep code concise. Here's an example of a pipeline using the generalized `action` method.
9 |
10 | ```ruby
11 | stage "Build" do
12 | action(
13 | name: "action1",
14 | action_type_id: {
15 | category: "Build",
16 | owner: "AWS",
17 | provider: "CodeBuild",
18 | version: "1",
19 | },
20 | run_order: 1,
21 | configuration: { project_name: 'demo1' },
22 | # output_artifacts: [name: "BuildArtifact#{name}"], # optional
23 | input_artifacts: [name: "SourceArtifact"], # SourceArtifact is the default primary source
24 | )
25 | end
26 | ```
27 |
28 | {% include prev_next.md %}
29 |
--------------------------------------------------------------------------------
/docs/_sass/_cta.scss:
--------------------------------------------------------------------------------
1 | // Styling for the call to action section
2 | section.cta {
3 | position: relative;
4 | padding: 50px 0;
5 | text-align: center;
6 | margin: 0 auto;
7 | // background-image: url('../img/bg-cta.jpg');
8 | background-position: center;
9 | @include background-cover;
10 | .cta-content {
11 | position: relative;
12 | z-index: 1;
13 | h2 {
14 | text-align: center;
15 | margin: 0 auto 25px auto;
16 | font-size: 50px;
17 | max-width: 450px;
18 | color: white;
19 | }
20 | @media (min-width: 768px) {
21 | h2 {
22 | text-align: center;
23 | margin: 0 auto;
24 | font-size: 80px;
25 | }
26 | }
27 | }
28 | .overlay {
29 | position: absolute;
30 | top: 0;
31 | left: 0;
32 | width: 100%;
33 | height: 100%;
34 | // background-color: fade-out(black, .5);
35 | background-color: #730c0c;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/spec/lib/pipeline/approve_spec.rb:
--------------------------------------------------------------------------------
1 | describe Pipedream::Pipeline do
2 | let(:stack) do
3 | stack = Pipedream::Stack.new(
4 | pipeline_path: "spec/fixtures/pipelines/#{pipeline_example}.rb",
5 | stack_name: "fake", # to avoid .pipedream check in settings
6 | )
7 | allow(stack).to receive(:perform)
8 | allow(stack).to receive(:url_info)
9 | stack
10 | end
11 |
12 | context "pipeline with approve step without existing sns topic arn" do
13 | let(:pipeline_example) { "approve" }
14 | it "stack" do
15 | stack.run
16 | template = stack.instance_variable_get(:@template)
17 | # creates and manages the SnsTopic
18 | expect(template["Resources"]["SnsTopic"]).to be_a(Hash)
19 | end
20 | end
21 |
22 | context "pipeline with approve step with existing sns topic arn" do
23 | let(:pipeline_example) { "approve_existing_sns" }
24 |
25 | it "stack" do
26 | stack.run
27 | template = stack.instance_variable_get(:@template)
28 | # does not creates the SnsTopic
29 | expect(template["Resources"]["SnsTopic"]).to be nil
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/lib/pipedream/dsl/pipeline.rb:
--------------------------------------------------------------------------------
1 | module Pipedream::Dsl
2 | module Pipeline
3 | include Approve
4 | include Codebuild
5 | include Github
6 | include Ssm
7 |
8 | PROPERTIES = %w[
9 | artifact_store
10 | artifact_stores
11 | disable_inboundstage_transitions
12 | input_artifacts
13 | name
14 | restart_execution_on_update
15 | role_arn
16 | stages
17 | ]
18 | PROPERTIES.each do |prop|
19 | define_method(prop) do |v|
20 | @properties[prop.to_sym] = v
21 | end
22 | end
23 |
24 | def pipeline_name
25 | @options[:pipeline_name]
26 | end
27 |
28 | def stage(name, &block)
29 | # Reset values for each stage declaraion
30 | @run_order = 1
31 |
32 | @current_stage = {name: name, actions: []}
33 | @stages << @current_stage
34 | block.call
35 | end
36 |
37 | def in_parallel
38 | @in_parallel = true
39 | yield
40 | @in_parallel = false
41 | end
42 |
43 | def action(*props)
44 | @current_stage[:actions] += props
45 | @run_order += 1 unless @in_parallel
46 | end
47 | end
48 | end
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2019 Tung Nguyen
2 |
3 | MIT License
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining
6 | a copy of this software and associated documentation files (the
7 | "Software"), to deal in the Software without restriction, including
8 | without limitation the rights to use, copy, modify, merge, publish,
9 | distribute, sublicense, and/or sell copies of the Software, and to
10 | permit persons to whom the Software is furnished to do so, subject to
11 | the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be
14 | included in all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/docs/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2019 Tung Nguyen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/docs/_docs/settings.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Settings
3 | nav_order: 7
4 | ---
5 |
6 | The `.pipedream/settings.yml` file can be used to adjust some of the behavior of pipedream. Here's an example of a settings.yml file:
7 |
8 | ```yaml
9 | base:
10 | # stack_naming:
11 | # append_env: true # default false
12 |
13 | development:
14 | # aws_profile: dev_profile
15 |
16 | production:
17 | # aws_profile: prod_profile
18 | ```
19 |
20 | The base settings are common and used for all the environments. The other environments are used according to the value of `PIPE_ENV`.
21 |
22 | ## Example
23 |
24 | pipe deploy # will use the development settings since development is the default
25 | PIPE_ENV=production pipe deploy # will use the production settings
26 |
27 | ## Options
28 |
29 | Name | Description
30 | --- | ---
31 | stack_naming.append_env | Determines if `PIPE_ENV` value is append to the pipeline name.
32 | aws_profile | This provides a way to bind `PIPE_ENV` to `AWS_PROFILE` tightly. This prevents you from forgetting to switch your `PIPE_ENV` when switching your `AWS_PROFILE`, thereby accidentally launching a stack in the wrong environment.
33 |
34 | {% include prev_next.md %}
35 |
--------------------------------------------------------------------------------
/lib/pipedream/dsl/pipeline/approve.rb:
--------------------------------------------------------------------------------
1 | module Pipedream::Dsl::Pipeline
2 | module Approve
3 | def approve(props)
4 | default = {
5 | name: "approve",
6 | action_type_id: {
7 | category: "Approval",
8 | owner: "AWS",
9 | provider: "Manual",
10 | version: "1",
11 | },
12 | run_order: @run_order,
13 | configuration: { # required: will be set
14 | notification_arn: {ref: "SnsTopic"}, # defaults to generated SNS topic
15 | },
16 | }
17 |
18 | # Normalize special options. Simple approach of setting the default
19 | case props
20 | when String, Symbol
21 | default[:configuration][:custom_data] = props
22 | props = {}
23 | when Hash
24 | default[:configuration][:notification_arn] = props.delete(:notification_arn) if props.key?(:notification_arn)
25 | default[:configuration][:custom_data] = props.delete(:custom_data) if props.key?(:custom_data)
26 | else
27 | raise "Invalid props type: #{props.class}"
28 | end
29 |
30 | options = default.merge(props)
31 | action(options)
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/docs/docs.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Overview
3 | nav_order: 2
4 | ---
5 |
6 | ## What is Pipe Dream?
7 |
8 | Pipe Dream is a tool that provides a powerful DSL to simplify creating and managing [AWS CodePipeline](https://aws.amazon.com/codepipeline/) resources. You can create a Pipeline, Scheduled Event, IAM Role, and Webhook.
9 |
10 | The [pipeline DSL]({% link _docs/dsl.md %}) is essentially a wrapper to CloudFormation for resources like the [CodePipeline Project resource](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codepipeline-pipeline.html). This means you can **fully control** and customize of the CodePipeline resources.
11 |
12 | ## Usage Scenarios
13 |
14 | Here are some ways to use Pipe Dream:
15 |
16 | * continuous integration and delivery
17 | * visualizing the deploy flow
18 | * building artifacts: Docker images, AMIs, jars, s3 objects, etc
19 |
20 | ## AWS CodePipeline vs CodeBuild
21 |
22 | AWS CodePipeline is higher-level software than CodeBuild. CodeBuild is a managed build service, and you can use it to automate tasks. CodePipeline helps you sequence the steps and puts it all together; providing you with a high-level visualization.
23 |
24 | {% include prev_next.md %}
25 |
--------------------------------------------------------------------------------
/docs/_includes/tutorials.md:
--------------------------------------------------------------------------------
1 | ## Introducing Jets
2 |
3 |
4 |
5 | ## Jets Introduction Series
6 |
7 | Introductions are focused on AWS fundamental essentials.
8 |
9 | {% assign posts = site.data.intro_series %}
10 | {% for post in posts %}
11 | * [{{ post.title }}]({{ post.url }}){% endfor %}
12 |
13 | ## Jets Tutorial Series
14 |
15 | Tutorials are focused on Jets fundamentals.
16 |
17 | {% assign posts = site.data.tutorial_series %}
18 | {% for post in posts %}
19 | * [{{ post.title }}]({{ post.url }}){% endfor %}
20 |
21 | ## Jets Articles
22 |
23 | Articles, tutorials, and demos on Jets.
24 |
25 | {% assign posts = site.data.articles %}
26 | {% for post in posts %}
27 | * [{{ post.title }}]({{ post.url }}){% endfor %}
28 |
29 | ## Tutorials
30 |
31 | * [HTML ActiveRecord Tutorial]({% link _docs/crud-html-activerecord.md %})
32 | * [JSON ActiveRecord Tutorial]({% link _docs/crud-json-activerecord.md %})
33 |
34 | ## Videos
35 |
36 | {% assign posts = site.data.video_playlists %}
37 | {% for post in posts %}
38 | * [{{ post.title }}]({{ post.url }}){% endfor %}
39 |
--------------------------------------------------------------------------------
/lib/template/.pipedream/pipeline.rb.tt:
--------------------------------------------------------------------------------
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 before 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
41 |
--------------------------------------------------------------------------------
/docs/_includes/nav.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Menu
5 |
6 |
17 |
18 |
--------------------------------------------------------------------------------
/docs/_sass/_footer.scss:
--------------------------------------------------------------------------------
1 | // Styling for the footer
2 | footer {
3 | padding: 25px 0;
4 | text-align: center;
5 | background-color: $gray-darker;
6 | color: white;
7 | p {
8 | margin: 0;
9 | }
10 | ul {
11 | margin-bottom: 0;
12 | li {
13 | a {
14 | font-size: 1.2em;
15 | color: white;
16 | &:hover,
17 | &:focus,
18 | &:active,
19 | &.active {
20 | text-decoration: none;
21 | }
22 | }
23 | }
24 | }
25 |
26 | ul.list-inline {
27 | li {
28 | display: inline;
29 | margin: 0 5px;
30 | a.btn-social {
31 | display: inline-block;
32 | width: 50px;
33 | height: 50px;
34 | border: 2px solid #fff;
35 | border-radius: 100%;
36 | text-align: center;
37 | font-size: 20px;
38 | line-height: 45px;
39 | }
40 | }
41 | }
42 | }
43 |
44 | .footer-col {
45 | padding-top: 20px;
46 | @media(min-width: 992px) {
47 | padding-top: 10px;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/lib/pipedream/deploy.rb:
--------------------------------------------------------------------------------
1 | module Pipedream
2 | class Deploy < Stack
3 | def run
4 | handle_rollback_completed!
5 | if stack_exists?(@stack_name)
6 | Update.new(@options).run
7 | else
8 | Create.new(@options).run
9 | end
10 | end
11 |
12 | def handle_rollback_completed!
13 | @stack = find_stack(@stack_name)
14 | if @stack && rollback_complete?(@stack)
15 | puts "Existing stack in ROLLBACK_COMPLETE state. Deleting stack before continuing."
16 | cfn.delete_stack(stack_name: @stack_name)
17 | status.wait
18 | status.reset
19 | @stack = nil # at this point stack has been deleted
20 | end
21 | end
22 |
23 | def rollback_complete?(stack)
24 | stack.stack_status == 'ROLLBACK_COMPLETE'
25 | end
26 |
27 | def find_stack(stack_name)
28 | return if ENV['TEST']
29 | resp = cfn.describe_stacks(stack_name: stack_name)
30 | resp.stacks.first
31 | rescue Aws::CloudFormation::Errors::ValidationError => e
32 | # example: Stack with id demo-web does not exist
33 | if e.message =~ /Stack with/ && e.message =~ /does not exist/
34 | nil
35 | else
36 | raise
37 | end
38 | end
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/docs/js/nav.js:
--------------------------------------------------------------------------------
1 | function onlyShow(className) {
2 | $("ul.build-tutorial").hide();
3 | $("ul.build-new").hide();
4 | $("ul.build-existing").hide();
5 | if (className) {
6 | $("ul." + className).show();
7 | }
8 | }
9 |
10 | $( document ).ready(function() {
11 | var currentPath = $(location).attr('pathname');
12 |
13 | // add active class to the subnav link based on the current page
14 | var activeLink = $(".content-nav a").filter(function(i, link) {
15 | return(link.pathname == currentPath);
16 | });
17 | activeLink.addClass("active");
18 |
19 | // allows use to use arrow keys to move back and forward through the docs
20 | var keymap = {};
21 |
22 | // LEFT
23 | keymap[ 37 ] = "#prev";
24 | // RIGHT
25 | keymap[ 39 ] = "#next";
26 |
27 | $( document ).on( "keyup", function(event) {
28 | var href,
29 | selector = keymap[ event.which ];
30 | // if the key pressed was in our map, check for the href
31 | if ( selector ) {
32 | href = $( selector ).attr( "href" );
33 | if ( href ) {
34 | // navigate where the link points
35 | window.location = href;
36 | }
37 | }
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/lib/pipedream/sns.rb:
--------------------------------------------------------------------------------
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_pipedream_file("sns.rb")
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/docs/_docs/dsl.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Pipe Dream DSL
3 | nav_order: 9
4 | ---
5 |
6 | Pipe Dream provides a simple yet powerful DSL to create CodePipeline related resources. Here's an example:
7 |
8 | ```ruby
9 | stage "Source" do
10 | github(
11 | source: "tongueroo/demo-test",
12 | auth_token: ssm("/github/user/token")
13 | )
14 | end
15 |
16 | stage "Build" do
17 | codebuild "demo1", "demo2"
18 | codebuild "demo3"
19 | end
20 |
21 | stage "Approve" do
22 | approve("Approve this deploy")
23 | end
24 |
25 | stage "Deploy" do
26 | codebuild "deploy"
27 | end
28 | ```
29 |
30 | Here are some examples of resources it can create:
31 |
32 | * [pipeline]({% link _docs/dsl/pipeline.md %}): The CodePipeline pipeline. This is required.
33 | * [iam role]({% link _docs/dsl/role.md %}): The IAM role associated with the CodePipeline pipeline.
34 | * [webhook]({% link _docs/dsl/webhook.md %}): The webhook associated with the CodePipeline pipeline.
35 | * [schedule]({% link _docs/dsl/schedule.md %}): An CloudWatch Event rule: triggers the pipeline to start on a scheduled basis.
36 | * [sns topic]({% link _docs/dsl/sns.md %}): The SNS Topic associated with the approval step. This is optional and provides a way to customize the SNS topic if needed.
37 |
38 | {% include prev_next.md %}
39 |
--------------------------------------------------------------------------------
/docs/_sass/_features.scss:
--------------------------------------------------------------------------------
1 | // Styling for the features section
2 | section.features {
3 | h3 {
4 | // background-color: green;
5 | // font-size: 1.6em;
6 | }
7 | .section-heading {
8 | margin-bottom: 20px;
9 | h2 {
10 | margin-top: 0;
11 | }
12 | p {
13 | margin-bottom: 0;
14 | }
15 | }
16 | .device-container,
17 | .feature-item {
18 | max-width: 300px;
19 | margin: 0 auto;
20 | }
21 | .device-container {
22 | margin-bottom: 100px;
23 | @media(min-width: 992px) {
24 | margin-bottom: 0;
25 | }
26 | }
27 | .feature-item {
28 | margin-bottom: 100px;
29 | text-align: center;
30 | h3 {
31 | font-size: 30px;
32 | }
33 | i {
34 | font-size: 80px;
35 | background: -webkit-linear-gradient(to left, $theme-secondary, $theme-tertiary);
36 | background: linear-gradient(to left, $theme-secondary, $theme-tertiary);
37 | -webkit-background-clip: text;
38 | -webkit-text-fill-color: transparent;
39 | }
40 | }
41 | @media(min-width: 992px) {
42 | .device-container,
43 | .feature-item {
44 | max-width: none;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | subnav: false
4 | ---
5 |
6 |
24 |
25 | {% include example.html %}
26 |
27 | {% include commands.html %}
28 |
29 |
38 |
--------------------------------------------------------------------------------
/docs/js/new-age.js:
--------------------------------------------------------------------------------
1 | (function($) {
2 | "use strict"; // Start of use strict
3 |
4 | // Smooth scrolling using jQuery easing
5 | $('a[href*="#"]:not([href="#"])').click(function() {
6 | if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname) {
7 | var target = $(this.hash);
8 | target = target.length ? target : $('[name=' + this.hash.slice(1) + ']');
9 | if (target.length) {
10 | $('html, body').animate({
11 | scrollTop: (target.offset().top - 48)
12 | }, 1000, "easeInOutExpo");
13 | return false;
14 | }
15 | }
16 | });
17 |
18 | // Activate scrollspy to add active class to navbar items on scroll
19 | $('body').scrollspy({
20 | target: '#mainNav',
21 | offset: 54
22 | });
23 |
24 | // Closes responsive menu when a link is clicked
25 | $('.navbar-collapse>ul>li>a').click(function() {
26 | $('.navbar-collapse').collapse('hide');
27 | });
28 |
29 | // Collapse the navbar when page is scrolled
30 | $(window).scroll(function() {
31 | if ($("#mainNav").offset().top > 10) {
32 | $("#mainNav").addClass("navbar-shrink");
33 | } else {
34 | $("#mainNav").removeClass("navbar-shrink");
35 | }
36 | });
37 |
38 | })(jQuery); // End of use strict
39 |
--------------------------------------------------------------------------------
/lib/pipedream/dsl/pipeline/codebuild.rb:
--------------------------------------------------------------------------------
1 | module Pipedream::Dsl::Pipeline
2 | module Codebuild
3 | def codebuild(*projects)
4 | default = {
5 | # name: '', # will be set
6 | action_type_id: {
7 | category: "Build",
8 | owner: "AWS",
9 | provider: "CodeBuild",
10 | version: "1",
11 | },
12 | run_order: @run_order,
13 | # configuration: { project_name: '' }, # will be set
14 | # output_artifacts: [name: "BuildArtifact#{name}"], # TODO: maybe make this configurable with a setting
15 | input_artifacts: [name: "MainArtifact"],
16 | }
17 |
18 | actions = projects.map do |item|
19 | if item.is_a?(String)
20 | name = item
21 | default.deep_merge(
22 | name: name,
23 | configuration: { project_name: item },
24 | )
25 | else # Hash
26 | # With the hash notation, user needs to set: name and project_name
27 | #
28 | # codebuild(name: "action-name", project_name: "codebuild-project-names")
29 | #
30 | project_name = item.delete(:project_name)
31 | if project_name
32 | item[:configuration] = { project_name: project_name }
33 | end
34 |
35 | item[:name] ||= project_name
36 | item.reverse_merge(default)
37 | end
38 | end
39 |
40 | action(*actions)
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/docs/_docs/dsl/sns.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: SNS Topic DSL
3 | nav_text: Sns Topic
4 | categories: dsl
5 | nav_order: 16
6 | ---
7 |
8 | Pipe Dream will create an SNS Topic and associate it with your [Approval Action]({% link _docs/dsl/pipeline/approve.md %}) automatically.
9 | For example, if you have created an Approval Action in the pipeline with the `approve` method, then pipedream will create and manage the SNS topic for you.
10 |
11 | For most cases, the default SNS topic should suffice. However, if you wish to control the SNS topic properties you can do so with a `.pipedream/sns.rb` file. By declaring your own SNS topic, pipedream will use yours instead of the default one it usually creates. Here's an example:
12 |
13 | ```ruby
14 | display_name "my display_name"
15 | kms_master_key_id "String"
16 | subscription([{
17 | endpoint: 'my@email.com',
18 | protocol: 'email', # protocol values: https://docs.aws.amazon.com/sns/latest/api/API_Subscribe.html
19 | }])
20 | # topic_name "my-topic", # Recommend not setting because update requires: Replacement. Allow CloudFormation to set it so 2 pipelines dont have same SNS Topic name that collides
21 | ```
22 |
23 | The methods in the `sns.rb` are simply properties of the [SNS::Topic](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sns-topic.html) CloudFormation Resource
24 |
25 | Note: Pipe Dream will only create the SNS Topic if you have declared an Approval Action in the `pipeline.rb` without specifying an existing SNS Topic ARN.
26 |
27 | {% include prev_next.md %}
28 |
--------------------------------------------------------------------------------
/lib/pipedream/dsl/pipeline/github.rb:
--------------------------------------------------------------------------------
1 | module Pipedream::Dsl::Pipeline
2 | module Github
3 | def github(props)
4 | # nice shorthands
5 | source = props.delete(:source)
6 | source = extract_repo_source(source)
7 | owner,repo = source.split("/")
8 |
9 | # cli option can override this in codepipe/pipeline.rb set_source!
10 | # so cli option always gets the highest precendence
11 | branch = props.delete(:branch) || "master" # always delete branch prop
12 |
13 | o_auth_token = props.delete(:auth_token)
14 | poll_for_source_changes = props.delete(:poll_for_source_changes) || "false"
15 |
16 | source_name = props.delete(:source_name) || "Main"
17 |
18 | default = {
19 | name: source_name,
20 | action_type_id: {
21 | category: "Source",
22 | owner: "ThirdParty",
23 | provider: "GitHub",
24 | version: "1",
25 | },
26 | run_order: @run_order,
27 | configuration: {
28 | branch: branch,
29 | o_auth_token: o_auth_token,
30 | owner: owner,
31 | poll_for_source_changes: poll_for_source_changes,
32 | repo: repo,
33 | },
34 | output_artifacts: [name: "#{source_name}Artifact"]
35 | }
36 | action(props.reverse_merge(default))
37 | end
38 |
39 | def extract_repo_source(url)
40 | url.sub('git@github.com:','').sub('https://github.com/','').sub(/\.git$/,'')
41 | end
42 | extend self # mainly for extract_repo_source
43 | end
44 | end
--------------------------------------------------------------------------------
/docs/_sass/_contact.scss:
--------------------------------------------------------------------------------
1 | // Styling for the download section
2 | section.contact {
3 | text-align: center;
4 | h2 {
5 | margin-top: 0;
6 | margin-bottom: 25px;
7 | i {
8 | color: $brand-google-plus;
9 | }
10 | }
11 | ul.list-social {
12 | margin-bottom: 0;
13 | li {
14 | a {
15 | font-size: 40px;
16 | line-height: 80px;
17 | display: block;
18 | width: 80px;
19 | height: 80px;
20 | color: white;
21 | border-radius: 100%;
22 | }
23 | &.social-twitter {
24 | a {
25 | background-color: $brand-twitter;
26 | &:hover {
27 | background-color: darken($brand-twitter, 5%);
28 | }
29 | }
30 | }
31 | &.social-facebook {
32 | a {
33 | background-color: $brand-facebook;
34 | &:hover {
35 | background-color: darken($brand-facebook, 5%);
36 | }
37 | }
38 | }
39 | &.social-google-plus {
40 | a {
41 | background-color: $brand-google-plus;
42 | &:hover {
43 | background-color: darken($brand-google-plus, 5%);
44 | }
45 | }
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/lib/pipedream/dsl/role.rb:
--------------------------------------------------------------------------------
1 | module Pipedream::Dsl
2 | module Role
3 | PROPERTIES = %w[
4 | assume_role_policy_document
5 | managed_policy_arns
6 | max_session_duration
7 | path
8 | permissions_boundary
9 | policies
10 | role_name
11 | ]
12 | PROPERTIES.each do |prop|
13 | define_method(prop) do |v|
14 | @properties[prop.to_sym] = v
15 | end
16 | end
17 |
18 | # convenience wrapper methods
19 | def iam_policy(*definitions)
20 | @iam_statements = definitions.map { |definition| standardize_iam_policy(definition) }
21 | end
22 |
23 | # Returns standarized IAM statement
24 | def standardize_iam_policy(definition)
25 | case definition
26 | when String
27 | # Expands simple string from: logs => logs:*
28 | definition = "#{definition}:*" unless definition.include?(':')
29 | {
30 | action: [definition],
31 | effect: "Allow",
32 | resource: "*",
33 | }
34 | when Hash
35 | definition
36 | end
37 | end
38 |
39 | def managed_iam_policy(*definitions)
40 | @managed_policy_arns = definitions.map { |definition| standardize_managed_iam_policy(definition) }
41 | end
42 |
43 | # AmazonEC2ReadOnlyAccess => arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess
44 | def standardize_managed_iam_policy(definition)
45 | return definition if definition.include?('iam::aws:policy')
46 |
47 | "arn:aws:iam::aws:policy/#{definition}"
48 | end
49 | end
50 | end
51 |
--------------------------------------------------------------------------------
/docs/_docs/start.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Start
3 | nav_order: 6
4 | ---
5 |
6 | You can start a pipeline with the `pipe start` command. Here's an example:
7 |
8 | $ pipe start
9 | Pipeline started: demo
10 | Please check the CodePipeline console for the status.
11 | CodePipeline Console: https://us-west-2.console.aws.amazon.com/codesuite/codepipeline/pipelines/demo/view
12 | Pipeline cli: aws codepipeline get-pipeline-execution --pipeline-execution-id 02579d64-9271-4edc-aa45-bc9629d732bb --pipeline-name demo
13 | $
14 |
15 | ## Specifying Code Branch
16 |
17 | If you would like start a build using a specific code branch you can use the `--branch` or `-b` option. Example:
18 |
19 | pipe start -b feature-branch
20 |
21 | Note: When you specify a branch pipedream actually first updates the pipeline before starting the pipeline execution. This is done because CodePipeline does not natively support specifying the branch. It is discussed more here: [Using Different Branches]({% link _docs/examples/different-branches.md %}).
22 |
23 | ## AWS CLI Equivalent
24 |
25 | The `pipe start` command is a simple wrapper to the AWS API with the ruby sdk. You can also start pipelines with the `aws codepipeline` cli. Here's the equivalent CLI command:
26 |
27 | aws codepipeline start-pipeline-execution --name demo
28 |
29 | Note: There is no native branch option with the `aws codepipeline` cli.
30 |
31 | ## CLI Reference
32 |
33 | Also, for help info you can check the [pipe start]({% link _reference/pipe-start.md %}) CLI reference.
34 |
35 | {% include prev_next.md %}
36 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | This project *loosely* adheres to [Semantic Versioning](http://semver.org/), even before v1.0.
5 |
6 | ## [0.4.8] - 2022-01-07
7 | - [#5](https://github.com/boltops-tools/pipedream/pull/5) improvements for multiple sources and in_parallel method
8 |
9 | ## [0.4.7] - 2021-12-29
10 | - add rexml dependency
11 |
12 | ## [0.4.6] - 2021-12-29
13 | - [#4](https://github.com/boltops-tools/pipedream/pull/4) fix activesupport require
14 | - fix settings merge
15 |
16 | ## [0.4.5]
17 | - add aws codepipeline get-pipeline-state command hint in output also
18 | - dont autocamelize code build project name
19 | - #3 fix typo
20 |
21 | ## [0.4.4]
22 | - add mfa support for normal IAM user
23 |
24 | ## [0.4.3]
25 | - fix pipedream renaming
26 |
27 | ## [0.4.2]
28 | - fix project_name
29 |
30 | ## [0.4.1]
31 | - remove codebuild_prefix and codebuild_suffix helpers
32 |
33 | ## [0.4.0]
34 | - rename to pipedream
35 |
36 | ## [0.3.3]
37 | - allow no settings.yml file
38 |
39 | ## [0.3.2]
40 | - update vendor/aws_data
41 |
42 | ## [0.3.1]
43 | - fix gem dependencies in vendor
44 |
45 | ## [0.3.0]
46 | - update docs and cli help
47 |
48 | ## [0.2.1]
49 | - fix different branch check
50 |
51 | ## [0.2.0]
52 | - DSL: pipeline, role, schedule, webhook, sns
53 | - pipe deploy -b branch
54 | - pipe start -b branch
55 | - pipe cli commands: init deploy, start, delete
56 | - ssm support
57 | - codebuild\_prefix and codebuild\_suffix support
58 | - auto-create s3 bucket for artifacts
59 |
60 | ## [0.1.0]
61 | - Initial release.
62 |
--------------------------------------------------------------------------------
/lib/pipedream/evaluate.rb:
--------------------------------------------------------------------------------
1 | module Pipedream
2 | module Evaluate
3 | def evaluate(path)
4 | source_code = IO.read(path)
5 | begin
6 | instance_eval(source_code, path)
7 | rescue Exception => e
8 | if e.class == SystemExit # allow exit to happen normally
9 | raise
10 | else
11 | task_definition_error(e)
12 | puts "\nFull error:"
13 | raise
14 | end
15 | end
16 | end
17 |
18 | private
19 | # Prints out a user friendly task_definition error message
20 | def task_definition_error(e)
21 | error_info = e.backtrace.first
22 | path, line_no, _ = error_info.split(':')
23 | line_no = line_no.to_i
24 | puts "Error evaluating #{path}:".color(:red)
25 | puts e.message
26 | puts "Here's the line in #{path} with the error:\n\n"
27 |
28 | contents = IO.read(path)
29 | content_lines = contents.split("\n")
30 | context = 5 # lines of context
31 | top, bottom = [line_no-context-1, 0].max, line_no+context-1
32 | spacing = content_lines.size.to_s.size
33 | content_lines[top..bottom].each_with_index do |line_content, index|
34 | line_number = top+index+1
35 | if line_number == line_no
36 | printf("%#{spacing}d %s\n".color(:red), line_number, line_content)
37 | else
38 | printf("%#{spacing}d %s\n", line_number, line_content)
39 | end
40 | end
41 | end
42 |
43 | def lookup_pipedream_file(name)
44 | [".pipedream", @options[:type], name].compact.join("/")
45 | end
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/docs/_reference/pipe-start.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: pipe start
3 | reference: true
4 | ---
5 |
6 | ## Usage
7 |
8 | pipe start
9 |
10 | ## Description
11 |
12 | Start codebuild project.
13 |
14 | You can start a pipeline with the `pipe start` command. Here's an example:
15 |
16 | $ pipe start
17 | Pipeline started: demo
18 | Please check the CodePipeline console for the status.
19 | CodePipeline Console: https://us-west-2.console.aws.amazon.com/codesuite/codepipeline/pipelines/demo/view
20 | Pipeline cli: aws codepipeline get-pipeline-execution --pipeline-execution-id 02579d64-9271-4edc-aa45-bc9629d732bb --pipeline-name demo
21 | $
22 |
23 | ## Specifying Code Branch
24 |
25 | If you would like start a build using a specific code branch you can use the `--branch` or `-b` option. Example:
26 |
27 | pipe start -b feature-branch
28 |
29 | ## AWS CLI Equivalent
30 |
31 | The `pipe start` command is a simple wrapper to the AWS API with the ruby sdk. You can also start pipelines with the `aws codepipeline` cli. Here's the equivalent CLI command:
32 |
33 | aws codepipeline start-pipeline-execution --name demo
34 |
35 |
36 | ## Options
37 |
38 | ```
39 | [--sure=SURE] # Bypass are you sure prompt
40 | b, [--branch=BRANCH] # git branch
41 | [--stack-name=STACK_NAME] # Override the generated stack name. If you use this you must always specify it
42 | [--wait], [--no-wait] # Wait for operation to complete
43 | # Default: true
44 | [--verbose], [--no-verbose]
45 | [--noop], [--no-noop]
46 | ```
47 |
48 |
--------------------------------------------------------------------------------
/lib/pipedream/pipeline.rb:
--------------------------------------------------------------------------------
1 | module Pipedream
2 | class Pipeline
3 | extend Memoist
4 | include Dsl::Pipeline
5 | include Evaluate
6 |
7 | def initialize(options={})
8 | @options = options
9 | @pipeline_path = options[:pipeline_path] || get_pipeline_path
10 | @properties = default_properties # defaults make pipeline.rb simpler
11 | @stages = []
12 | end
13 |
14 | def run
15 | evaluate(@pipeline_path)
16 | @properties[:stages] ||= @stages
17 | set_source_branch!
18 |
19 | resource = {
20 | pipeline: {
21 | type: "AWS::CodePipeline::Pipeline",
22 | properties: @properties
23 | }
24 | }
25 | CfnCamelizer.transform(resource)
26 | end
27 |
28 | def default_properties
29 | {
30 | name: @options[:full_pipeline_name],
31 | role_arn: { "Fn::GetAtt": "IamRole.Arn" },
32 | artifact_store: {
33 | type: "S3",
34 | location: s3_bucket, # auto creates s3 bucket
35 | }
36 | }
37 | end
38 |
39 | # cli branch option always takes highest precedence
40 | def set_source_branch!
41 | return unless @options[:branch]
42 |
43 | source_stage = @properties[:stages].first
44 | action = source_stage[:actions].first
45 | action[:configuration][:branch] = @options[:branch]
46 | end
47 |
48 | def exist?
49 | File.exist?(@pipeline_path)
50 | end
51 |
52 | def s3_bucket
53 | S3Bucket.name
54 | end
55 |
56 | private
57 | def get_pipeline_path
58 | lookup_pipedream_file "pipeline.rb"
59 | end
60 | end
61 | end
62 |
--------------------------------------------------------------------------------
/docs/_docs/examples/different-branches.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Using Different Branches
3 | nav_text: Different Branches
4 | categories: examples
5 | nav_order: 19
6 | ---
7 |
8 | CodePipeline currently does not supports starting the pipeline execution with different branches natively. To get around this, we can:
9 |
10 | 1. update the pipeline before starting it.
11 | 2. create additional pipelines.
12 |
13 | Pipe Dream supports both methods.
14 |
15 | ## Update Pipeline Approach
16 |
17 | With the update pipeline approach, the pipeline gets updated if the current pipeline branch is different from the requested branch before a pipeline execution starts. Examples:
18 |
19 | pipe start -b master
20 | pipe start -b qa
21 |
22 | Note: With this approach, since the pipeline gets updated, the pipeline will maintain the last branch it was started with.
23 |
24 | ## Multiple Pipelines Approach
25 |
26 | You might normally set the branch option in your pipeline.rb. Example:
27 |
28 | ```ruby
29 | stage "Source" do
30 | github(
31 | source: "user/repo",
32 | branch: "master",
33 | auth_token: ssm("/github/user/token")
34 | )
35 | end
36 | ```
37 |
38 | When we deploy to create the pipelines, we can explicitly specify the branch to use. The cli option overrides the branch specified in `pipeline.rb`. Examples:
39 |
40 | pipe deploy demo-master -b master
41 | pipe deploy demo-qa -b qa
42 |
43 | This creates 2 pipelines. The demo-master pipeline will use the master branch, and the demo-qa pipeline will use the qa branch.
44 |
45 | To start the pipelines:
46 |
47 | pipe start demo-master
48 | pipe start demo-qa
49 |
50 | {% include prev_next.md %}
51 |
--------------------------------------------------------------------------------
/lib/pipedream/webhook.rb:
--------------------------------------------------------------------------------
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_pipedream_file("webhook.rb")
58 | end
59 | end
60 | end
61 |
--------------------------------------------------------------------------------
/docs/_includes/head.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {% if page.title %}
9 | {{ page.title }} - {{ site.title }}
10 | {% else %}
11 | Pipe Dream
12 | {% endif %}
13 |
14 |
15 |
16 | {% if site.meta_author %} {% endif %}
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/docs/_docs/dsl/pipeline.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Pipeline DSL
3 | nav_text: Pipeline
4 | categories: dsl
5 | nav_order: 10
6 | ---
7 |
8 | The pipeline DSL allows you to define the Stages and Actions within that Stage with only a few lines of code. In the [Quick Start]({% link quick-start.md %}), we define a very short pipeline to keep the introduction simple. Here we'll show more of the DSL power.
9 |
10 | ```ruby
11 | stage "Source" do
12 | github(
13 | source: "tongueroo/demo-test",
14 | auth_token: ssm("/github/user/token")
15 | )
16 | end
17 |
18 | stage "Build" do
19 | codebuild "demo1", "demo2"
20 | codebuild "demo3"
21 | end
22 |
23 | stage "Approve" do
24 | approve("Approve this deploy")
25 | end
26 |
27 | stage "Deploy" do
28 | codebuild "deploy"
29 | end
30 | ```
31 |
32 | This pipeline has 3 stages:
33 |
34 | 1. Downloads the source code from Gitub and uploads it to S3 as an output artifact.
35 | 2. Starts 3 codebuild projects with s3 upload from the previous step as an input artifact.
36 | 3. Waits for a manual approval stage.
37 | 4. Uses another codebuild project to kick off a deploy.
38 |
39 | ## Build Stage
40 |
41 | Within the build stage, there are multiple actions. Some of them run in parallel and some in serial.
42 |
43 | * The demo1 and demo2 codebuild projects run on the same `RunOrder=1`. They run in parallel.
44 | * The demo3 codebuild project run with `RunOrder=2`. It starts after both demo1 and demo2 finishes.
45 |
46 | The Pipeline DSL allows to you connect the stages together how you want them with very little code.
47 |
48 | ## Pipeline Specific DSL Docs
49 |
50 | {% assign docs = site.docs | where: "categories","dsl-pipeline" %}
51 | {% for doc in docs -%}
52 | * [{{doc.nav_text}}]({{doc.url}})
53 | {% endfor %}
54 |
55 | {% include prev_next.md %}
56 |
--------------------------------------------------------------------------------
/docs/_docs/conventions.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Naming Conventions
3 | nav_order: 8
4 | ---
5 |
6 | Pipe Dream follows a few naming conventions.
7 |
8 | ## Pipeline Name
9 |
10 | It will set the pipeline name by inferring the name of the parent folder. For example, if the parent folder is `demo`.
11 |
12 | cd demo
13 | pipe deploy
14 |
15 | The pipeline is named `demo`. You can override this easily by providing a pipeline name.
16 |
17 | pipe deploy my-pipeline # explicitly use my-pipeline as pipeline name
18 |
19 | The pipeline is named `my-pipeline`
20 |
21 | ## PIPE_ENV_EXTRA
22 |
23 | The `PIPE_ENV_EXTRA` also affects the name of the pipeline. It gets appended at the end of the pipeline name.
24 |
25 | PIPE_ENV_EXTRA=2 pipe deploy my-pipeline
26 |
27 | The pipeline is named `my-pipeline-2`.
28 |
29 | ## Settings append_env option
30 |
31 | If the append_env is configured in the [Settings]({% link _docs/settings.md %}), then the `PIPE_ENV` is added to the pipeline name. For example: `demo-development` instead of `demo`.
32 |
33 | ## Pipeline and Stack Names
34 |
35 | The CloudFormation stack name which creates the CodePipeline related resources is named the same as the pipeline name with `-pipe` appended to the stack name. Examples:
36 |
37 | PIPE_ENV | PIPE_ENV_EXTRA | append_env | Pipeline Name | Stack Name
38 | --- | --- | --- | --- | ---
39 | development | (not set) | false | demo | demo-pipe
40 | development | (not set) | true | demo-development | demo-development-pipe
41 | production | (not set) | true | demo-production | demo-production-pipe
42 | development | 2 | false | demo-2 | demo-2-pipe
43 | development | (not set) | true | demo-development | demo-development-pipe |
44 | development | 2 | true | demo-development | demo-development-2-pipe
45 |
46 | {% include prev_next.md %}
47 |
--------------------------------------------------------------------------------
/docs/_sass/_global.scss:
--------------------------------------------------------------------------------
1 | // Global styling for this template
2 | html,
3 | body {
4 | width: 100%;
5 | height: 100%;
6 | }
7 |
8 | body {
9 | @include body-font;
10 | }
11 |
12 | a {
13 | color: #0275d8;
14 | @include transition-all;
15 | &:hover,
16 | &:focus {
17 | color: darken(#0275d8, 10%);
18 | }
19 | }
20 |
21 | hr {
22 | max-width: 100px;
23 | margin: 25px auto 0;
24 | border-width: 1px;
25 | border-color: fade-out($gray-darker, .9);
26 | }
27 |
28 | hr.light {
29 | border-color: white;
30 | }
31 |
32 | h1,
33 | h2,
34 | h3,
35 | h4,
36 | h5,
37 | h6 {
38 | @include heading-font;
39 | }
40 |
41 | p {
42 | font-size: 1em;
43 | line-height: 1.5;
44 | margin-bottom: 20px;
45 | @media (min-width:992px) {
46 | font-size: 1.1em;
47 | }
48 | }
49 |
50 | li {
51 | font-size: 16px;
52 | @media (min-width:992px) {
53 | font-size: 18px;
54 | }
55 | }
56 |
57 | // code blocks
58 | pre {
59 | font-size: 12px;
60 | }
61 |
62 | table td {
63 | vertical-align: top;
64 | }
65 |
66 | code {
67 | font-size: 80%;
68 | }
69 |
70 |
71 | section {
72 | padding: 60px 0;
73 | h2 {
74 | // font-size: 50px;
75 | }
76 | }
77 |
78 | ::-moz-selection {
79 | color: white;
80 | background: $gray-darker;
81 | text-shadow: none;
82 | }
83 |
84 | ::selection {
85 | color: white;
86 | background: $gray-darker;
87 | text-shadow: none;
88 | }
89 |
90 | img::selection {
91 | color: white;
92 | background: transparent;
93 | }
94 |
95 | img::-moz-selection {
96 | color: white;
97 | background: transparent;
98 | }
99 |
100 | body {
101 | -webkit-tap-highlight-color: $gray-darker;
102 | }
103 |
--------------------------------------------------------------------------------
/pipedream.gemspec:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 | lib = File.expand_path("../lib", __FILE__)
3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4 | require "pipedream/version"
5 |
6 | Gem::Specification.new do |spec|
7 | spec.name = "pipedream"
8 | spec.version = Pipedream::VERSION
9 | spec.authors = ["Tung Nguyen"]
10 | spec.email = ["tongueroo@gmail.com"]
11 | spec.summary = "A beautiful and powerful DSL to create and manage AWS CodePipeline pipelines"
12 | spec.homepage = "https://github.com/tongueroo/pipedream"
13 | spec.license = "MIT"
14 |
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)/})
18 | end
19 | spec.files = gem_files + vendor_files
20 | spec.bindir = "exe"
21 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23 | spec.require_paths = ["lib"]
24 |
25 | spec.add_dependency "activesupport"
26 | spec.add_dependency "aws-mfa-secure"
27 | spec.add_dependency "aws-sdk-cloudformation"
28 | spec.add_dependency "aws-sdk-codepipeline"
29 | spec.add_dependency "aws-sdk-s3"
30 | spec.add_dependency "aws-sdk-ssm"
31 | spec.add_dependency "cfn_camelizer"
32 | spec.add_dependency "memoist"
33 | spec.add_dependency "rainbow"
34 | spec.add_dependency "render_me_pretty"
35 | spec.add_dependency "rexml"
36 | spec.add_dependency "thor"
37 | spec.add_dependency "zeitwerk"
38 |
39 | spec.add_development_dependency "bundler"
40 | spec.add_development_dependency "byebug"
41 | spec.add_development_dependency "cli_markdown"
42 | spec.add_development_dependency "rake"
43 | spec.add_development_dependency "rspec"
44 | end
45 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/less/mixins.less:
--------------------------------------------------------------------------------
1 | // Mixins
2 | // --------------------------
3 |
4 | .fa-icon() {
5 | display: inline-block;
6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 |
12 | }
13 |
14 | .fa-icon-rotate(@degrees, @rotation) {
15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})";
16 | -webkit-transform: rotate(@degrees);
17 | -ms-transform: rotate(@degrees);
18 | transform: rotate(@degrees);
19 | }
20 |
21 | .fa-icon-flip(@horiz, @vert, @rotation) {
22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)";
23 | -webkit-transform: scale(@horiz, @vert);
24 | -ms-transform: scale(@horiz, @vert);
25 | transform: scale(@horiz, @vert);
26 | }
27 |
28 |
29 | // Only display content to screen readers. A la Bootstrap 4.
30 | //
31 | // See: http://a11yproject.com/posts/how-to-hide-content/
32 |
33 | .sr-only() {
34 | position: absolute;
35 | width: 1px;
36 | height: 1px;
37 | padding: 0;
38 | margin: -1px;
39 | overflow: hidden;
40 | clip: rect(0,0,0,0);
41 | border: 0;
42 | }
43 |
44 | // Use in conjunction with .sr-only to only display content when it's focused.
45 | //
46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
47 | //
48 | // Credit: HTML5 Boilerplate
49 |
50 | .sr-only-focusable() {
51 | &:active,
52 | &:focus {
53 | position: static;
54 | width: auto;
55 | height: auto;
56 | margin: 0;
57 | overflow: visible;
58 | clip: auto;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/docs/_docs/dsl/role.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Role DSL
3 | nav_text: Role
4 | categories: dsl
5 | nav_order: 14
6 | ---
7 |
8 | Pipe Dream can create the IAM service role associated with the pipeline. Here's an example:
9 |
10 | .pipedream/role.rb:
11 |
12 | ```ruby
13 | iam_policy("logs", "ssm")
14 | ```
15 |
16 | For more control, here's a longer form:
17 |
18 | ```ruby
19 | iam_policy(
20 | action: [
21 | "logs:CreateLogGroup",
22 | "logs:CreateLogStream",
23 | "logs:PutLogEvents",
24 | "ssm:*",
25 | ],
26 | effect: "Allow",
27 | resource: "*"
28 | )
29 | ```
30 |
31 | You can also create managed IAM policy.
32 |
33 | ```ruby
34 | managed_iam_policy("AmazonS3ReadOnlyAccess")
35 | ```
36 |
37 | You can also add multiple managed IAM policies:
38 |
39 | ```ruby
40 | managed_iam_policy("AmazonS3ReadOnlyAccess", "AmazonEC2ReadOnlyAccess")
41 | ```
42 |
43 | ## Full DSL
44 |
45 | The convenience methods merely wrap properties of the [AWS::IAM::Role
46 | CloudFormation Resource](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html). If you wanted to set the CloudFormation properties more directly, here's an example of using the "Full" DSL.
47 |
48 | .pipedream/role.rb:
49 |
50 | ```ruby
51 | assume_role_policy_document(
52 | statement: [{
53 | action: ["sts:AssumeRole"],
54 | effect: "Allow",
55 | principal: {
56 | service: ["codepipeline.amazonaws.com"]
57 | }
58 | }],
59 | version: "2012-10-17"
60 | )
61 | path("/")
62 | policies([{
63 | policy_name: "CodeBuildAccess",
64 | policy_document: {
65 | version: "2012-10-17",
66 | statement: [{
67 | action: [
68 | "logs:CreateLogGroup",
69 | "logs:CreateLogStream",
70 | "logs:PutLogEvents",
71 | ],
72 | effect: "Allow",
73 | resource: "*"
74 | }]
75 | }
76 | }])
77 | ```
78 |
79 | {% include prev_next.md %}
80 |
--------------------------------------------------------------------------------
/docs/_docs/examples/multiple-codebuild-projects.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Multiple CodeBuild Projects
3 | nav_text: Multiple CodeBuild
4 | categories: examples
5 | nav_order: 20
6 | ---
7 |
8 | In this example guide, we'll create a couple of test CodeBuild projects and quickly connect them up to a pipeline.
9 |
10 | ## CodeBuild Projects
11 |
12 | We'll use the the [cody](https://cody.run/) tool to quickly get going.
13 |
14 | You can use any project, even an empty folder. You just have to make sure it is pushed to GitHub and has a `buildspec.yml`. If you need an example project, you can try this one: [tongueroo/demo-ufo](https://github.com/tongueroo/demo-ufo).
15 |
16 | First, you can use `cody init` create some starter `.cody` files.
17 |
18 | gem install cody # installs cody command
19 | cody init # create starter .cody files including buildspec.yml
20 | git add .
21 | git commit -m 'add starter .cody files'
22 | git push
23 |
24 | Then create the 4 CodeBuild projects for testing:
25 |
26 | for i in {1..4} ; do cody deploy demo$i --no-wait ; done
27 |
28 | ## CodePipeline
29 |
30 | Let's define a pipeline now with the 4 CodeBuild test projects. First, use `pipe init` to create the starter `.pipedream` files. Update your `pipeline.rb` with the following:
31 |
32 | .pipedream/pipeline.rb:
33 |
34 | ```ruby
35 | stage "Source" do
36 | github(
37 | source: "tongueroo/demo-ufo", # replace with your repo
38 | auth_token: ssm("/github/user/token")
39 | )
40 | end
41 |
42 | stage "Build" do
43 | codebuild "demo1"
44 | codebuild "demo2", "demo3" # runs in parallel
45 | codebuild "demo4"
46 | end
47 | ```
48 |
49 | Deploy it with:
50 |
51 | pipe deploy
52 |
53 | Last, start the pipeline execution:
54 |
55 | pipe start
56 |
57 | That's it! The pipeline will look like this:
58 |
59 | 
60 |
61 | {% include prev_next.md %}
62 |
--------------------------------------------------------------------------------
/docs/vendor/font-awesome/scss/_mixins.scss:
--------------------------------------------------------------------------------
1 | // Mixins
2 | // --------------------------
3 |
4 | @mixin fa-icon() {
5 | display: inline-block;
6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 |
12 | }
13 |
14 | @mixin fa-icon-rotate($degrees, $rotation) {
15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})";
16 | -webkit-transform: rotate($degrees);
17 | -ms-transform: rotate($degrees);
18 | transform: rotate($degrees);
19 | }
20 |
21 | @mixin fa-icon-flip($horiz, $vert, $rotation) {
22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)";
23 | -webkit-transform: scale($horiz, $vert);
24 | -ms-transform: scale($horiz, $vert);
25 | transform: scale($horiz, $vert);
26 | }
27 |
28 |
29 | // Only display content to screen readers. A la Bootstrap 4.
30 | //
31 | // See: http://a11yproject.com/posts/how-to-hide-content/
32 |
33 | @mixin sr-only {
34 | position: absolute;
35 | width: 1px;
36 | height: 1px;
37 | padding: 0;
38 | margin: -1px;
39 | overflow: hidden;
40 | clip: rect(0,0,0,0);
41 | border: 0;
42 | }
43 |
44 | // Use in conjunction with .sr-only to only display content when it's focused.
45 | //
46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
47 | //
48 | // Credit: HTML5 Boilerplate
49 |
50 | @mixin sr-only-focusable {
51 | &:active,
52 | &:focus {
53 | position: static;
54 | width: auto;
55 | height: auto;
56 | margin: 0;
57 | overflow: visible;
58 | clip: auto;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/docs/vendor/jquery-easing/jquery.easing.compatibility.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Easing Compatibility v1 - http://gsgd.co.uk/sandbox/jquery/easing
3 | *
4 | * Adds compatibility for applications that use the pre 1.2 easing names
5 | *
6 | * Copyright (c) 2007 George Smith
7 | * Licensed under the MIT License:
8 | * http://www.opensource.org/licenses/mit-license.php
9 | */
10 |
11 | (function($){
12 | $.extend( $.easing,
13 | {
14 | easeIn: function (x, t, b, c, d) {
15 | return $.easing.easeInQuad(x, t, b, c, d);
16 | },
17 | easeOut: function (x, t, b, c, d) {
18 | return $.easing.easeOutQuad(x, t, b, c, d);
19 | },
20 | easeInOut: function (x, t, b, c, d) {
21 | return $.easing.easeInOutQuad(x, t, b, c, d);
22 | },
23 | expoin: function(x, t, b, c, d) {
24 | return $.easing.easeInExpo(x, t, b, c, d);
25 | },
26 | expoout: function(x, t, b, c, d) {
27 | return $.easing.easeOutExpo(x, t, b, c, d);
28 | },
29 | expoinout: function(x, t, b, c, d) {
30 | return $.easing.easeInOutExpo(x, t, b, c, d);
31 | },
32 | bouncein: function(x, t, b, c, d) {
33 | return $.easing.easeInBounce(x, t, b, c, d);
34 | },
35 | bounceout: function(x, t, b, c, d) {
36 | return $.easing.easeOutBounce(x, t, b, c, d);
37 | },
38 | bounceinout: function(x, t, b, c, d) {
39 | return $.easing.easeInOutBounce(x, t, b, c, d);
40 | },
41 | elasin: function(x, t, b, c, d) {
42 | return $.easing.easeInElastic(x, t, b, c, d);
43 | },
44 | elasout: function(x, t, b, c, d) {
45 | return $.easing.easeOutElastic(x, t, b, c, d);
46 | },
47 | elasinout: function(x, t, b, c, d) {
48 | return $.easing.easeInOutElastic(x, t, b, c, d);
49 | },
50 | backin: function(x, t, b, c, d) {
51 | return $.easing.easeInBack(x, t, b, c, d);
52 | },
53 | backout: function(x, t, b, c, d) {
54 | return $.easing.easeOutBack(x, t, b, c, d);
55 | },
56 | backinout: function(x, t, b, c, d) {
57 | return $.easing.easeInOutBack(x, t, b, c, d);
58 | }
59 | });})(jQuery);
60 |
--------------------------------------------------------------------------------
/docs/_docs/ecs-deploy.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'ECS Deploy: Codebuild ufo ship vs CodePipeline ECS Deploy'
3 | nav_order: 21
4 | ---
5 |
6 | CodePipeline comes with many [Action Type Integrations](https://docs.aws.amazon.com/codepipeline/latest/userguide/integrations-action-type.html). One of the Integrations is [Amazon Elastic Container Service](https://docs.aws.amazon.com/codepipeline/latest/userguide/integrations-action-type.html#integrations-deploy) deployment. It is recommended to use [codebuild and ufo](https://codebuild.cloud/docs/examples/ecs/) to handle deployment to ECS though. We discuss some reasons below.
7 |
8 | ## Timeout
9 |
10 | With the CodePipeline ECS Deploy if your ECS service fails to stabilize then the pipeline stage will not timeout until 60 minutes later. There is no built-in way to abort the pipeline stage. This is discussed here: [CodePipeline stage timeouts / abort?](https://forums.aws.amazon.com/thread.jspa?threadID=216350).
11 |
12 | A workaround is discussed here: [How to stop an execution or set set timeout for an action in AWS CodePipeline?](https://stackoverflow.com/questions/50925732/how-to-stop-an-execution-or-set-set-timeout-for-an-action-in-aws-codepipeline/50929558) So to workaround waiting for 60 minutes, we can update the pipeline. This is a little bit inconvenient. By using a CodeBuild project, we have control over the timeout.
13 |
14 | ## It's Less Powerful
15 |
16 | The way the current CodePipeline ECS Deploy Action works is that it pulls down the current ECS task definition of the ECS service. It then replaces the image property on it. Last, it then updates the ECS service with the newly built Docker image.
17 |
18 | The [ufo tool](https://ufoships.com) is more powerful. The `ufo ship` command also handles creating the [ELB Load Balancer]((https://ufoships.com/docs/extras/load-balancer/)) and a vanity [Route53 endpoint](https://ufoships.com/docs/extras/route53-support/) for us. Also, it keeps task definitions codified.
19 |
20 | {% include prev_next.md %}
21 |
--------------------------------------------------------------------------------
/docs/_includes/subnav.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Quick Start
4 | Docs
5 |
13 |
14 | DSL Syntax
15 |
16 | {% assign docs = site.docs | where: "categories","dsl" %} {% for doc in docs -%}
17 | {% if doc.nav_text == "Pipeline" %}
18 | {{doc.nav_text}}
19 |
20 | {% assign docs = site.docs | where: "categories","dsl-pipeline" %} {% for doc in docs -%}
21 | {{doc.nav_text}}
22 | {% endfor %}
23 |
24 |
25 | {% else %}
26 | {{doc.nav_text}}
27 | {% endif %}
28 | {% endfor %}
29 |
30 |
31 | Examples
32 |
33 | {% assign docs = site.docs | where: "categories","examples" %} {% for doc in docs -%}
34 | {{doc.nav_text}}
35 | {% endfor %}
36 |
37 |
38 | More
39 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/docs/_config.yml:
--------------------------------------------------------------------------------
1 | # Site settings
2 | title: pipedream
3 | email: tongueroo@gmail.com
4 | url: https://pipedream.run
5 | description: "Pipedream CodePipeline DSL"
6 | keywords: "pipedream codepipeline boltops dsl ruby aws"
7 | skills: ""
8 | meta_author: Tung Nguyen
9 |
10 | # Google webmaster tools
11 | google_verify:
12 | google_analytics: "UA-98684555-12"
13 |
14 | # https://ssl.bing.com/webmaster/configure/verify/ownership Option 2 content= goes here
15 | bing_verify:
16 |
17 | # Contact form:
18 | # - static : pass through formspree.io to validate email sending
19 | # - disqus : replace contact form by disqus thread
20 | # - comment the line below if you want to stick with the default PHP contact form
21 | contact: static
22 |
23 | # If you use disqus you need disqus shortname
24 | # https://help.disqus.com/customer/portal/articles/466208
25 | disqus_shortname:
26 |
27 | # Color settings (hex-codes without the leading hash-tag)
28 | color:
29 | primary: 3972c7
30 | primary-rgb: "24,288,156" #"128,179,255"
31 | secondary: 2c3e50 #FD6E8A
32 | secondary-dark: 233140 #A2122F
33 | links: a3c8ff
34 |
35 | # Footer settings
36 | footer:
37 | copyright: BoltOps, LLC
38 | location: San Francisco, CA
39 | social: BoltOps
40 | credits:
41 | contact: contact@boltops.com
42 | phone:
43 |
44 | # Social networks usernames (many more available: google-plus, flickr, dribbble, pinterest, instagram, tumblr, linkedin, etc.)
45 | social:
46 | - title: twitter
47 | url: http://twitter.com/tongueroo
48 | - title: github
49 | url: https://github.com/tongueroo/pipedream
50 |
51 | # Credits content
52 | credits:
53 |
54 | # Build settings
55 | markdown: kramdown
56 | permalink: pretty
57 |
58 | gh_url: https://github.com/tongueroo/pipedream
59 |
60 | collections:
61 | docs:
62 | name: "Documentation"
63 | output: true
64 | reference:
65 | name: "Reference"
66 | output: true
67 |
68 | defaults:
69 | - values:
70 | layout: default
71 |
72 | plugins_dir:
73 | - jekyll-coffeescript
74 |
--------------------------------------------------------------------------------
/lib/pipedream/sequence.rb:
--------------------------------------------------------------------------------
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
67 |
--------------------------------------------------------------------------------
/lib/pipedream/core.rb:
--------------------------------------------------------------------------------
1 | require 'pathname'
2 | require 'yaml'
3 | require 'active_support/core_ext/string'
4 |
5 | module Pipedream
6 | module Core
7 | extend Memoist
8 |
9 | def root
10 | path = ENV['PIPE_ROOT'] || '.'
11 | Pathname.new(path)
12 | end
13 |
14 | def env
15 | # 2-way binding
16 | pipe_env = env_from_profile || 'development'
17 | pipe_env = ENV['PIPE_ENV'] if ENV['PIPE_ENV'] # highest precedence
18 | ActiveSupport::StringInquirer.new(pipe_env)
19 | end
20 | memoize :env
21 |
22 | def env_extra
23 | env_extra = ENV['PIPE_ENV_EXTRA'] if ENV['PIPE_ENV_EXTRA'] # highest precedence
24 | return if env_extra&.empty?
25 | env_extra
26 | end
27 | memoize :env_extra
28 |
29 | # Overrides AWS_PROFILE based on the Pipedream.env if set in configs/settings.yml
30 | # 2-way binding.
31 | def set_aws_profile!
32 | return if ENV['TEST']
33 | return unless File.exist?("#{Pipedream.root}/.pipedream/settings.yml") # for rake docs
34 | return unless settings # Only load if within Pipedream project and there's a settings.yml
35 |
36 | data = settings || {}
37 | if data[:aws_profile]
38 | puts "Using AWS_PROFILE=#{data[:aws_profile]} from PIPE_ENV=#{Pipedream.env} in config/settings.yml"
39 | ENV['AWS_PROFILE'] = data[:aws_profile]
40 | end
41 | end
42 |
43 | def settings
44 | Setting.new.data
45 | end
46 | memoize :settings
47 |
48 | def check_pipedream_project!
49 | check_path = "#{Pipedream.root}/.pipedream"
50 | unless File.exist?(check_path)
51 | puts "ERROR: No .pipedream folder found. Are you sure you are in a project with pipedream setup?".color(:red)
52 | puts "Current directory: #{Dir.pwd}"
53 | puts "If you want to set up pipedream for this prjoect, please create a settings file via: pipe init"
54 | exit 1 unless ENV['TEST']
55 | end
56 | end
57 |
58 | private
59 | def env_from_profile
60 | Pipedream::Setting.new.pipe_env
61 | end
62 | end
63 | end
64 |
--------------------------------------------------------------------------------
/docs/_includes/footer.html:
--------------------------------------------------------------------------------
1 |
35 |
36 |
43 |
--------------------------------------------------------------------------------
/docs/_sass/_mixins.scss:
--------------------------------------------------------------------------------
1 | // Mixins
2 | @mixin transition-all() {
3 | -webkit-transition: all .35s;
4 | -moz-transition: all .35s;
5 | transition: all .35s;
6 | }
7 |
8 | @mixin background-cover() {
9 | -webkit-background-size: cover;
10 | -moz-background-size: cover;
11 | -o-background-size: cover;
12 | background-size: cover;
13 | }
14 |
15 | @mixin button-variant($color, $background, $border) {
16 | color: $color;
17 | border-color: $border;
18 | background-color: $background;
19 | &:focus,
20 | &.focus {
21 | color: $color;
22 | border-color: darken($border, 25%);
23 | background-color: darken($background, 10%);
24 | }
25 | &:hover {
26 | color: $color;
27 | border-color: darken($border, 12%);
28 | background-color: darken($background, 10%);
29 | }
30 | &:active,
31 | &.active,
32 | .open > &.dropdown-toggle {
33 | color: $color;
34 | border-color: darken($border, 12%);
35 | background-color: darken($background, 10%);
36 | &:hover,
37 | &:focus,
38 | &.focus {
39 | color: $color;
40 | border-color: darken($border, 25%);
41 | background-color: darken($background, 17%);
42 | }
43 | }
44 | &:active,
45 | &.active,
46 | .open > &.dropdown-toggle {
47 | background-image: none;
48 | }
49 | &.disabled,
50 | &[disabled],
51 | fieldset[disabled] & {
52 | &:hover,
53 | &:focus,
54 | &.focus {
55 | border-color: $border;
56 | background-color: $background;
57 | }
58 | }
59 | .badge {
60 | color: $background;
61 | background-color: $color;
62 | }
63 | }
64 |
65 | @mixin heading-font {
66 | font-family: 'Catamaran', 'Helvetica', 'Arial', 'sans-serif';
67 | font-weight: 200;
68 | letter-spacing: 1px;
69 | }
70 |
71 | @mixin body-font {
72 | font-family: 'Muli', 'Helvetica', 'Arial', 'sans-serif';
73 | }
74 |
75 | @mixin alt-font {
76 | font-family: 'Lato', 'Helvetica', 'Arial', 'sans-serif';
77 | letter-spacing: 2px;
78 | text-transform: uppercase;
79 | }
80 |
--------------------------------------------------------------------------------
/lib/pipedream/cli.rb:
--------------------------------------------------------------------------------
1 | module Pipedream
2 | class CLI < Command
3 | class_option :verbose, type: :boolean
4 | class_option :noop, type: :boolean
5 |
6 | desc "init", "Initialize project with .codepipline files"
7 | long_desc Help.text(:init)
8 | Init.cli_options.each do |args|
9 | option(*args)
10 | end
11 | register(Init, "init", "init", "Set up initial .codepipline files.")
12 |
13 | common_options = Proc.new do
14 | option :stack_name, desc: "Override the generated stack name. If you use this you must always specify it"
15 | option :wait, type: :boolean, default: true, desc: "Wait for operation to complete"
16 | end
17 |
18 | desc "deploy PIPELINE_NAME", "Deploy pipeline."
19 | long_desc Help.text(:deploy)
20 | option :branch, aliases: "b", desc: "git branch" # important to default to nil
21 | common_options.call
22 | def deploy(pipeline_name=nil)
23 | Deploy.new(options.merge(pipeline_name: pipeline_name)).run
24 | end
25 |
26 | desc "start", "Start codebuild project."
27 | long_desc Help.text(:start)
28 | option :sure, desc: "Bypass are you sure prompt"
29 | option :branch, aliases: "b", desc: "git branch" # important to default to nil
30 | common_options.call
31 | def start(pipeline_name=nil)
32 | Start.new(options.merge(pipeline_name: pipeline_name)).run
33 | end
34 |
35 | desc "delete", "Delete codebuild project."
36 | long_desc Help.text(:delete)
37 | option :sure, desc: "Bypass are you sure prompt"
38 | common_options.call
39 | def delete(pipeline_name=nil)
40 | Delete.new(options.merge(pipeline_name: pipeline_name)).run
41 | end
42 |
43 | desc "completion *PARAMS", "Prints words for auto-completion."
44 | long_desc Help.text("completion")
45 | def completion(*params)
46 | Completer.new(CLI, *params).run
47 | end
48 |
49 | desc "completion_script", "Generates a script that can be eval to setup auto-completion."
50 | long_desc Help.text("completion_script")
51 | def completion_script
52 | Completer::Script.generate
53 | end
54 |
55 | desc "version", "prints version"
56 | def version
57 | puts VERSION
58 | end
59 | end
60 | end
61 |
--------------------------------------------------------------------------------
/docs/_sass/_masthead.scss:
--------------------------------------------------------------------------------
1 | // Styling for the masthead
2 | header.masthead {
3 | position: relative;
4 | overflow-y: hidden;
5 | width: 100%;
6 | min-height: auto;
7 | color: white;
8 | background-color: #020766;
9 | // background: url('../img/bg-pattern.png'), $theme-secondary;
10 | // background: url('../img/bg-pattern.png'), -webkit-linear-gradient(to left, $theme-secondary, $theme-tertiary);
11 | // background: url('../img/bg-pattern.png'), linear-gradient(to left, $theme-secondary, $theme-tertiary);
12 | .header-content {
13 | position: relative;
14 | padding: 100px 0 50px;
15 | text-align: center;
16 | .header-content-inner {
17 | position: relative;
18 | max-width: 500px;
19 | margin: 0 auto;
20 | h1 {
21 | font-size: 30px;
22 | margin-top: 0;
23 | margin-bottom: 30px;
24 | }
25 | .list-badges {
26 | margin-bottom: 25px;
27 | img {
28 | height: 50px;
29 | margin-bottom: 25px;
30 | }
31 | }
32 | }
33 | }
34 | .device-container {
35 | max-width: 300px;
36 | margin: 0 auto 100px;
37 | .screen img {
38 | border-radius: 3px;
39 | }
40 | }
41 | @media (min-width: 768px) {
42 | min-height: 100%;
43 | .header-content {
44 | height: 100vh;
45 | min-height: 600px;
46 | padding: 0;
47 | text-align: left;
48 | .header-content-inner {
49 | position: absolute;
50 | top: 50%;
51 | max-width: none;
52 | margin: 0;
53 | transform: translateY(-50%);
54 | h1 {
55 | font-size: 35px;
56 | }
57 | }
58 | }
59 | .device-container {
60 | max-width: none;
61 | max-height: calc(100vh - 100px);
62 | margin: 100px auto 0;
63 | }
64 | }
65 | @media (min-width: 992px) {
66 | .header-content .header-content-inner h1 {
67 | font-size: 50px;
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/lib/pipedream/init.rb:
--------------------------------------------------------------------------------
1 | module Pipedream
2 | class Init < Sequence
3 | # Ugly, this is how I can get the options from to match with this Thor::Group
4 | def self.cli_options
5 | [
6 | [:name, desc: "CodePipeline project name."],
7 | [:mode, desc: "Modes: light or full", default: "light" ],
8 | [:force, type: :boolean, desc: "Bypass overwrite are you sure prompt for existing files."],
9 | [:template, desc: "Custom template to use."],
10 | [:template_mode, desc: "Template mode: replace or additive."],
11 | ]
12 | end
13 | cli_options.each { |o| class_option(*o) }
14 |
15 | def setup_template_repo
16 | return unless @options[:template]&.include?('/')
17 |
18 | sync_template_repo
19 | end
20 |
21 | def set_source_path
22 | return unless @options[:template]
23 |
24 | custom_template = "#{ENV['HOME']}/.pipedream/templates/#{full_repo_name}"
25 |
26 | if @options[:template_mode] == "replace" # replace the template entirely
27 | override_source_paths(custom_template)
28 | else # additive: modify on top of default template
29 | default_template = File.expand_path("../../template", __FILE__)
30 | override_source_paths([custom_template, default_template])
31 | end
32 | end
33 |
34 | def copy_project
35 | puts "Initialize pipedream project in .pipedream"
36 |
37 | excludes = %w[.git]
38 | if @options[:mode] == "light"
39 | excludes += %w[
40 | settings.yml
41 | sns.rb
42 | ]
43 | end
44 | pattern = Regexp.new(excludes.join('|'))
45 |
46 | if @options[:template]
47 | directory ".", ".pipedream", exclude_pattern: pattern
48 | else
49 | directory ".", exclude_pattern: pattern
50 | end
51 | end
52 |
53 | private
54 | def project_name
55 | inferred_name = File.basename(Dir.pwd).gsub('_','-').gsub(/[^0-9a-zA-Z,-]/, '')
56 | @options[:name] || inferred_name
57 | end
58 |
59 | def project_github_repo
60 | default = "user/repo"
61 | return default unless File.exist?(".git/config") && git_installed?
62 |
63 | url = `git config --get remote.origin.url`.strip
64 | repo = Dsl::Pipeline::Github.extract_repo_source(url)
65 | repo == '' ? default : repo
66 | end
67 | end
68 | end
--------------------------------------------------------------------------------
/docs/_docs/dsl/pipeline/approve.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Approval Action DSL
3 | nav_text: Approve
4 | categories: dsl-pipeline
5 | nav_order: 12
6 | ---
7 |
8 | You can add an Approval Action to a Stage with the `approve` method. There are various helpful forms. Let's start with the simplest form.
9 |
10 | ## String Form
11 |
12 | The approve method take can take a simple String. In this form, it sets the message for the approval action. Essentially, it sets the `configuration.CustomData` property of the Approval action. See [Add an Action to a Pipeline in CodePipeline](https://docs.aws.amazon.com/codepipeline/latest/userguide/approvals-action-add.html) docs for the full structure.
13 |
14 | ```ruby
15 | stage "Approve" do
16 | approve("Approve this deployment")
17 | end
18 | ```
19 |
20 | With CodePipeline, an SNS topic is required to be associated with the Approval Action. In the case of a String form, pipedream will automatically create and manage the SNS topic associated with the `approve` declaration.
21 |
22 | ## Simplified Configuration Hash Form
23 |
24 | If the `approve` method is provided a Hash with the `notification_arn` and `custom_data`, then pipedream will set the `configuration` directly. Example:
25 |
26 | ```ruby
27 | stage "Approve" do
28 | approve(
29 | notification_arn: "arn:aws:sns:us-west-2:112233445566:hello-topic",
30 | custom_data: "Approve deployment",
31 | )
32 | end
33 | ```
34 |
35 | In this case, the Pipe Dream will *not* create an SNS Topic as we're have specified an existing SNS topic.
36 |
37 | ## Full Config Form
38 |
39 | The convenience methods merely wrap a CodePipeline Approval Action. An example of the Approval Action structure is provided in the [Add an Action to a Pipeline in CodePipeline](https://docs.aws.amazon.com/codepipeline/latest/userguide/approvals-action-add.html) docs.
40 |
41 | If you need to set the properties more directly, here's an example of using the "Full" Config.
42 |
43 | ```ruby
44 | stage "Approve" do
45 | approve(
46 | name: "approve",
47 | action_type_id: {
48 | category: "Approval",
49 | owner: "AWS",
50 | provider: "Manual",
51 | version: "1",
52 | },
53 | run_order: 1,
54 | configuration: {
55 | custom_data: "my message",
56 | notification_arn: {ref: "SnsTopic"}, # defaults to generated SNS topic
57 | },
58 | )
59 | end
60 | ```
61 |
62 | {% include prev_next.md %}
63 |
--------------------------------------------------------------------------------
/docs/_docs/dsl/pipeline/codebuild.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Codebuild Project
3 | nav_text: Codebuild
4 | categories: dsl-pipeline
5 | nav_order: 13
6 | ---
7 |
8 | The `codebuild` method is one of the most useful methods in the `pipeline.rb` DSL arsenal. With it, you can add codebuild projects to your pipeline and sequence them quickly. Let's start with the simplest form.
9 |
10 | ## String Form
11 |
12 | With the String form, the String sets both the name of the CodePipeline Action and CodeBuild Project.
13 |
14 | ```ruby
15 | stage "Deploy" do
16 | codebuild "demo1"
17 | codebuild "demo2", "demo3" # runs in parallel
18 | codebuild "demo4"
19 | end
20 | ```
21 |
22 | With just a few lines of code, we have define the pipeline to run the `demo1` codebuild project first. Then, in parallel, run `demo2` and `demo3` second. Last, run `demo4`.
23 |
24 | ## Simplified Hash Form
25 |
26 | With the Simplified Hash form, we have more control over the CodePipeline Action and CodeBuild Project names.
27 |
28 | ```ruby
29 | stage "Deploy" do
30 | codebuild(name: "action1", project_name: "demo1")
31 | codebuild({name: "action2", project_name: "demo2"}, {name: "action3", project_name: "demo3"}) # runs in parallel
32 | codebuild(name: "action4", project_name: "demo4")
33 | end
34 | ```
35 |
36 | In this form, we can explicitly set what the Action Name displays as in the CodePipeline. We can also set the CodeBuild project name explicitly.
37 |
38 | Note: You can mix and match the String form and the Hash form. Each item in the argument list gets evaluated and expanded out appropriately.
39 |
40 | ## Full Hash Form
41 |
42 | With the Full Hash Form, we have full control of the Action properties. To keep this example concise, we'll declare only one codebuild Action.
43 |
44 | ```ruby
45 | stage "Build" do
46 | codebuild(
47 | name: "action1",
48 | action_type_id: {
49 | category: "Build",
50 | owner: "AWS",
51 | provider: "CodeBuild",
52 | version: "1",
53 | },
54 | run_order: 1,
55 | configuration: { project_name: 'demo1' },
56 | # output_artifacts: [name: "BuildArtifact#{name}"], # optional
57 | input_artifacts: [name: "SourceArtifact"], # default
58 | )
59 | end
60 | ```
61 |
62 | The various forms all ultimately expand properties to the Full Hash Form. Generally, it is recommended you start with the simplest form and use the more complex forms when required.
63 |
64 | {% include prev_next.md %}
65 |
--------------------------------------------------------------------------------
/lib/pipedream/pipeline/s3_bucket.rb:
--------------------------------------------------------------------------------
1 | require "aws-sdk-s3"
2 |
3 | class Pipedream::Pipeline
4 | class S3Bucket
5 | extend Memoist
6 | include Pipedream::AwsServices
7 |
8 | class << self
9 | extend Memoist
10 | def name
11 | new.name
12 | end
13 | memoize :name
14 | end
15 |
16 | def name
17 | ensure_exists(bucket_name)
18 | bucket_name
19 | end
20 | memoize :name
21 |
22 | def bucket_name
23 | "codepipeline-#{aws.region}-#{aws.account}"
24 | end
25 |
26 | def ensure_exists(name)
27 | return if exists?(name) || ENV['TEST']
28 | s3.create_bucket(bucket: name)
29 | policy = {
30 | "Version": "2012-10-17",
31 | "Id": "SSEAndSSLPolicy",
32 | "Statement": [
33 | {
34 | "Sid": "DenyUnEncryptedObjectUploads",
35 | "Effect": "Deny",
36 | "Principal": "*",
37 | "Action": "s3:PutObject",
38 | "Resource": "arn:aws:s3:::#{name}/*",
39 | "Condition": {
40 | "StringNotEquals": {
41 | "s3:x-amz-server-side-encryption": "aws:kms"
42 | }
43 | }
44 | },
45 | {
46 | "Sid": "DenyInsecureConnections",
47 | "Effect": "Deny",
48 | "Principal": "*",
49 | "Action": "s3:*",
50 | "Resource": "arn:aws:s3:::#{name}/*",
51 | "Condition": {
52 | "Bool": {
53 | "aws:SecureTransport": "false"
54 | }
55 | }
56 | }
57 | ]
58 | }
59 | s3.put_bucket_policy(
60 | bucket: name,
61 | policy: JSON.dump(policy),
62 | )
63 | rescue Aws::S3::Errors::BucketAlreadyExists => e
64 | puts "ERROR #{e.class}: #{e.message}".color(:red)
65 | puts "Bucket name: #{name}"
66 | exit 1
67 | end
68 |
69 | def exists?(name)
70 | begin
71 | s3.head_bucket(bucket: name)
72 | true
73 | rescue Aws::S3::Errors::BucketAlreadyOwnedByYou, Aws::S3::Errors::Http301Error
74 | # These exceptions indicate bucket already exists
75 | # Aws::S3::Errors::Http301Error could be inaccurate but compromising for simplicity
76 | true
77 | rescue
78 | false
79 | end
80 | end
81 |
82 | private
83 | def aws
84 | AwsData.new
85 | end
86 | memoize :aws
87 | end
88 | end
89 |
--------------------------------------------------------------------------------
/docs/vendor/jquery-easing/jquery.easing.min.js:
--------------------------------------------------------------------------------
1 | (function(factory){if(typeof define==="function"&&define.amd){define(["jquery"],function($){return factory($)})}else if(typeof module==="object"&&typeof module.exports==="object"){exports=factory(require("jquery"))}else{factory(jQuery)}})(function($){$.easing.jswing=$.easing.swing;var pow=Math.pow,sqrt=Math.sqrt,sin=Math.sin,cos=Math.cos,PI=Math.PI,c1=1.70158,c2=c1*1.525,c3=c1+1,c4=2*PI/3,c5=2*PI/4.5;function bounceOut(x){var n1=7.5625,d1=2.75;if(x<1/d1){return n1*x*x}else if(x<2/d1){return n1*(x-=1.5/d1)*x+.75}else if(x<2.5/d1){return n1*(x-=2.25/d1)*x+.9375}else{return n1*(x-=2.625/d1)*x+.984375}}$.extend($.easing,{def:"easeOutQuad",swing:function(x){return $.easing[$.easing.def](x)},easeInQuad:function(x){return x*x},easeOutQuad:function(x){return 1-(1-x)*(1-x)},easeInOutQuad:function(x){return x<.5?2*x*x:1-pow(-2*x+2,2)/2},easeInCubic:function(x){return x*x*x},easeOutCubic:function(x){return 1-pow(1-x,3)},easeInOutCubic:function(x){return x<.5?4*x*x*x:1-pow(-2*x+2,3)/2},easeInQuart:function(x){return x*x*x*x},easeOutQuart:function(x){return 1-pow(1-x,4)},easeInOutQuart:function(x){return x<.5?8*x*x*x*x:1-pow(-2*x+2,4)/2},easeInQuint:function(x){return x*x*x*x*x},easeOutQuint:function(x){return 1-pow(1-x,5)},easeInOutQuint:function(x){return x<.5?16*x*x*x*x*x:1-pow(-2*x+2,5)/2},easeInSine:function(x){return 1-cos(x*PI/2)},easeOutSine:function(x){return sin(x*PI/2)},easeInOutSine:function(x){return-(cos(PI*x)-1)/2},easeInExpo:function(x){return x===0?0:pow(2,10*x-10)},easeOutExpo:function(x){return x===1?1:1-pow(2,-10*x)},easeInOutExpo:function(x){return x===0?0:x===1?1:x<.5?pow(2,20*x-10)/2:(2-pow(2,-20*x+10))/2},easeInCirc:function(x){return 1-sqrt(1-pow(x,2))},easeOutCirc:function(x){return sqrt(1-pow(x-1,2))},easeInOutCirc:function(x){return x<.5?(1-sqrt(1-pow(2*x,2)))/2:(sqrt(1-pow(-2*x+2,2))+1)/2},easeInElastic:function(x){return x===0?0:x===1?1:-pow(2,10*x-10)*sin((x*10-10.75)*c4)},easeOutElastic:function(x){return x===0?0:x===1?1:pow(2,-10*x)*sin((x*10-.75)*c4)+1},easeInOutElastic:function(x){return x===0?0:x===1?1:x<.5?-(pow(2,20*x-10)*sin((20*x-11.125)*c5))/2:pow(2,-20*x+10)*sin((20*x-11.125)*c5)/2+1},easeInBack:function(x){return c3*x*x*x-c1*x*x},easeOutBack:function(x){return 1+c3*pow(x-1,3)+c1*pow(x-1,2)},easeInOutBack:function(x){return x<.5?pow(2*x,2)*((c2+1)*2*x-c2)/2:(pow(2*x-2,2)*((c2+1)*(x*2-2)+c2)+2)/2},easeInBounce:function(x){return 1-bounceOut(1-x)},easeOutBounce:bounceOut,easeInOutBounce:function(x){return x<.5?(1-bounceOut(1-2*x))/2:(1+bounceOut(2*x-1))/2}})});
--------------------------------------------------------------------------------
/lib/pipedream/command.rb:
--------------------------------------------------------------------------------
1 | require "thor"
2 |
3 | # Override thor's long_desc identation behavior
4 | # https://github.com/erikhuda/thor/issues/398
5 | class Thor
6 | module Shell
7 | class Basic
8 | def print_wrapped(message, options = {})
9 | message = "\n#{message}" unless message[0] == "\n"
10 | stdout.puts message
11 | end
12 | end
13 | end
14 | end
15 |
16 | module Pipedream
17 | class Command < Thor
18 | class << self
19 | def dispatch(m, args, options, config)
20 | # Allow calling for help via:
21 | # codepipe command help
22 | # codepipe command -h
23 | # codepipe command --help
24 | # codepipe command -D
25 | #
26 | # as well thor's normal way:
27 | #
28 | # codepipe help command
29 | help_flags = Thor::HELP_MAPPINGS + ["help"]
30 | if args.length > 1 && !(args & help_flags).empty?
31 | args -= help_flags
32 | args.insert(-2, "help")
33 | end
34 |
35 | # codepipe version
36 | # codepipe --version
37 | # codepipe -v
38 | version_flags = ["--version", "-v"]
39 | if args.length == 1 && !(args & version_flags).empty?
40 | args = ["version"]
41 | end
42 |
43 | super
44 | end
45 |
46 | # Override command_help to include the description at the top of the
47 | # long_description.
48 | def command_help(shell, command_name)
49 | meth = normalize_command_name(command_name)
50 | command = all_commands[meth]
51 | alter_command_description(command)
52 | super
53 | end
54 |
55 | def alter_command_description(command)
56 | return unless command
57 |
58 | # Add description to beginning of long_description
59 | long_desc = if command.long_description
60 | "#{command.description}\n\n#{command.long_description}"
61 | else
62 | command.description
63 | end
64 |
65 | # add reference url to end of the long_description
66 | unless website.empty?
67 | full_command = [command.ancestor_name, command.name].compact.join('-')
68 | url = "#{website}/reference/codepipe-#{full_command}"
69 | long_desc += "\n\nHelp also available at: #{url}"
70 | end
71 |
72 | command.long_description = long_desc
73 | end
74 | private :alter_command_description
75 |
76 | # meant to be overriden
77 | def website
78 | ""
79 | end
80 | end
81 | end
82 | end
83 |
--------------------------------------------------------------------------------
/docs/vendor/bootstrap/css/bootstrap-reboot.min.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["../../scss/_normalize.scss","bootstrap-reboot.css","../../scss/_reboot.scss","../../scss/_variables.scss","../../scss/mixins/_hover.scss"],"names":[],"mappings":"4EAYA,KACE,YAAA,WACA,YAAA,KACA,qBAAA,KACA,yBAAA,KAUF,KACE,OAAA,EAOF,QAAA,MAAA,OAAA,OAAA,IAAA,QAME,QAAA,MAQF,GACE,UAAA,IACA,OAAA,MAAA,EAWF,WAAA,OAAA,KAGE,QAAA,MAOF,OACE,OAAA,IAAA,KAQF,GACE,mBAAA,YAAA,WAAA,YACA,OAAA,EACA,SAAA,QAQF,IACE,YAAA,UAAA,UACA,UAAA,IAWF,EACE,iBAAA,YACA,6BAAA,QAQF,SAAA,QAEE,cAAA,EAQF,YACE,cAAA,KACA,gBAAA,UACA,gBAAA,UAAA,OAOF,EAAA,OAEE,YAAA,QAOF,EAAA,OAEE,YAAA,OAQF,KAAA,IAAA,KAGE,YAAA,UAAA,UACA,UAAA,IAOF,IACE,WAAA,OAOF,KACE,iBAAA,KACA,MAAA,KAOF,MACE,UAAA,IAQF,IAAA,IAEE,UAAA,IACA,YAAA,EACA,SAAA,SACA,eAAA,SAGF,IACE,OAAA,OAGF,IACE,IAAA,MAUF,MAAA,MAEE,QAAA,aAOF,sBACE,QAAA,KACA,OAAA,EAOF,IACE,aAAA,KAOF,eACE,SAAA,OAWF,OAAA,MAAA,SAAA,OAAA,SAKE,YAAA,WACA,UAAA,KACA,YAAA,KACA,OAAA,EAQF,OAAA,MAEE,SAAA,QAQF,OAAA,OAEE,eAAA,KASF,aAAA,cAAA,OAAA,mBAIE,mBAAA,OAOF,gCAAA,+BAAA,gCAAA,yBAIE,aAAA,KACA,QAAA,EAOF,6BAAA,4BAAA,6BAAA,sBAIE,QAAA,IAAA,OAAA,WAOF,SACE,OAAA,IAAA,MAAA,OACA,OAAA,EAAA,IACA,QAAA,MAAA,OAAA,MAUF,OACE,mBAAA,WAAA,WAAA,WACA,MAAA,QACA,QAAA,MACA,UAAA,KACA,QAAA,EACA,YAAA,OAQF,SACE,QAAA,aACA,eAAA,SAOF,SACE,SAAA,KCrKF,gBAAA,aD+KE,mBAAA,WAAA,WAAA,WACA,QAAA,EC1KF,yCAAA,yCDmLE,OAAA,KC9KF,cDuLE,mBAAA,UACA,eAAA,KCnLF,4CAAA,yCD4LE,mBAAA,KAQF,6BACE,mBAAA,OACA,KAAA,QAWF,QAAA,KAEE,QAAA,MAOF,QACE,QAAA,UAUF,OACE,QAAA,aAOF,SACE,QAAA,KCnNF,SD8NE,QAAA,KEtbF,KACE,mBAAA,WAAA,WAAA,WAGF,EAAA,QAAA,SAGE,mBAAA,QAAA,WAAA,QAoBA,cAAgB,MAAA,aAQlB,KAYE,mBAAA,UAGA,4BAAA,YAGF,KACE,YAAA,cAAA,UAAA,mBAAA,WAAA,OC2K4H,iBD3K5H,MAAA,WACA,UAAA,KACA,YAAA,IACA,YAAA,IAEA,MAAA,QAEA,iBAAA,KD2LF,sBClLE,QAAA,YAYF,GAAI,GAAI,GAAI,GAAI,GAAI,GAClB,WAAA,EACA,cAAA,MAOF,EACE,WAAA,EACA,cAAA,KAIF,0BAAA,YAGE,OAAA,KAGF,QACE,cAAA,KACA,WAAA,OACA,YAAA,QAGF,GAAA,GAAA,GAGE,WAAA,EACA,cAAA,KAGF,MAAA,MAAA,MAAA,MAIE,cAAA,EAGF,GACE,YAAA,IAGF,GACE,cAAA,MACA,YAAA,EAGF,WACE,OAAA,EAAA,EAAA,KAQF,EACE,MAAA,QACA,gBAAA,KEhJE,QAAA,QFmJA,MAAA,QACA,gBAAA,UAUJ,8BACE,MAAA,QACA,gBAAA,KEhKE,oCAAA,oCFmKA,MAAA,QACA,gBAAA,KANJ,oCAUI,QAAA,EASJ,IAEE,WAAA,EAEA,cAAA,KAEA,SAAA,KAQF,OAGE,OAAA,EAAA,EAAA,KAQF,IAGE,eAAA,ODsIF,cCzHE,OAAA,QAcF,cAAA,EAAA,KAAA,OAAA,MAAA,MAAA,OAAA,QAAA,SASE,iBAAA,aAAA,aAAA,aAQF,MAEE,gBAAA,SAEA,iBAAA,YAGF,QACE,YAAA,OACA,eAAA,OACA,MAAA,QACA,WAAA,KACA,aAAA,OAGF,GAEE,WAAA,KAQF,MAEE,QAAA,aACA,cAAA,MAOF,aACE,QAAA,IAAA,OACA,QAAA,IAAA,KAAA,yBAGF,OAAA,MAAA,OAAA,SAME,YAAA,QAGF,8BAAA,2BAMI,OAAA,YAKJ,iBAAA,iBAAA,2BAAA,kBASE,mBAAA,QAGF,SAEE,OAAA,SAGF,SAME,UAAA,EAEA,QAAA,EACA,OAAA,EACA,OAAA,EAGF,OAEE,QAAA,MACA,MAAA,KACA,QAAA,EACA,cAAA,MACA,UAAA,OACA,YAAA,QAGF,mBAKE,mBAAA,KAIF,OACE,QAAA,aDsEF,SC9DE,QAAA"}
--------------------------------------------------------------------------------
/docs/quick-start.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Quick Start
3 | nav_order: 1
4 | ---
5 |
6 | In a hurry? No problem! Here's a quick start to get going.
7 |
8 | ## Summary
9 |
10 | gem install pipedream
11 | cd
12 | pipe init # generates starter .pipedream files
13 | # edit .pipedream/pipeline.rb
14 | pipe deploy # create the CodePipeline pipeline via CloudFormation
15 | pipe start # start a CodePipeline pipeline execution
16 |
17 | ## What Happened?
18 |
19 | Here are a little more details on what the summarized commands do. First, we install the pipedream tool.
20 |
21 | gem install pipedream
22 |
23 | Change into your project directory.
24 |
25 | cd
26 |
27 | If you need a demo project, you can try this demo project: [tongueroo/demo-ufo](git clone https://github.com/tongueroo/demo-ufo).
28 |
29 | git clone https://github.com/tongueroo/demo-ufo demo
30 | cd demo
31 |
32 | Create the starter .pipedream files in the project.
33 |
34 | pipe init # generates starter .pipedream files
35 |
36 | An important generated file is `.pipedream/pipeline.rb`. The starter file defines the pipeline via an [CodePipeline DSL]({% link _docs/dsl.md %}). It looks something like this:
37 |
38 | ```ruby
39 | stage "Source" do
40 | github(
41 | source: "user/repo", # replace with your repo
42 | auth_token: ssm("/github/user/token") # replace with your token
43 | )
44 | end
45 |
46 | stage "Build" do
47 | codebuild "demo"
48 | end
49 | ```
50 |
51 | The pipeline definition is much shorter than typical CloudFormation code. In this short pipeline, there are 2 stages:
52 |
53 | 1. Downloads the source code from Gitub and uploads it to S3 as an output artifact.
54 | 2. Starts some codebuild project with the code that was previously uploaded to s3 as the input artifact.
55 |
56 | Note, you need to have a codebuild project already created as a prerequisite. The example instructions for that are here: [Create CodeBuild Project]({% link _docs/examples/codebuild-project.md %}).
57 |
58 | You can then deploy or create the pipeline with a single command:
59 |
60 | pipe deploy
61 |
62 | This deploys a CloudFormation stack that creates a CodePipeline pipeline and IAM role. The IAM role permissions is defined in `.pipedream/role.rb` via the [IAM Role DSL]({% link _docs/dsl/role.md %}).
63 |
64 | Once the stack is complete. You can start the CodePipeline pipeline via the CLI or the CodePipeline console. Here is the CLI command:
65 |
66 | pipe start
67 |
68 | Here's what CodePipeline pipeline output looks like:
69 |
70 | 
71 |
72 | {% include prev_next.md %}
73 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # Pipe Dream
6 |
7 | 
8 | [](http://badge.fury.io/rb/pipedream)
9 |
10 | [](https://www.boltops.com)
11 |
12 | Pipe Dream provides a DSL to make it easy create a CodePipeline pipeline.
13 |
14 | Pipe Dream installs `pipedream` and `pipe` executables. Both of them do the same thing, `pipe` is just shorter to type.
15 |
16 | The documentation site is at: [pipedream.run](https://pipedream.run/)
17 |
18 | ## Quick Start
19 |
20 | pipe init
21 | pipe deploy
22 | pipe start
23 | pipe delete
24 |
25 | ## Init and Structure
26 |
27 | First, run `pipe init` to generate a starter `.pipedream` folder structure.
28 |
29 | $ tree .pipedream
30 | .pipedream
31 | ├── pipeline.rb
32 | └── schedule.rb
33 |
34 | File | Description
35 | --- | ---
36 | pipeline.rb | The CodePipeline pipeline written as a DSL. This is required. Here are the [Pipeline DSL docs](https://pipedream.run/docs/dsl/pipeline/)
37 | schedule.rb | A CloudWatch scheduled event written as a DSL. Here are the [Schedule DSL docs](https://pipedream.run/docs/dsl/schedule/)
38 |
39 | ## DSL
40 |
41 | .pipedream/pipeline.rb:
42 |
43 | ```ruby
44 | stage "Source" do
45 | github(
46 | source: "tongueroo/demo-ufo",
47 | auth_token: ssm("/github/user/token")
48 | )
49 | end
50 | stage "DeployStacks" do
51 | codebuild "demo1" # action declaration
52 | codebuild "demo2", "demo3" # will run in parallel
53 | codebuild "demo4" # action declaration
54 | end
55 | ```
56 |
57 | More [DSL docs](https://pipedream.run/docs/dsl/)
58 |
59 | ## Installation
60 |
61 | Add this line to your application's Gemfile:
62 |
63 | gem "pipedream"
64 |
65 | And then execute:
66 |
67 | bundle
68 |
69 | Or install it yourself as:
70 |
71 | gem install pipedream
72 |
73 | ## Contributing
74 |
75 | 1. Fork it
76 | 2. Create your feature branch (`git checkout -b my-new-feature`)
77 | 3. Commit your changes (`git commit -am "Add some feature"`)
78 | 4. Push to the branch (`git push origin my-new-feature`)
79 | 5. Create new Pull Request
80 |
--------------------------------------------------------------------------------
/docs/_sass/_navbar.scss:
--------------------------------------------------------------------------------
1 | // Styling for the navbar
2 | #mainNav {
3 | border-color: fade-out($gray-darker, .95);
4 | background-color: white;
5 | color: #777;
6 |
7 | border-bottom-color: #efefef;
8 | border-bottom-width: 2px;
9 | border-bottom-style: solid;
10 |
11 | @include transition-all;
12 | @include heading-font;
13 | .navbar-brand {
14 | color: #222;
15 | @include heading-font;
16 | &:hover,
17 | &:focus {
18 | color: darken($theme-primary, 10%);
19 | }
20 | @media (min-width: 992px) {
21 | font-size: 2em;
22 | }
23 | }
24 | .navbar-toggler {
25 | font-size: 12px;
26 | padding: 8px 10px;
27 | color: $gray-darker;
28 | }
29 | .navbar-nav {
30 | > li {
31 | > a {
32 | font-size: 1.05em;
33 | @include alt-font;
34 | &.active {
35 | color: $theme-primary !important;
36 | background-color: transparent;
37 | &:hover {
38 | background-color: transparent;
39 | }
40 | }
41 | }
42 | > a,
43 | > a:focus {
44 | color: $gray-darker;
45 | &:hover {
46 | color: $theme-primary;
47 | }
48 | }
49 | }
50 | }
51 | @media (min-width: 992px) {
52 | border-bottom-color: #efefef;
53 | border-bottom-width: 2px;
54 | border-bottom-style: solid;
55 |
56 | background-color: transparent;
57 | background-color: white;
58 |
59 | .navbar-brand {
60 | color: fade(#777, 70%);
61 | &:hover,
62 | &:focus {
63 | color: #777;
64 | }
65 | }
66 | .navbar-nav > li > a,
67 | .navbar-nav > li > a:focus {
68 | // color: fade-out(#777, .3);
69 | &:hover {
70 | color: #777;
71 | }
72 | }
73 | &.navbar-shrink {
74 | border-color: fade-out($gray-darker, .9);
75 | background-color: white;
76 | .navbar-brand {
77 | color: $gray-darker;
78 | &:hover,
79 | &:focus {
80 | color: $theme-primary;
81 | }
82 | }
83 | .navbar-nav > li > a,
84 | .navbar-nav > li > a:focus {
85 | color: $gray-darker;
86 | &:hover {
87 | color: $theme-primary;
88 | }
89 | }
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/lib/pipedream/help/deploy.md:
--------------------------------------------------------------------------------
1 | Examples:
2 |
3 | pipe deploy
4 | pipe deploy demo # explicitly specify pipeline name
5 | pipe deploy demo -b mybranch # specify git branch
6 |
7 | The pipeline is generated from the DSL and created with CloudFormation. The files that the DSL evaluates are in the `.pipedream` folder:
8 |
9 | .pipedream/pipeline.rb
10 | .pipedream/role.rb
11 | .pipedream/schedule.rb
12 | .pipedream/webhook.rb
13 |
14 | To create the CodePipeline pipeline, you run:
15 |
16 | pipe deploy
17 |
18 | You'll see output that looks something like this:
19 |
20 | $ pipe deploy
21 | Generated CloudFormation template at /tmp/codepipeline.yml
22 | Deploying stack demo-pipe with CodePipeline project demo
23 | Creating stack demo-pipe. Check CloudFormation console for status.
24 | Stack name demo-pipe status CREATE_IN_PROGRESS
25 | Here's the CloudFormation url to check for more details https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks
26 | Waiting for stack to complete
27 | 04:14:03AM CREATE_IN_PROGRESS AWS::CloudFormation::Stack demo-pipe User Initiated
28 | 04:14:06AM CREATE_IN_PROGRESS AWS::IAM::Role IamRole
29 | 04:14:07AM CREATE_IN_PROGRESS AWS::IAM::Role IamRole Resource creation Initiated
30 | 04:14:25AM CREATE_COMPLETE AWS::IAM::Role IamRole
31 | 04:14:28AM CREATE_IN_PROGRESS AWS::CodePipeline::Pipeline Pipeline
32 | 04:14:29AM CREATE_IN_PROGRESS AWS::CodePipeline::Pipeline Pipeline Resource creation Initiated
33 | 04:14:29AM CREATE_COMPLETE AWS::CodePipeline::Pipeline Pipeline
34 | 04:14:31AM CREATE_IN_PROGRESS AWS::CodePipeline::Webhook Webhook
35 | 04:14:33AM CREATE_IN_PROGRESS AWS::CodePipeline::Webhook Webhook Resource creation Initiated
36 | 04:14:33AM CREATE_COMPLETE AWS::CodePipeline::Webhook Webhook
37 | 04:14:35AM CREATE_COMPLETE AWS::CloudFormation::Stack demo-pipe
38 | Stack success status: CREATE_COMPLETE
39 | Time took for stack deployment: 35s.
40 | $
41 |
42 | ## Explicit Pipeline Name
43 |
44 | By default, the pipeline name is inferred and is the parent folder that you are within. You can explicitly specify the pipeline name as the first CLI argument:
45 |
46 | pipe deploy my-pipeline
47 |
48 | ## Specify Git Branch
49 |
50 | It is useful to build pipelines with different source git branches. You can pass a `--branch` option to the `pipe deploy` command. The cli `—-branch` option always takes the highest precedence. Example:
51 |
52 | pipe deploy my-pipeline --branch my-branch
53 |
54 | Note: When you specify a branch pipedream actually first updates the pipeline before starting the pipeline execution. This is done because CodePipeline does not natively support specifying the branch. It is discussed more here: [Using Different Branches]({% link _docs/examples/different-branches.md %}).
55 |
--------------------------------------------------------------------------------
/docs/_docs/deploy.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Deploy
3 | nav_order: 5
4 | ---
5 |
6 | The pipeline is generated from the DSL and created with CloudFormation. The files that the DSL evaluates are in the `.pipedream` folder:
7 |
8 | .pipedream/pipeline.rb
9 | .pipedream/role.rb
10 | .pipedream/schedule.rb
11 | .pipedream/webhook.rb
12 |
13 | To create the CodePipeline pipeline, you run:
14 |
15 | pipe deploy
16 |
17 | You'll see output that looks something like this:
18 |
19 | $ pipe deploy
20 | Generated CloudFormation template at /tmp/codepipeline.yml
21 | Deploying stack demo-pipe with CodePipeline project demo
22 | Creating stack demo-pipe. Check CloudFormation console for status.
23 | Stack name demo-pipe status CREATE_IN_PROGRESS
24 | Here's the CloudFormation url to check for more details https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks
25 | Waiting for stack to complete
26 | 04:14:03AM CREATE_IN_PROGRESS AWS::CloudFormation::Stack demo-pipe User Initiated
27 | 04:14:06AM CREATE_IN_PROGRESS AWS::IAM::Role IamRole
28 | 04:14:07AM CREATE_IN_PROGRESS AWS::IAM::Role IamRole Resource creation Initiated
29 | 04:14:25AM CREATE_COMPLETE AWS::IAM::Role IamRole
30 | 04:14:28AM CREATE_IN_PROGRESS AWS::CodePipeline::Pipeline Pipeline
31 | 04:14:29AM CREATE_IN_PROGRESS AWS::CodePipeline::Pipeline Pipeline Resource creation Initiated
32 | 04:14:29AM CREATE_COMPLETE AWS::CodePipeline::Pipeline Pipeline
33 | 04:14:31AM CREATE_IN_PROGRESS AWS::CodePipeline::Webhook Webhook
34 | 04:14:33AM CREATE_IN_PROGRESS AWS::CodePipeline::Webhook Webhook Resource creation Initiated
35 | 04:14:33AM CREATE_COMPLETE AWS::CodePipeline::Webhook Webhook
36 | 04:14:35AM CREATE_COMPLETE AWS::CloudFormation::Stack demo-pipe
37 | Stack success status: CREATE_COMPLETE
38 | Time took for stack deployment: 35s.
39 | $
40 |
41 | ## Explicit Pipeline Name
42 |
43 | By default, the pipeline name is inferred and is the parent folder name that you are within. You can explicitly specify the pipeline name as the first CLI argument:
44 |
45 | pipe deploy my-pipeline
46 |
47 | ## Specify Git Branch
48 |
49 | It is useful to build pipelines with different source git branches. You can pass a `--branch` option to the `pipe deploy` command. The cli `—-branch` option always takes the highest precedence. Example:
50 |
51 | pipe deploy my-pipeline --branch my-branch
52 |
53 | Note: When you specify a branch pipedream actually first updates the pipeline before starting the pipeline execution. This is done because CodePipeline does not currently support specifying the branch. It is discussed more here: [Using Different Branches]({% link _docs/examples/different-branches.md %}).
54 |
55 | ## CLI Reference
56 |
57 | Also, for help info you can check the [pipe deploy]({% link _reference/pipe-deploy.md %}) CLI reference.
58 |
59 | {% include prev_next.md %}
60 |
--------------------------------------------------------------------------------
/lib/pipedream/aws_services/helpers.rb:
--------------------------------------------------------------------------------
1 | module Pipedream::AwsServices
2 | module Helpers
3 | def stack_exists?(stack_name)
4 | return false if ENV['TEST']
5 |
6 | exist = nil
7 | begin
8 | # When the stack does not exist an exception is raised. Example:
9 | # Aws::CloudFormation::Errors::ValidationError: Stack with id blah does not exist
10 | cfn.describe_stacks(stack_name: stack_name)
11 | exist = true
12 | rescue Aws::CloudFormation::Errors::ValidationError => e
13 | if e.message =~ /does not exist/
14 | exist = false
15 | elsif e.message.include?("'stackName' failed to satisfy constraint")
16 | # Example of e.message when describe_stack with invalid stack name
17 | # "1 validation error detected: Value 'instance_and_route53' at 'stackName' failed to satisfy constraint: Member must satisfy regular expression pattern: [a-zA-Z][-a-zA-Z0-9]*|arn:[-a-zA-Z0-9:/._+]*"
18 | puts "Invalid stack name: #{stack_name}"
19 | puts "Full error message: #{e.message}"
20 | exit 1
21 | else
22 | raise # re-raise exception because unsure what other errors can happen
23 | end
24 | end
25 | exist
26 | end
27 |
28 | def pipeline_name_convention(name_base)
29 | items = [@pipeline_name, @options[:type], Pipedream.env_extra]
30 | items.insert(2, Pipedream.env) if Pipedream.settings.dig(:stack_naming, :append_env)
31 | items.reject(&:blank?).compact.join("-")
32 | end
33 |
34 | def inferred_pipeline_name
35 | # Essentially the project's parent folder
36 | File.basename(Dir.pwd).gsub('_','-').gsub(/\.+/,'-').gsub(/[^0-9a-zA-Z,-]/, '')
37 | end
38 |
39 | # Examples:
40 | #
41 | # myapp-ci-deploy # with Settings stack_naming append_env set to false.
42 | # myapp-ci-deploy-development
43 | # myapp-ci-deploy-development-2
44 | #
45 | def inferred_stack_name(pipeline_name)
46 | items = [pipeline_name, @options[:type], Pipedream.env_extra, "pipe"]
47 | append_env = Pipedream.settings.dig(:stack_naming, :append_env)
48 | items.insert(2, Pipedream.env) if append_env
49 | items.reject(&:blank?).compact.join("-")
50 | end
51 |
52 | def are_you_sure?(stack_name, action)
53 | if @options[:sure]
54 | sure = 'y'
55 | else
56 | message = case action
57 | when :update
58 | "Are you sure you want to want to update the #{stack_name.color(:green)} stack with the changes? (y/N)"
59 | when :delete
60 | "Are you sure you want to want to delete the #{stack_name.color(:green)} stack? (y/N)"
61 | end
62 | puts message
63 | sure = $stdin.gets
64 | end
65 |
66 | unless sure =~ /^y/
67 | puts "Whew! Exiting without running #{action}."
68 | exit 0
69 | end
70 | end
71 | end
72 | end
--------------------------------------------------------------------------------
/lib/pipedream/setting.rb:
--------------------------------------------------------------------------------
1 | require 'yaml'
2 | require 'render_me_pretty'
3 |
4 | module Pipedream
5 | class Setting
6 | extend Memoist
7 | def initialize(check_pipedream_project=true)
8 | @check_pipedream_project = check_pipedream_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_pipedream_project! if @check_pipedream_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 |
29 | env_data = all_envs[pipe_env] || {}
30 | base_data = all_envs["base"] || {}
31 | data = base_data.merge(env_data)
32 |
33 | data.deep_symbolize_keys
34 | end
35 | memoize :data
36 |
37 | # Resolves infinite problem since Pipedream.env can be determined from PIPE_ENV or settings.yml files.
38 | # When ufo is determined from settings it should not called Pipedream.env since that in turn calls
39 | # Settings.new.data which can then cause an infinite loop.
40 | def pipe_env
41 | path = "#{cb_root}/.pipedream/settings.yml"
42 | if File.exist?(path)
43 | settings = YAML.load_file(path)
44 | env = settings.find do |_env, section|
45 | section ||= {}
46 | ENV['AWS_PROFILE'] && ENV['AWS_PROFILE'] == section['aws_profile']
47 | end
48 | end
49 |
50 | pipe_env = env.first if env
51 | pipe_env = ENV['PIPE_ENV'] if ENV['PIPE_ENV'] # highest precedence
52 | pipe_env || 'development'
53 | end
54 |
55 | private
56 | def load_file(path)
57 | return Hash.new({}) unless File.exist?(path)
58 |
59 | content = RenderMePretty.result(path)
60 | data = YAML.load(content)
61 | # If key is is accidentally set to nil it screws up the merge_base later.
62 | # So ensure that all keys with nil value are set to {}
63 | data.each do |env, _setting|
64 | data[env] ||= {}
65 | end
66 | data
67 | end
68 |
69 | # automatically add base settings to the rest of the environments
70 | def merge_base(all_envs)
71 | base = all_envs["base"] || {}
72 | all_envs.each do |env, settings|
73 | all_envs[env] = base.merge(settings) unless env == "base"
74 | end
75 | all_envs
76 | end
77 |
78 | def project_settings_path
79 | "#{cb_root}/.pipedream/settings.yml"
80 | end
81 |
82 | def cb_root
83 | ENV["PIPE_ROOT"] || Dir.pwd
84 | end
85 | end
86 | end
87 |
--------------------------------------------------------------------------------
/lib/pipedream/schedule.rb:
--------------------------------------------------------------------------------
1 | module Pipedream
2 | class Schedule
3 | include Pipedream::Dsl::Schedule
4 | include Evaluate
5 |
6 | def initialize(options={})
7 | @options = options
8 | @schedule_path = options[:schedule_path] || get_schedule_path
9 | @properties = default_properties
10 | end
11 |
12 | def run
13 | return unless File.exist?(@schedule_path)
14 |
15 | old_properties = @properties.clone
16 | evaluate(@schedule_path)
17 |
18 | @properties[:schedule_expression] = @schedule_expression if @schedule_expression
19 | set_rule_event! if @rule_event_props
20 | return if old_properties == @properties # empty schedule.rb file
21 |
22 | resource = {
23 | events_rule: {
24 | type: "AWS::Events::Rule",
25 | properties: @properties
26 | },
27 | events_rule_role: events_rule_role,
28 | }
29 | CfnCamelizer.transform(resource)
30 | end
31 |
32 | def set_rule_event!
33 | props = @rule_event_props
34 | if props.key?(:detail)
35 | description = props.key?(:description) ? props.delete(:description) : rule_description
36 | rule_props = { event_pattern: props, description: description }
37 | else # if props.key?(:event_pattern)
38 | props[:description] ||= rule_description
39 | rule_props = props
40 | end
41 |
42 | @properties.merge!(rule_props)
43 | end
44 |
45 | def default_properties
46 | description = "CodePipeline #{@options[:full_pipeline_name]}"
47 | name = description.gsub(" ", "-").downcase
48 | {
49 | description: description,
50 | # event_pattern: ,
51 | name: name,
52 | # schedule_expression: ,
53 | state: "ENABLED",
54 | targets: [{
55 | arn: "arn:aws:codepipeline:#{aws.region}:#{aws.account}:#{@options[:full_pipeline_name]}",
56 | role_arn: { "Fn::GetAtt": "EventsRuleRole.Arn" }, # required for specific CodePipeline target.
57 | id: "CodePipelineTarget",
58 | }]
59 | }
60 | end
61 |
62 | private
63 | def get_schedule_path
64 | lookup_pipedream_file("schedule.rb")
65 | end
66 |
67 | def events_rule_role
68 | {
69 | type: "AWS::IAM::Role",
70 | properties: {
71 | assume_role_policy_document: {
72 | statement: [{
73 | action: [ "sts:AssumeRole" ],
74 | effect: "Allow",
75 | principal: { service: [ "events.amazonaws.com" ] }
76 | }],
77 | version: "2012-10-17"
78 | },
79 | path: "/",
80 | policies: [{
81 | policy_name: "CodePipelineAccess",
82 | policy_document: {
83 | version: "2012-10-17",
84 | statement: [{
85 | action: "codepipeline:StartPipelineExecution",
86 | effect: "Allow",
87 | resource: "arn:aws:codepipeline:#{aws.region}:#{aws.account}:#{@options[:full_pipeline_name]}"
88 | }]
89 | }
90 | }]
91 | }
92 | }
93 | end
94 |
95 | def aws
96 | @aws ||= AwsData.new
97 | end
98 | end
99 | end
100 |
--------------------------------------------------------------------------------
/lib/pipedream/start.rb:
--------------------------------------------------------------------------------
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 # pipeline name
58 | else
59 | puts "ERROR: Unable to find the pipeline 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 |
70 | puts "Pipeline started: #{pipeline_name}"
71 | puts "Please check the CodePipeline console for the status."
72 | puts "CodePipeline Console: #{url}"
73 | puts "Pipeline cli commands:"
74 | puts
75 | puts " aws codepipeline get-pipeline-execution --pipeline-execution-id #{execution_id} --pipeline-name #{pipeline_name}"
76 | puts " aws codepipeline get-pipeline-state --name #{pipeline_name}"
77 | puts
78 | end
79 |
80 | def pipeline_exists?(name)
81 | codepipeline.get_pipeline(name: name)
82 | true
83 | rescue Aws::CodePipeline::Errors::PipelineNotFoundException
84 | false
85 | end
86 | end
87 | end
88 |
--------------------------------------------------------------------------------
/docs/_includes/commands.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
The Code
5 |
Easy to learn
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
Overview
14 |
15 | {% highlight sh %}
16 | pipe init
17 | pipe deploy
18 | pipe start
19 | pipe delete
20 | {% endhighlight %}
21 |
22 |
23 |
24 |
Structure
25 |
26 | {% highlight sh %}
27 | .pipedream
28 | ├── pipeline.rb
29 | ├── role.rb
30 | ├── schedule.rb
31 | ├── settings.yml
32 | └── webhook.rb
33 | {% endhighlight %}
34 |
35 |
36 |
37 |
38 |
39 |
Usage
40 |
41 | {% highlight sh %}
42 | pipe deploy # infers the pipeline name from parent folder
43 | pipe deploy pipeline-name # explicitly specify pipeline name
44 |
45 | pipe start # infers the pipeline name from parent folder
46 | pipe start pipeline-name # explicitly specify pipeline name
47 | {% endhighlight %}
48 |
49 |
50 |
51 |
pipeline.rb
52 |
53 | {% highlight ruby %}
54 | stage "Source" do
55 | github(
56 | source: "user/repo",
57 | auth_token: ssm("/github/user/token")
58 | )
59 | end
60 | stage "DeployStacks" do
61 | codebuild "demo1" # action declaration
62 | codebuild "demo2", "demo3" # will run in parallel
63 | codebuild "demo4" # action declaration
64 | end
65 | {% endhighlight %}
66 |
67 |
68 |
69 |
70 |
71 |
role.rb
72 |
73 |
74 | {% highlight ruby %}
75 | iam_policy("logs", "ssm")
76 | {% endhighlight %}
77 |
78 |
79 |
80 |
webhook.rb
81 |
82 | {% highlight ruby %}
83 | github_token(ssm("/codepipeline/github/token"))
84 | {% endhighlight %}
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/docs/_reference/pipe-deploy.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: pipe deploy
3 | reference: true
4 | ---
5 |
6 | ## Usage
7 |
8 | pipe deploy PIPELINE_NAME
9 |
10 | ## Description
11 |
12 | Deploy pipeline.
13 |
14 | Examples:
15 |
16 | pipe deploy
17 | pipe deploy demo # explicitly specify pipeline name
18 | pipe deploy demo -b mybranch # specify git branch
19 |
20 | The pipeline is generated from the DSL and created with CloudFormation. The files that the DSL evaluates are in the `.pipedream` folder:
21 |
22 | .pipedream/pipeline.rb
23 | .pipedream/role.rb
24 | .pipedream/schedule.rb
25 | .pipedream/webhook.rb
26 |
27 | To create the CodePipeline pipeline, you run:
28 |
29 | pipe deploy
30 |
31 | You'll see output that looks something like this:
32 |
33 | $ pipe deploy
34 | Generated CloudFormation template at /tmp/codepipeline.yml
35 | Deploying stack demo-pipe with CodePipeline project demo
36 | Creating stack demo-pipe. Check CloudFormation console for status.
37 | Stack name demo-pipe status CREATE_IN_PROGRESS
38 | Here's the CloudFormation url to check for more details https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks
39 | Waiting for stack to complete
40 | 04:14:03AM CREATE_IN_PROGRESS AWS::CloudFormation::Stack demo-pipe User Initiated
41 | 04:14:06AM CREATE_IN_PROGRESS AWS::IAM::Role IamRole
42 | 04:14:07AM CREATE_IN_PROGRESS AWS::IAM::Role IamRole Resource creation Initiated
43 | 04:14:25AM CREATE_COMPLETE AWS::IAM::Role IamRole
44 | 04:14:28AM CREATE_IN_PROGRESS AWS::CodePipeline::Pipeline Pipeline
45 | 04:14:29AM CREATE_IN_PROGRESS AWS::CodePipeline::Pipeline Pipeline Resource creation Initiated
46 | 04:14:29AM CREATE_COMPLETE AWS::CodePipeline::Pipeline Pipeline
47 | 04:14:31AM CREATE_IN_PROGRESS AWS::CodePipeline::Webhook Webhook
48 | 04:14:33AM CREATE_IN_PROGRESS AWS::CodePipeline::Webhook Webhook Resource creation Initiated
49 | 04:14:33AM CREATE_COMPLETE AWS::CodePipeline::Webhook Webhook
50 | 04:14:35AM CREATE_COMPLETE AWS::CloudFormation::Stack demo-pipe
51 | Stack success status: CREATE_COMPLETE
52 | Time took for stack deployment: 35s.
53 | $
54 |
55 | ## Explicit Pipeline Name
56 |
57 | By default, the pipeline name is inferred and is the parent folder that you are within. You can explicitly specify the pipeline name as the first CLI argument:
58 |
59 | pipe deploy my-pipeline
60 |
61 | ## Specify Git Branch
62 |
63 | It is useful to build pipelines with different source git branches. You can pass a `--branch` option to the `pipe deploy` command. The cli `—-branch` option always takes the highest precedence. Example:
64 |
65 | pipe deploy my-pipeline --branch my-branch
66 |
67 | Note: When you specify a branch pipedream actually first updates the pipeline before starting the pipeline execution. This is done because CodePipeline does not natively support specifying the branch. It is discussed more here: [Using Different Branches]({% link _docs/examples/different-branches.md %}).
68 |
69 |
70 | ## Options
71 |
72 | ```
73 | b, [--branch=BRANCH] # git branch
74 | [--stack-name=STACK_NAME] # Override the generated stack name. If you use this you must always specify it
75 | [--wait], [--no-wait] # Wait for operation to complete
76 | # Default: true
77 | [--verbose], [--no-verbose]
78 | [--noop], [--no-noop]
79 | ```
80 |
81 |
--------------------------------------------------------------------------------
/lib/pipedream/stack.rb:
--------------------------------------------------------------------------------
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
96 |
--------------------------------------------------------------------------------
/docs/_sass/_syntax.scss:
--------------------------------------------------------------------------------
1 | .highlight { background: #ffffff; }
2 | .highlight .c { color: #999988; font-style: italic } /* Comment */
3 | .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
4 | .highlight .k { font-weight: bold } /* Keyword */
5 | .highlight .o { font-weight: bold } /* Operator */
6 | .highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */
7 | .highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */
8 | .highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */
9 | .highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
10 | .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
11 | .highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */
12 | .highlight .ge { font-style: italic } /* Generic.Emph */
13 | .highlight .gr { color: #aa0000 } /* Generic.Error */
14 | .highlight .gh { color: #999999 } /* Generic.Heading */
15 | .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
16 | .highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */
17 | .highlight .go { color: #888888 } /* Generic.Output */
18 | .highlight .gp { color: #555555 } /* Generic.Prompt */
19 | .highlight .gs { font-weight: bold } /* Generic.Strong */
20 | .highlight .gu { color: #aaaaaa } /* Generic.Subheading */
21 | .highlight .gt { color: #aa0000 } /* Generic.Traceback */
22 | .highlight .kc { font-weight: bold } /* Keyword.Constant */
23 | .highlight .kd { font-weight: bold } /* Keyword.Declaration */
24 | .highlight .kp { font-weight: bold } /* Keyword.Pseudo */
25 | .highlight .kr { font-weight: bold } /* Keyword.Reserved */
26 | .highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */
27 | .highlight .m { color: #009999 } /* Literal.Number */
28 | .highlight .s { color: #d14 } /* Literal.String */
29 | .highlight .na { color: #008080 } /* Name.Attribute */
30 | .highlight .nb { color: #0086B3 } /* Name.Builtin */
31 | .highlight .nc { color: #445588; font-weight: bold } /* Name.Class */
32 | .highlight .no { color: #008080 } /* Name.Constant */
33 | .highlight .ni { color: #800080 } /* Name.Entity */
34 | .highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */
35 | .highlight .nf { color: #990000; font-weight: bold } /* Name.Function */
36 | .highlight .nn { color: #555555 } /* Name.Namespace */
37 | .highlight .nt { color: #000080 } /* Name.Tag */
38 | .highlight .nv { color: #008080 } /* Name.Variable */
39 | .highlight .ow { font-weight: bold } /* Operator.Word */
40 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */
41 | .highlight .mf { color: #009999 } /* Literal.Number.Float */
42 | .highlight .mh { color: #009999 } /* Literal.Number.Hex */
43 | .highlight .mi { color: #009999 } /* Literal.Number.Integer */
44 | .highlight .mo { color: #009999 } /* Literal.Number.Oct */
45 | .highlight .sb { color: #d14 } /* Literal.String.Backtick */
46 | .highlight .sc { color: #d14 } /* Literal.String.Char */
47 | .highlight .sd { color: #d14 } /* Literal.String.Doc */
48 | .highlight .s2 { color: #d14 } /* Literal.String.Double */
49 | .highlight .se { color: #d14 } /* Literal.String.Escape */
50 | .highlight .sh { color: #d14 } /* Literal.String.Heredoc */
51 | .highlight .si { color: #d14 } /* Literal.String.Interpol */
52 | .highlight .sx { color: #d14 } /* Literal.String.Other */
53 | .highlight .sr { color: #009926 } /* Literal.String.Regex */
54 | .highlight .s1 { color: #d14 } /* Literal.String.Single */
55 | .highlight .ss { color: #990073 } /* Literal.String.Symbol */
56 | .highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */
57 | .highlight .vc { color: #008080 } /* Name.Variable.Class */
58 | .highlight .vg { color: #008080 } /* Name.Variable.Global */
59 | .highlight .vi { color: #008080 } /* Name.Variable.Instance */
60 | .highlight .il { color: #009999 } /* Literal.Number.Integer.Long */
61 |
62 | // fix css the pre code block that is generated with ```
63 | .highlighter-rouge .highlight {
64 | background: #ecf0f1;
65 | }
--------------------------------------------------------------------------------
/docs/vendor/bootstrap/css/bootstrap-reboot.min.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none}html{-webkit-box-sizing:border-box;box-sizing:border-box}*,::after,::before{-webkit-box-sizing:inherit;box-sizing:inherit}@-ms-viewport{width:device-width}html{-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}body{font-family:-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-size:1rem;font-weight:400;line-height:1.5;color:#292b2c;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{cursor:help}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}a{color:#0275d8;text-decoration:none}a:focus,a:hover{color:#014c8c;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle}[role=button]{cursor:pointer}[role=button],a,area,button,input,label,select,summary,textarea{-ms-touch-action:manipulation;touch-action:manipulation}table{border-collapse:collapse;background-color:transparent}caption{padding-top:.75rem;padding-bottom:.75rem;color:#636c72;text-align:left;caption-side:bottom}th{text-align:left}label{display:inline-block;margin-bottom:.5rem}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,select,textarea{line-height:inherit}input[type=checkbox]:disabled,input[type=radio]:disabled{cursor:not-allowed}input[type=date],input[type=time],input[type=datetime-local],input[type=month]{-webkit-appearance:listbox}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit}input[type=search]{-webkit-appearance:none}output{display:inline-block}[hidden]{display:none!important}/*# sourceMappingURL=bootstrap-reboot.min.css.map */
--------------------------------------------------------------------------------
/docs/_sass/_timeline.scss:
--------------------------------------------------------------------------------
1 | section#timeline {
2 | border-top-style: solid;
3 | border-top-width: 2px;
4 | border-top-color: #cacaca;
5 | }
6 |
7 | .timeline {
8 | position: relative;
9 | padding: 0;
10 | list-style: none;
11 | }
12 |
13 | .timeline:before {
14 | content: "";
15 | position: absolute;
16 | top: 0;
17 | bottom: 0;
18 | left: 40px;
19 | width: 2px;
20 | margin-left: -1.5px;
21 | background-color: #f1f1f1;
22 | }
23 |
24 | .timeline>li {
25 | position: relative;
26 | margin-bottom: 50px;
27 | min-height: 50px;
28 | }
29 |
30 | .timeline>li:before,
31 | .timeline>li:after {
32 | content: " ";
33 | display: table;
34 | }
35 |
36 | .timeline>li:after {
37 | clear: both;
38 | }
39 |
40 | .timeline>li .timeline-panel {
41 | float: right;
42 | position: relative;
43 | width: 100%;
44 | padding: 0 20px 0 100px;
45 | text-align: left;
46 | }
47 |
48 | .timeline>li .timeline-panel:before {
49 | right: auto;
50 | left: -15px;
51 | border-right-width: 15px;
52 | border-left-width: 0;
53 | }
54 |
55 | .timeline>li .timeline-panel:after {
56 | right: auto;
57 | left: -14px;
58 | border-right-width: 14px;
59 | border-left-width: 0;
60 | }
61 |
62 | .timeline>li .timeline-image {
63 | z-index: 100;
64 | position: absolute;
65 | left: 0;
66 | width: 80px;
67 | height: 80px;
68 | margin-left: 0;
69 | border: 7px solid #f1f1f1;
70 | border-radius: 100%;
71 | text-align: center;
72 | color: #fff;
73 | background-color: #fed136;
74 | }
75 |
76 | .timeline>li .timeline-image h4 {
77 | margin-top: 26px;
78 | font-size: 18px;
79 | line-height: 14px;
80 | }
81 |
82 | .timeline>li.timeline-inverted>.timeline-panel {
83 | float: right;
84 | padding: 0 20px 0 100px;
85 | text-align: left;
86 | }
87 |
88 | .timeline>li.timeline-inverted>.timeline-panel:before {
89 | right: auto;
90 | left: -15px;
91 | border-right-width: 15px;
92 | border-left-width: 0;
93 | }
94 |
95 | .timeline>li.timeline-inverted>.timeline-panel:after {
96 | right: auto;
97 | left: -14px;
98 | border-right-width: 14px;
99 | border-left-width: 0;
100 | }
101 |
102 | .timeline>li:last-child {
103 | margin-bottom: 0;
104 | }
105 |
106 | .timeline .timeline-heading h4 {
107 | margin-top: 0;
108 | color: inherit;
109 | }
110 |
111 | .timeline .timeline-heading h4.subheading {
112 | text-transform: none;
113 | }
114 |
115 | .timeline .timeline-body>p,
116 | .timeline .timeline-body>ul {
117 | margin-bottom: 0;
118 | }
119 |
120 | @media(min-width:768px) {
121 | .timeline:before {
122 | left: 50%;
123 | }
124 |
125 | .timeline>li {
126 | margin-bottom: 100px;
127 | min-height: 100px;
128 | }
129 |
130 | .timeline>li .timeline-panel {
131 | float: left;
132 | width: 41%;
133 | padding: 0 20px 20px 30px;
134 | text-align: right;
135 | }
136 |
137 | .timeline>li .timeline-image {
138 | left: 50%;
139 | width: 100px;
140 | height: 100px;
141 | margin-left: -50px;
142 | }
143 |
144 | .timeline>li .timeline-image h4 {
145 | margin-top: 32px;
146 | font-size: 20px;
147 | line-height: 18px;
148 | }
149 |
150 | .timeline>li.timeline-inverted>.timeline-panel {
151 | float: right;
152 | padding: 0 30px 20px 20px;
153 | text-align: left;
154 | }
155 | }
156 |
157 | @media(min-width:992px) {
158 | .timeline>li {
159 | min-height: 150px;
160 | }
161 |
162 | .timeline>li .timeline-panel {
163 | padding: 0 20px 20px;
164 | }
165 |
166 | .timeline>li .timeline-image {
167 | width: 150px;
168 | height: 150px;
169 | margin-left: -75px;
170 | }
171 |
172 | .timeline>li .timeline-image h4 {
173 | margin-top: 55px;
174 | font-size: 38px;
175 | line-height: 26px;
176 | }
177 |
178 | .timeline>li.timeline-inverted>.timeline-panel {
179 | padding: 0 20px 20px;
180 | }
181 | }
182 |
183 | @media(min-width:1200px) {
184 | .timeline>li {
185 | min-height: 170px;
186 | }
187 |
188 | .timeline>li .timeline-panel {
189 | padding: 0 20px 20px 100px;
190 | }
191 |
192 | .timeline>li .timeline-image {
193 | width: 170px;
194 | height: 170px;
195 | margin-left: -85px;
196 | }
197 |
198 | .timeline>li .timeline-image h4 {
199 | /*margin-top: 40px;*/
200 | margin-top: 65px;
201 | font-size: 42px;
202 | }
203 |
204 | .timeline>li.timeline-inverted>.timeline-panel {
205 | padding: 0 100px 20px 20px;
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/docs/vendor/jquery-easing/jquery.easing.js:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery Easing v1.4.1 - http://gsgd.co.uk/sandbox/jquery/easing/
3 | * Open source under the BSD License.
4 | * Copyright © 2008 George McGinley Smith
5 | * All rights reserved.
6 | * https://raw.github.com/gdsmith/jquery-easing/master/LICENSE
7 | */
8 |
9 | (function (factory) {
10 | if (typeof define === "function" && define.amd) {
11 | define(['jquery'], function ($) {
12 | return factory($);
13 | });
14 | } else if (typeof module === "object" && typeof module.exports === "object") {
15 | exports = factory(require('jquery'));
16 | } else {
17 | factory(jQuery);
18 | }
19 | })(function($){
20 |
21 | // Preserve the original jQuery "swing" easing as "jswing"
22 | $.easing.jswing = $.easing.swing;
23 |
24 | var pow = Math.pow,
25 | sqrt = Math.sqrt,
26 | sin = Math.sin,
27 | cos = Math.cos,
28 | PI = Math.PI,
29 | c1 = 1.70158,
30 | c2 = c1 * 1.525,
31 | c3 = c1 + 1,
32 | c4 = ( 2 * PI ) / 3,
33 | c5 = ( 2 * PI ) / 4.5;
34 |
35 | // x is the fraction of animation progress, in the range 0..1
36 | function bounceOut(x) {
37 | var n1 = 7.5625,
38 | d1 = 2.75;
39 | if ( x < 1/d1 ) {
40 | return n1*x*x;
41 | } else if ( x < 2/d1 ) {
42 | return n1*(x-=(1.5/d1))*x + 0.75;
43 | } else if ( x < 2.5/d1 ) {
44 | return n1*(x-=(2.25/d1))*x + 0.9375;
45 | } else {
46 | return n1*(x-=(2.625/d1))*x + 0.984375;
47 | }
48 | }
49 |
50 | $.extend( $.easing,
51 | {
52 | def: 'easeOutQuad',
53 | swing: function (x) {
54 | return $.easing[$.easing.def](x);
55 | },
56 | easeInQuad: function (x) {
57 | return x * x;
58 | },
59 | easeOutQuad: function (x) {
60 | return 1 - ( 1 - x ) * ( 1 - x );
61 | },
62 | easeInOutQuad: function (x) {
63 | return x < 0.5 ?
64 | 2 * x * x :
65 | 1 - pow( -2 * x + 2, 2 ) / 2;
66 | },
67 | easeInCubic: function (x) {
68 | return x * x * x;
69 | },
70 | easeOutCubic: function (x) {
71 | return 1 - pow( 1 - x, 3 );
72 | },
73 | easeInOutCubic: function (x) {
74 | return x < 0.5 ?
75 | 4 * x * x * x :
76 | 1 - pow( -2 * x + 2, 3 ) / 2;
77 | },
78 | easeInQuart: function (x) {
79 | return x * x * x * x;
80 | },
81 | easeOutQuart: function (x) {
82 | return 1 - pow( 1 - x, 4 );
83 | },
84 | easeInOutQuart: function (x) {
85 | return x < 0.5 ?
86 | 8 * x * x * x * x :
87 | 1 - pow( -2 * x + 2, 4 ) / 2;
88 | },
89 | easeInQuint: function (x) {
90 | return x * x * x * x * x;
91 | },
92 | easeOutQuint: function (x) {
93 | return 1 - pow( 1 - x, 5 );
94 | },
95 | easeInOutQuint: function (x) {
96 | return x < 0.5 ?
97 | 16 * x * x * x * x * x :
98 | 1 - pow( -2 * x + 2, 5 ) / 2;
99 | },
100 | easeInSine: function (x) {
101 | return 1 - cos( x * PI/2 );
102 | },
103 | easeOutSine: function (x) {
104 | return sin( x * PI/2 );
105 | },
106 | easeInOutSine: function (x) {
107 | return -( cos( PI * x ) - 1 ) / 2;
108 | },
109 | easeInExpo: function (x) {
110 | return x === 0 ? 0 : pow( 2, 10 * x - 10 );
111 | },
112 | easeOutExpo: function (x) {
113 | return x === 1 ? 1 : 1 - pow( 2, -10 * x );
114 | },
115 | easeInOutExpo: function (x) {
116 | return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ?
117 | pow( 2, 20 * x - 10 ) / 2 :
118 | ( 2 - pow( 2, -20 * x + 10 ) ) / 2;
119 | },
120 | easeInCirc: function (x) {
121 | return 1 - sqrt( 1 - pow( x, 2 ) );
122 | },
123 | easeOutCirc: function (x) {
124 | return sqrt( 1 - pow( x - 1, 2 ) );
125 | },
126 | easeInOutCirc: function (x) {
127 | return x < 0.5 ?
128 | ( 1 - sqrt( 1 - pow( 2 * x, 2 ) ) ) / 2 :
129 | ( sqrt( 1 - pow( -2 * x + 2, 2 ) ) + 1 ) / 2;
130 | },
131 | easeInElastic: function (x) {
132 | return x === 0 ? 0 : x === 1 ? 1 :
133 | -pow( 2, 10 * x - 10 ) * sin( ( x * 10 - 10.75 ) * c4 );
134 | },
135 | easeOutElastic: function (x) {
136 | return x === 0 ? 0 : x === 1 ? 1 :
137 | pow( 2, -10 * x ) * sin( ( x * 10 - 0.75 ) * c4 ) + 1;
138 | },
139 | easeInOutElastic: function (x) {
140 | return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ?
141 | -( pow( 2, 20 * x - 10 ) * sin( ( 20 * x - 11.125 ) * c5 )) / 2 :
142 | pow( 2, -20 * x + 10 ) * sin( ( 20 * x - 11.125 ) * c5 ) / 2 + 1;
143 | },
144 | easeInBack: function (x) {
145 | return c3 * x * x * x - c1 * x * x;
146 | },
147 | easeOutBack: function (x) {
148 | return 1 + c3 * pow( x - 1, 3 ) + c1 * pow( x - 1, 2 );
149 | },
150 | easeInOutBack: function (x) {
151 | return x < 0.5 ?
152 | ( pow( 2 * x, 2 ) * ( ( c2 + 1 ) * 2 * x - c2 ) ) / 2 :
153 | ( pow( 2 * x - 2, 2 ) *( ( c2 + 1 ) * ( x * 2 - 2 ) + c2 ) + 2 ) / 2;
154 | },
155 | easeInBounce: function (x) {
156 | return 1 - bounceOut( 1 - x );
157 | },
158 | easeOutBounce: bounceOut,
159 | easeInOutBounce: function (x) {
160 | return x < 0.5 ?
161 | ( 1 - bounceOut( 1 - 2 * x ) ) / 2 :
162 | ( 1 + bounceOut( 2 * x - 1 ) ) / 2;
163 | }
164 | });
165 |
166 | });
167 |
--------------------------------------------------------------------------------