├── CONTRIBUTING.markdown ├── LICENSE ├── README.markdown └── init.rb /CONTRIBUTING.markdown: -------------------------------------------------------------------------------- 1 | [Don't screw up the commit message.][1] It's all I ask. 2 | 3 | [1]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Tim Pope 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Heroku wildcards 2 | 3 | > Charlie: You're not letting the wild card do his thing. 4 | > Dennis: Is there any reason behind what you're doing? 5 | > Charlie: Wild card. 6 | > 7 | > — *It's Always Sunny in Philadelphia*. 8 | 9 | Run a command across multiple apps by including `*` in the app name. 10 | 11 | $ heroku ps --app=myapp-* 12 | # myapp-staging 13 | === web: `bundle exec rails server thin -p $PORT` 14 | web.1: up 2013/03/02 19:40:05 (~ 1h ago) 15 | 16 | # myapp-production 17 | === web: `bundle exec rails server thin -p $PORT` 18 | web.1: up 2013/03/02 11:53:30 (~ 9h ago) 19 | web.2: up 2013/03/02 11:56:05 (~ 9h ago) 20 | 21 | You can also use commas for more precise specification: 22 | 23 | $ heroku maintenance:on -a thing1,thing2 24 | 25 | Or match against the Git remote name: 26 | 27 | $ heroku config:set -r* BUILDPACK_URL=https://github.com/tpope/heroku-buildpack-ruby-tpope 28 | 29 | Try it with the [Heroku binstubs](https://github.com/tpope/heroku-binstubs) 30 | plugin: 31 | 32 | $ heroku binstubs:create 'myapp-*' --as each-env 33 | 34 | ## Installation 35 | 36 | cd ~/.heroku/plugins 37 | git clone https://github.com/tpope/heroku-wildcards.git 38 | 39 | Requires a version of the Heroku CLI with legacy Ruby support. 40 | 41 | ## Bonus feature 42 | 43 | $ heroku --app myapp run console 44 | ! `--app` is not a heroku command. 45 | ! Perhaps you meant `--help` or `apps`. 46 | ! See `heroku help` for a list of available commands. 47 | 48 | Don't you just hate that? Well, since I was already monkeying with the 49 | dispatcher, I went ahead and fixed it. 50 | 51 | ## License 52 | 53 | Copyright © Tim Pope. MIT License. See LICENSE for details. 54 | -------------------------------------------------------------------------------- /init.rb: -------------------------------------------------------------------------------- 1 | require 'heroku/command' 2 | 3 | class << Heroku::Command 4 | 5 | alias boring_old_wildcard_free_run run 6 | def run(cmd, original_args=[]) 7 | if cmd =~ /^-([ar]|-app|-remote)$/ 8 | original_args.unshift(cmd) 9 | cmd = original_args.delete_at(2) || 'help' 10 | elsif cmd =~ /^-/ 11 | original_args.unshift(cmd) 12 | cmd = original_args.delete_at(1) || 'help' 13 | end 14 | 15 | option = '--app' 16 | pattern = ENV['HEROKU_APP'] 17 | args = original_args.dup 18 | args.each_with_index do |arg, i| 19 | case arg 20 | when '--' 21 | break 22 | when /^-(?:a|-app)$/ 23 | pattern = args.delete_at(i+1) 24 | args.delete_at(i) 25 | break 26 | when /^-(?:r|-remote)$/ 27 | pattern = args.delete_at(i+1) 28 | args.delete_at(i) 29 | option = '--remote' 30 | break 31 | when /^-(?:a|-app=)(.*)$/ 32 | pattern = $1 33 | args.delete_at(i) 34 | break 35 | when /^-(?:r|-remote=)(.*)$/ 36 | pattern = $1 37 | args.delete_at(i) 38 | option = '--remote' 39 | break 40 | end 41 | end 42 | 43 | if !pattern 44 | option = '--remote' 45 | pattern = git("config heroku.remote")[/.+/] 46 | end 47 | 48 | if pattern.to_s.include?('*') || pattern.to_s.include?(',') 49 | found = false 50 | if option == '--remote' 51 | Heroku::Command::Base.allocate.send(:git_remotes).to_a 52 | else 53 | Heroku::Auth.api.get_apps.body.map { |a| [a['name'], a['name']] } 54 | end.each do |candidate, app| 55 | if pattern.split(',').any? { |glob| File.fnmatch?(glob, candidate) } 56 | found = true 57 | if $stdout.tty? && ENV['TERM'] != 'dumb' 58 | display("\e[01m# #{app}\e[00m") 59 | else 60 | display("# #{app}") 61 | end 62 | system($0, cmd, option, candidate, *args) 63 | end 64 | end 65 | unless found 66 | error("You do not have access to any apps matching #{pattern}.") 67 | end 68 | else 69 | boring_old_wildcard_free_run(cmd, original_args) 70 | end 71 | end 72 | 73 | end 74 | --------------------------------------------------------------------------------