git-runner 0.0.6 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +102 -17
- data/git-runner.gemspec +1 -1
- data/lib/git-runner/base.rb +33 -21
- data/lib/git-runner/branch.rb +3 -4
- data/lib/git-runner/command.rb +33 -10
- data/lib/git-runner/text.rb +42 -32
- data/lib/git-runner/version.rb +1 -1
- metadata +4 -4
data/README.md
CHANGED
@@ -1,39 +1,124 @@
|
|
1
1
|
# Git Runner
|
2
2
|
|
3
|
-
|
3
|
+
[![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/JamesBrooks/git-runner)
|
4
4
|
|
5
|
-
[Demonstration Video, Using git-runner to perform automatic deploys](http://ascii.io/a/1349)
|
6
5
|
|
7
|
-
|
6
|
+
Git Runner is a ruby framework to create and run tasks after commits are pushed to a git repository.
|
7
|
+
|
8
|
+
It works by having the git server-side post-update hook (`hooks/post-update`) invoke `git-runner`. Git Runner inspects all of the pushed branches (`refs/heads/*`) and looks for any Git Runner tasks (called instructions) to run. Such an instruction is `Deploy`, which allows for the application to be deployed after a push.
|
9
|
+
|
10
|
+
Git Runner instructions are distrubuted as separate gems, see **Available Instructions** below for what instructions are currently available for use.
|
11
|
+
|
12
|
+
Have a look at this short [demonistration video](http://ascii.io/a/1349) for what it looks like for a user pushing to a Git Runner enabled repository (using `git-runner-deploy`).
|
13
|
+
|
14
|
+
|
15
|
+
## Why?
|
16
|
+
|
17
|
+
#### Origins
|
18
|
+
|
19
|
+
Git Runner originated from a need to simply the deployment process (capistrano) within my organisation for people who don't have their environments setup with ruby and the required gems. I wanted to make the process work for even those who are using GUI git clients.
|
20
|
+
|
21
|
+
|
22
|
+
#### Wouldn't a simple script do the job?
|
23
|
+
|
24
|
+
While you certainly could create a ruby script at `hooks/post-update` and have that run after a push with good results, Git Runner provides a robust framework for authoring re-usable tasks that you can share between all of your code repositories and run only when you need to run them.
|
25
|
+
|
26
|
+
You could do it all in a script of your own if you like, but Git Runner is there to help you out and make the process less error-prone and more maintainable.
|
27
|
+
|
28
|
+
|
29
|
+
## How
|
30
|
+
|
31
|
+
After pushing to a git repository various server-side hooks are ran, including a hook named `post-update`. `post-update` needs to run `git-runner` with it's arguments.
|
32
|
+
|
33
|
+
Git Runner looks for pushes to any branches (`refs/heads/*`). For each branch it greps the repository for one or more Git Runner instructions within a instruction file.
|
34
|
+
|
35
|
+
The instruction file and instruction markers are configurable (see **Configuration** below), by default the configuration file is `config/deploy.rb` and Git Runner instructions begin with `# GitRunner:`, e.g.
|
36
|
+
|
37
|
+
```
|
38
|
+
# GitRunner: Deploy
|
39
|
+
... rest of the file ...
|
40
|
+
```
|
41
|
+
|
42
|
+
*Instructions can be on any line within the instruction file and multiple instructions are present (instructions are ran in order).*
|
43
|
+
|
44
|
+
Any instructions that are found within the instruction file are then processed and ran if able, with any messages being displayed to the user currently pushing the repository.
|
45
|
+
|
46
|
+
Any errors encountered will also be displayed with all relevent details being written to a log on the server.
|
47
|
+
|
48
|
+
|
49
|
+
## Features
|
50
|
+
|
51
|
+
* Robust framework for running tasks (instructions) after updates are made to a repository.
|
52
|
+
* Have all of your tasks available to all of your repositories, only use the ones you need on a per repository basis.
|
53
|
+
* Activiation through instructions contained within the repository.
|
54
|
+
* Branch detection, behave differently for different branches if you like.
|
55
|
+
* Simple authoring of additional instructions.
|
56
|
+
* Error handling, notification and logging.
|
57
|
+
|
58
|
+
|
59
|
+
## Available Instructions
|
60
|
+
|
61
|
+
Name | Gem | Description
|
62
|
+
---------------------------------------------------------- | ----------------- | ---------------------------------------
|
63
|
+
[Deploy](https://github.com/JamesBrooks/git-runner-deploy) | git-runner-deploy | Application deployment using capistrano
|
8
64
|
|
9
|
-
Instructions are contained within `lib/git-runner/instructions`. By default the instructions contained here and only used for support purposes, real functionality is abstracted into separate gems (at this time the only real instuction is deploy).
|
10
65
|
|
11
66
|
## Installation
|
12
67
|
|
13
|
-
|
68
|
+
This section needs a lot more fleshing out as installation overly trivial. The main thing to worry about is making sure that `hooks/post-update` in each of your repositories is able to run `git-runner` (and pass it's arguments on).
|
69
|
+
|
70
|
+
|
71
|
+
#### Install the git-runner
|
14
72
|
|
15
|
-
|
73
|
+
Install the gem and any other additional instruction gems that you need, for example if we want Git Runner with capistrano deploy support:
|
16
74
|
|
17
|
-
|
18
|
-
|
75
|
+
```
|
76
|
+
gem install git-runner
|
77
|
+
gem install git-runner-deploy
|
78
|
+
```
|
19
79
|
|
20
|
-
|
80
|
+
#### Hook up git-runner to fire on hooks/post-update
|
21
81
|
|
82
|
+
There are a few ways to accomplish this, such as directly symlinking `hooks/post-update` to the executable path for git-runner. Currently I prefer the following approach of creating a script that loads rubygems and git-runner + calls git runner. The following is the contents of my `hooks/post-update` file:
|
22
83
|
|
23
|
-
|
84
|
+
```
|
85
|
+
#!/usr/bin/env ruby
|
86
|
+
|
87
|
+
require 'rubygems'
|
88
|
+
require 'git-runner'
|
89
|
+
|
90
|
+
GitRunner::Base.new(ARGV).run
|
91
|
+
```
|
24
92
|
|
25
|
-
Symlink `hooks/post-update` to `git-runner`, or if `post-update` is already in use modify it to run `git-runner` with the arguments supplied to the hook.
|
26
93
|
|
27
94
|
## Configuration
|
28
95
|
|
29
|
-
Configuration can be
|
96
|
+
Configuration can be changed through a YAML file at either `/etc/git-runner.yml` or `$HOME/.git-runner.yml`. The default configuration settings are:
|
97
|
+
|
98
|
+
Option | Default Value | Description
|
99
|
+
------------------ | ---------------- | --------------------------------------------------------------------------
|
100
|
+
git_executable | /usr/bin/env git | Location of the git executable to use
|
101
|
+
instruction_file | config/deploy.rb | Where to look for Git Runner instructions within each repository
|
102
|
+
instruction_prefix | # GitRunner: | What Git Runner instructions will be prefixed with in the instruction file
|
103
|
+
tmp_directory | /tmp/git-runner | Working directory for git-runner
|
104
|
+
|
105
|
+
|
106
|
+
## TODOs
|
107
|
+
|
108
|
+
* Support to monitor a command (stdout and stderr) as the command is running, not just at the end.
|
109
|
+
* Instruction file path is globally set, make this overwritable on a per-repository basis?
|
110
|
+
* Instruction prefix is globally set, make this overwritable on a per-repository basis?
|
111
|
+
* Have core functionality fire useful hooks.
|
112
|
+
* Improve the output/text library, it can work better!
|
113
|
+
* Simplify Base#run (CodeClimate)
|
114
|
+
|
115
|
+
|
116
|
+
## Support
|
117
|
+
|
118
|
+
Check out [GitHub Issues](https://github.com/JamesBrooks/git-runner/issues) to see if anyone else has had the same problem you have, or create a new issue.
|
30
119
|
|
31
|
-
|
32
|
-
* **instruction_file** (default: 'config/deploy.rb')
|
33
|
-
* **instruction_prefix** (default: '# GitRunner:')
|
34
|
-
* **tmp_directory** (default: '/tmp/git-runner')
|
120
|
+
Also feel free to contact me directly (james at jamesbrooks dot net) for non-support comments or support of a more sensitive nature.
|
35
121
|
|
36
|
-
## TODO
|
37
122
|
|
38
123
|
## Contributing
|
39
124
|
|
data/git-runner.gemspec
CHANGED
data/lib/git-runner/base.rb
CHANGED
@@ -26,31 +26,13 @@ module GitRunner
|
|
26
26
|
|
27
27
|
|
28
28
|
rescue GitRunner::Instruction::Failure => ex
|
29
|
-
|
30
|
-
Text.out("Stopping runner, no further instructions will be performed\n")
|
31
|
-
Text.new_line
|
29
|
+
handle_instruction_failure_exception(ex)
|
32
30
|
|
33
31
|
rescue GitRunner::Command::Failure => ex
|
34
|
-
|
35
|
-
Text.out(Text.red("\u2716 Command failed: " + Text.red(ex.result.command)), :heading)
|
36
|
-
|
37
|
-
write_error_log do |log|
|
38
|
-
log << Command.history_to_s
|
39
|
-
end
|
40
|
-
|
41
|
-
Text.new_line
|
32
|
+
handle_command_failure_exception(ex)
|
42
33
|
|
43
34
|
rescue Exception => ex
|
44
|
-
|
45
|
-
Text.out(Text.red("\u2716 Unknown exception occured: #{ex}"), :heading)
|
46
|
-
|
47
|
-
write_error_log do |log|
|
48
|
-
log << Command.history_to_s
|
49
|
-
log << ex.message + "\n"
|
50
|
-
log << ex.backtrace.map { |line| " #{line}\n" }.join
|
51
|
-
end
|
52
|
-
|
53
|
-
Text.new_line
|
35
|
+
handle_unknown_exception(ex)
|
54
36
|
|
55
37
|
ensure
|
56
38
|
Text.finish
|
@@ -64,6 +46,36 @@ module GitRunner
|
|
64
46
|
Gem::Specification._all.map(&:name).select { |gem| gem =~ /^git-runner-/ }.each { |name| require(name) }
|
65
47
|
end
|
66
48
|
|
49
|
+
def handle_instruction_failure_exception(ex)
|
50
|
+
Text.new_line
|
51
|
+
Text.out("Stopping runner, no further instructions will be performed\n")
|
52
|
+
Text.new_line
|
53
|
+
end
|
54
|
+
|
55
|
+
def handle_command_failure_exception(ex)
|
56
|
+
Text.new_line
|
57
|
+
Text.out(Text.red("\u2716 Command failed: " + Text.red(ex.result.command)), :heading)
|
58
|
+
|
59
|
+
write_error_log do |log|
|
60
|
+
log << Command.history_to_s
|
61
|
+
end
|
62
|
+
|
63
|
+
Text.new_line
|
64
|
+
end
|
65
|
+
|
66
|
+
def handle_unknown_exception(ex)
|
67
|
+
Text.new_line
|
68
|
+
Text.out(Text.red("\u2716 Unknown exception occured: #{ex}"), :heading)
|
69
|
+
|
70
|
+
write_error_log do |log|
|
71
|
+
log << Command.history_to_s
|
72
|
+
log << ex.message + "\n"
|
73
|
+
log << ex.backtrace.map { |line| " #{line}\n" }.join
|
74
|
+
end
|
75
|
+
|
76
|
+
Text.new_line
|
77
|
+
end
|
78
|
+
|
67
79
|
def write_error_log
|
68
80
|
log_directory = File.join(Configuration.tmp_directory, 'logs')
|
69
81
|
error_log = File.join(log_directory, Time.now.strftime("%Y%m%d%H%M%S") + '-error.log')
|
data/lib/git-runner/branch.rb
CHANGED
@@ -32,10 +32,9 @@ module GitRunner
|
|
32
32
|
|
33
33
|
# Process the output to generate instructions
|
34
34
|
output.split("\n").map do |line|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
instruction
|
35
|
+
Instruction.from_raw(line).tap do |instruction|
|
36
|
+
instruction.branch = self
|
37
|
+
end
|
39
38
|
end
|
40
39
|
end
|
41
40
|
end
|
data/lib/git-runner/command.rb
CHANGED
@@ -6,17 +6,21 @@ module GitRunner
|
|
6
6
|
|
7
7
|
|
8
8
|
def execute(*commands)
|
9
|
-
|
10
|
-
|
9
|
+
# Extract options (if any)
|
10
|
+
opts = commands.last.is_a?(Hash) ? commands.pop : {}
|
11
11
|
|
12
|
-
|
12
|
+
# Set session callback procs
|
13
|
+
session.outproc = opts[:outproc]
|
14
|
+
session.errproc = opts[:errproc]
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
+
# Cycle through and run commands
|
17
|
+
execute_commands(commands)
|
16
18
|
|
17
|
-
|
18
|
-
|
19
|
+
# Clear session callback procs
|
20
|
+
session.outproc = nil
|
21
|
+
session.errproc = nil
|
19
22
|
|
23
|
+
# Return full output of the last ran command (should this be all commands perhaps?)
|
20
24
|
history.last.out
|
21
25
|
end
|
22
26
|
|
@@ -25,13 +29,27 @@ module GitRunner
|
|
25
29
|
end
|
26
30
|
|
27
31
|
def history_to_s
|
28
|
-
history.map
|
29
|
-
"Status: #{result.status}; Command: #{result.command}\n#{result.out}\n--------------------\n"
|
30
|
-
end.join
|
32
|
+
history.map(&:to_s).join("\n#{'-' * 20}\n")
|
31
33
|
end
|
32
34
|
|
33
35
|
|
34
36
|
private
|
37
|
+
def execute_commands(commands)
|
38
|
+
commands.each do |command|
|
39
|
+
out = StringIO::new
|
40
|
+
|
41
|
+
# Run the command through the active shell session
|
42
|
+
session.execute(command, :stdout => out, :stderr => out)
|
43
|
+
|
44
|
+
# Construct result and store is as part of the command history
|
45
|
+
result = Result.new(command, out.string, session.exit_status)
|
46
|
+
history << result
|
47
|
+
|
48
|
+
# Bubble up a failure exception if the command failed
|
49
|
+
raise Failure.new(result) if result.failure?
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
35
53
|
def session
|
36
54
|
@session ||= Session::Bash::Login.new
|
37
55
|
end
|
@@ -57,8 +75,13 @@ module GitRunner
|
|
57
75
|
def failure?
|
58
76
|
!success?
|
59
77
|
end
|
78
|
+
|
79
|
+
def to_s
|
80
|
+
"Status: #{status}; Command: #{command}\n#{out}"
|
81
|
+
end
|
60
82
|
end
|
61
83
|
|
84
|
+
|
62
85
|
class Failure < StandardError
|
63
86
|
attr_accessor :result
|
64
87
|
|
data/lib/git-runner/text.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
module GitRunner
|
2
|
-
|
2
|
+
module Text
|
3
|
+
extend self
|
4
|
+
|
3
5
|
COLOR_START = "\033["
|
4
6
|
COLOR_END = "m"
|
5
7
|
COLOR_RESET = "#{COLOR_START}0#{COLOR_END}"
|
@@ -22,45 +24,53 @@ module GitRunner
|
|
22
24
|
}
|
23
25
|
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
27
|
+
def begin
|
28
|
+
STDOUT.sync = true
|
29
|
+
print("\e[1G \e[1G")
|
30
|
+
end
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
def finish
|
33
|
+
print("\n")
|
34
|
+
end
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
36
|
+
def out(str, style=nil)
|
37
|
+
# Ensure that new lines overwrite the default 'remote: ' text
|
38
|
+
str = str.gsub("\n", "\n\e[1G#{padding(nil)}")
|
38
39
|
|
39
|
-
|
40
|
-
|
40
|
+
print "\n\e[1G#{padding(style).ljust(7 + (@indentation || 0))}#{str}"
|
41
|
+
end
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
43
|
+
def new_line
|
44
|
+
out('')
|
45
|
+
end
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
def #{color}(str, style=:normal)
|
50
|
-
"#{COLOR_START}\#{STYLES[style]};#{code}#{COLOR_END}\#{str}#{COLOR_RESET}"
|
51
|
-
end
|
52
|
-
EOF
|
53
|
-
end
|
47
|
+
def indent(spaces=2)
|
48
|
+
@indentation ||= 0
|
49
|
+
@indentation += spaces
|
54
50
|
|
51
|
+
yield
|
52
|
+
|
53
|
+
@indentation -= spaces
|
54
|
+
Text.new_line
|
55
|
+
end
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
else
|
62
|
-
''
|
57
|
+
# Color methods
|
58
|
+
COLORS.each do |color, code|
|
59
|
+
class_eval <<-EOF
|
60
|
+
def #{color}(str, style=:normal)
|
61
|
+
"#{COLOR_START}\#{STYLES[style]};#{code}#{COLOR_END}\#{str}#{COLOR_RESET}"
|
63
62
|
end
|
63
|
+
EOF
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
private
|
68
|
+
def padding(style)
|
69
|
+
case style
|
70
|
+
when :heading
|
71
|
+
'----->'
|
72
|
+
else
|
73
|
+
''
|
64
74
|
end
|
65
75
|
end
|
66
76
|
end
|
data/lib/git-runner/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: git-runner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: session
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
21
|
+
version: 3.1.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
29
|
+
version: 3.1.0
|
30
30
|
description: GitRunner is a ruby framework to implement and run tasks after code has
|
31
31
|
been pushed to a Git repository. It works by invoking `git-runner` through `hooks/post-update`
|
32
32
|
in your remote Git repository.
|