├── .gitignore ├── Gemfile ├── Gemfile.lock ├── README.md ├── app.json ├── bulk-sample.rb ├── ci-bundle-update.rb └── wercker.yml /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle 2 | /.envrc 3 | /vendor/bundle 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | ruby '2.3.1' 3 | 4 | gem 'circleci' 5 | gem 'httparty' 6 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | circleci (2.0.1) 5 | httparty (0.15.6) 6 | multi_xml (>= 0.5.2) 7 | multi_xml (0.6.0) 8 | 9 | PLATFORMS 10 | ruby 11 | 12 | DEPENDENCIES 13 | circleci 14 | httparty 15 | 16 | 17 | RUBY VERSION 18 | ruby 2.3.1p112 19 | 20 | BUNDLED WITH 21 | 1.10.5 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ci-build-trigger 2 | 3 | Build your CI project with build_parameters "{BUNDLE_UPDATE: true}" and more. 4 | 5 | It supports `CircleCI` and `Wercker`. 6 | 7 | ## Setup 8 | 9 | 1. Click [![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy) 10 | 1. Open Heroku scheduler `ex. $ heroku addons:open scheduler --app ` 11 | 1. Add command to Heroku scheduler 12 | * **CircleCI**: `$ bundle exec ruby ci-bundle-update.rb` 13 | * **Wercker**: `$ bundle exec ruby ci-bundle-update.rb --ci wercker` 14 | 15 | ## More 16 | 17 | In Japanese 18 | 19 | http://masutaka.net/chalow/2015-07-28-1.html 20 | 21 | ## Recommend for CircleCI users 22 | 23 | You can use [Scheduling a Workflow](https://circleci.com/docs/2.0/workflows/#scheduling-a-workflow) of CircleCI 2.0. It provides scheduled build like crontab. 24 | 25 | :bulb: So I recommend to use Scheduling a Workflow, not ci-build-trigger. 26 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bundle update as CI", 3 | "keywords": [ 4 | "CircleCI", 5 | "bundler" 6 | ], 7 | "env": { 8 | "GITHUB_USERNAME": { 9 | "description": "Your GitHub account or organization" 10 | }, 11 | "GITHUB_REPONAME": { 12 | "description": "Your GitHub repository name" 13 | }, 14 | "BRANCH": { 15 | "value": "master" 16 | }, 17 | "CIRCLECI_TOKEN": { 18 | "description": "CircleCI: Project Setting -> API Permissions", 19 | "required": false 20 | }, 21 | "WERCKER_TOKEN": { 22 | "description": "Wercker: Settings -> Personal tokens", 23 | "required": false 24 | }, 25 | "EXTRA_BUILD_PARAMETERS": { 26 | "description": "format: =,=,...", 27 | "required": false 28 | }, 29 | "TZ": { 30 | "description": "Set your timezone, if you use EXEC_DAYS.", 31 | "value": "UTC", 32 | "required": false 33 | }, 34 | "EXEC_DAYS": { 35 | "description": "ex. 'Sun or Mon,Wed,Fri' if unset, executes every day.", 36 | "required": false 37 | } 38 | }, 39 | "addons": ["scheduler:standard"] 40 | } 41 | -------------------------------------------------------------------------------- /bulk-sample.rb: -------------------------------------------------------------------------------- 1 | require_relative 'ci-bundle-update' 2 | 3 | exec_days = ENV['EXEC_DAYS'] 4 | github_username = ENV['GITHUB_USERNAME'] 5 | branch = ENV['BRANCH'] 6 | extra_build_parameters = ENV['EXTRA_BUILD_PARAMETERS'] 7 | 8 | # $TRIGGERS :: :,:,... 9 | ENV['TRIGGERS'].split(',').each do |trigger| 10 | circleci_token, github_reponame = trigger.split(':') 11 | 12 | puts "GitHub repository is #{github_username}/#{github_reponame}" 13 | 14 | ci_bundle_update = CiBundleUpdate::CircleCi.new(circleci_token, exec_days, extra_build_parameters) 15 | ci_bundle_update.build(github_username, github_reponame, branch) 16 | end 17 | -------------------------------------------------------------------------------- /ci-bundle-update.rb: -------------------------------------------------------------------------------- 1 | require 'circleci' 2 | require 'httparty' 3 | 4 | module CiBundleUpdate 5 | class Base 6 | def initialize(token, exec_days, raw_extra_build_parameters) 7 | @exec_days = exec_days 8 | @raw_extra_build_parameters = raw_extra_build_parameters 9 | post_initialize(token, exec_days) 10 | end 11 | 12 | def build 13 | raise NotImplementedError 14 | end 15 | 16 | private 17 | 18 | attr_reader :exec_days, :raw_extra_build_parameters 19 | 20 | def post_initialize(_token, _exec_days) 21 | nil 22 | end 23 | 24 | def extra_build_parameters 25 | raise NotImplementedError 26 | end 27 | 28 | def skip? 29 | exec_days && 30 | ! exec_days.split(',').include?(Time.now.strftime('%a')) 31 | end 32 | end 33 | 34 | class CircleCi < Base 35 | def build(username, reponame, branch) 36 | if skip? 37 | puts "This build was skipped for $EXEC_DAYS (#{exec_days})" 38 | return 39 | end 40 | 41 | response = ::CircleCi::Project.new(username, reponame).build_branch( 42 | branch, 43 | {}, 44 | build_parameters: { 'BUNDLE_UPDATE' => true }.merge(extra_build_parameters) 45 | ) 46 | 47 | if response.success? 48 | puts "This build was accepted" 49 | else 50 | puts "This build was not accepted for #{response.body}" 51 | end 52 | end 53 | 54 | private 55 | 56 | def post_initialize(token, _exec_days) 57 | ::CircleCi.configure do |config| 58 | config.token = token 59 | end 60 | end 61 | 62 | def extra_build_parameters 63 | @extra_build_parameters ||= 64 | begin 65 | ary = (raw_extra_build_parameters || "") 66 | .split(',') 67 | .map{|e| e.split('=')} 68 | .flatten 69 | Hash[*ary] 70 | end 71 | end 72 | end 73 | 74 | class Wercker < Base 75 | include HTTParty 76 | 77 | base_uri 'https://app.wercker.com/api/v3' 78 | 79 | def build(username, reponame, branch) 80 | if skip? 81 | puts "This build was skipped for $EXEC_DAYS (#{exec_days})" 82 | return 83 | end 84 | 85 | application = get_application(username, reponame) 86 | build_pipeline = get_build_pipeline(application['id'], branch) 87 | raise 'build pipeline not found.' unless build_pipeline 88 | run_build(build_pipeline['id'], branch) 89 | end 90 | 91 | private 92 | 93 | def post_initialize(token, _exec_days) 94 | @headers = { 95 | Authorization: "Bearer #{token}", 96 | 'Content-type': 'application/json', 97 | } 98 | end 99 | 100 | def get_application(username, reponame) 101 | self.class.get("/applications/#{username}/#{reponame}", headers: @headers).parsed_response 102 | end 103 | 104 | def get_build_pipeline(application_id, branch) 105 | query = { 106 | applicationId: application_id, 107 | branch: branch, 108 | } 109 | 110 | runs = self.class.get('/runs', query: query, headers: @headers).parsed_response 111 | run = runs.find { |run| run['pipeline']['name'] == 'build' } 112 | run['pipeline'] if run 113 | end 114 | 115 | def run_build(pipeline_id, branch) 116 | body = { 117 | pipelineId: pipeline_id, 118 | branch: branch, 119 | envVars: [ 120 | { key: 'BUNDLE_UPDATE', value: 'true' }, 121 | *extra_build_parameters 122 | ], 123 | } 124 | 125 | self.class.post('/runs', body: body.to_json, headers: @headers) 126 | end 127 | 128 | def extra_build_parameters 129 | @extra_build_parameters ||= 130 | (raw_extra_build_parameters || "") 131 | .split(',') 132 | .map{|e| e.split('=')} 133 | .map{|k,v| {key: k, value: v}} 134 | end 135 | end 136 | end 137 | 138 | if $0 == __FILE__ 139 | require 'optparse' 140 | options = ARGV.getopts(nil, 'ci:circle_ci') 141 | 142 | case options['ci'] 143 | when 'circle_ci' 144 | ci_bundle_update = CiBundleUpdate::CircleCi.new( 145 | ENV['CIRCLECI_TOKEN'], 146 | ENV['EXEC_DAYS'], 147 | ENV['EXTRA_BUILD_PARAMETERS'] 148 | ) 149 | 150 | when 'wercker' 151 | ci_bundle_update = CiBundleUpdate::Wercker.new( 152 | ENV['WERCKER_TOKEN'], 153 | ENV['EXEC_DAYS'], 154 | ENV['EXTRA_BUILD_PARAMETERS'] 155 | ) 156 | end 157 | 158 | ci_bundle_update.build(ENV['GITHUB_USERNAME'], ENV['GITHUB_REPONAME'], ENV['BRANCH']) 159 | end 160 | -------------------------------------------------------------------------------- /wercker.yml: -------------------------------------------------------------------------------- 1 | box: ruby:2.3.1 2 | build: 3 | steps: 4 | - bundle-install 5 | --------------------------------------------------------------------------------