tinyci 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5531654099be53cbad1500af1c180555e4453396
4
- data.tar.gz: 4f90146f6f2aaf50b78fa162a363a8d80666f810
3
+ metadata.gz: 39e61578a53b2ca58444388af0f0b1b3653c2896
4
+ data.tar.gz: 86be8e7dbf6d742a8814323ccf75d5c1ce645c22
5
5
  SHA512:
6
- metadata.gz: 697dbb6e5e32e9bede86917e1466093180c87a0a327946ffcc12fab7fcc7c06aad91be64d11004cccef9f127a96dd892bdfbaf1783dce2ca233eb5b779efd355
7
- data.tar.gz: 48097b1dc7213415c2d462dc055beb50ab77b6467f71f488dd12e34870ec59f7e2ce4abb41e00d5a135b2c8a0eafff37b69221c409c39aef2058448c67f9d17b
6
+ metadata.gz: 864c7040005a7a6f778bb5392c580847e35024e160150063148d52a0ddcf059b5ab0f5f56f756efc8907eb16a74c0aea071585b1a399413dde3611a83dca92e0
7
+ data.tar.gz: b84f48399d21f174c485c2b3626fb35ca3b05d89f0b5547e06388848caaa5b2672e1c55ac8bdd4adf73ea291e710af44f3bfb03894289a651b002e34839a956d
data/.tinyci.yml ADDED
@@ -0,0 +1,8 @@
1
+ builder:
2
+ class: ScriptBuilder
3
+ config:
4
+ command: docker build -t tinyci .
5
+ tester:
6
+ class: ScriptTester
7
+ config:
8
+ command: docker run tinyci bundle exec rspec --format documentation
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ 0.3.0 - October 18, 2018
2
+ Add compactor
3
+ Fixes to hooks
1
4
  0.2.0 - October 13, 2018
2
5
  Add hooks
3
6
  0.1.2 - August 16, 2018
data/Dockerfile ADDED
@@ -0,0 +1,38 @@
1
+ FROM alpine:3.8
2
+
3
+ RUN mkdir -p /etc \
4
+ && { \
5
+ echo 'install: --no-document'; \
6
+ echo 'update: --no-document'; \
7
+ } >> /etc/gemrc
8
+
9
+ RUN apk add --no-cache -u \
10
+ ruby \
11
+ ruby-dev \
12
+ ruby-irb \
13
+ ruby-etc \
14
+ libffi-dev \
15
+ build-base \
16
+ git
17
+
18
+ RUN git config --global user.email "you@example.com"
19
+ RUN git config --global user.name "Your Name"
20
+
21
+ # RUN ln -sf /usr/share/zoneinfo/Europe/London /etc/localtime
22
+
23
+ RUN gem install bundler
24
+ RUN bundle config --global silence_root_warning 1
25
+
26
+ WORKDIR /tmp
27
+ ADD Gemfile Gemfile
28
+ ADD Gemfile.lock Gemfile.lock
29
+ ADD tinyci.gemspec tinyci.gemspec
30
+ ADD lib/tinyci/version.rb lib/tinyci/version.rb
31
+ ADD lib/tinyci/logo.txt lib/tinyci/logo.txt
32
+ RUN bundle install
33
+
34
+ ADD . /tinyci
35
+
36
+ WORKDIR /tinyci
37
+
38
+ CMD bin/tinyci
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- tinyci (0.2.0)
4
+ tinyci (0.3.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -107,6 +107,19 @@ hooker:
107
107
  after_build: ./after_build.sh
108
108
  ```
109
109
 
110
+ #### Compactor
111
+
112
+ With continued use, the `builds` directory will grow ever larger. TinyCI provides the `compact` command to deal with this. It compresses old builds into `.tar.gz` files.
113
+
114
+ "Old" in this context is defined using two options to the `tinyci compact` command:
115
+
116
+ * `--num-builds-to-leave` - How many build directories to leave in place, starting from the newest. Defaults to `1`.
117
+ * `--builds-to-leave` - A comma-separated list of specific build directories to leave in place.
118
+
119
+ The latter option is intended for use in an automated deployment system, to allow the script to run without removing builds that are being used somewhere else in the system. For a demonstration of this, see the [example project](#Example_Project).
120
+
121
+ To use it, simply run `tinyci compact` from the root of the repo you wish to compact.
122
+
110
123
  #### Logging/Output
111
124
 
112
125
  TinyCI is executed in a `post-update` git hook. As such, the output is shown to the user as part of the local call to `git push`. Once the TinyCI hook is running, the local git process can be freely killed if the user does not wish to watch the output - this will not affect the remote execution of TinyCI.
@@ -123,8 +136,6 @@ Instead, this second TinyCI execution should begin tailing the output of the fir
123
136
 
124
137
  * It would be desirable to add a command to the TinyCI binary to SSH into the remote server and tail the the log output of a currently running TinyCI process, enabling functionality similar to that described in above, but without making a new commit.
125
138
 
126
- * The exported copies of each build are left on the disk forever. This will obviously eat disk space. One could handle deleting/compressing them with a cronjob, however it would be desirable to integrate this functionality into TinyCI and to automate it.
127
-
128
139
  * More configuration options should be added, eg. specification of the export path.
129
140
 
130
141
  * In general, more local functionality for the TinyCI binary would be desirable, some way to retrieve the results of tests and query them from the local clone for example, or some way to show them in `git log` output.
@@ -160,85 +171,9 @@ Now, commit the configuration file and push it to your remote repository. As dis
160
171
 
161
172
  #### Example Project
162
173
 
163
- Here we will demonstrate cloning the [tinyci-example](https://github.com/JonnieCache/tinyci-example) project, creating a bare clone of it to simulate our server where the tests will run, and pushing a commit to see TinyCI in action.
164
-
165
- The example project has very simple build and test scripts written in bash.
166
-
167
- First, create a directory to store both clones:
168
-
169
- $ mkdir tinyci-test
170
- $ cd tinyci-test
171
-
172
- Clone the example project from github:
173
-
174
- $ git clone https://github.com/JonnieCache/tinyci-example.git
175
-
176
- Cloning into 'tinyci-example'...
177
- remote: Counting objects: 8, done.
178
- remote: Compressing objects: 100% (6/6), done.
179
- remote: Total 8 (delta 0), reused 8 (delta 0), pack-reused 0
180
- Unpacking objects: 100% (8/8), done.
181
-
182
- Clone it again into a bare repository:
183
-
184
- $ git clone --bare tinyci-example tinyci-example-bare
185
-
186
- Cloning into bare repository 'tinyci-example-bare'...
187
- done.
188
-
189
- Install tinyci:
190
-
191
- $ gem install tinyci
192
-
193
- Install the tinyci hook into our bare clone:
194
-
195
- $ cd tinyci-example-bare
196
- $ tinyci install
197
-
198
- [09:48:42] tinyci post-update hook installed sucessfully
199
-
200
- Go into our initial clone and make a change:
201
-
202
- $ cd ../tinyci-example
203
- $ echo "foo" > bar
204
- $ git add bar
205
- $ git commit -m 'foobar'
206
-
207
- [master cebb4ec] foobar
208
- 1 file changed, 1 insertion(+)
209
- create mode 100644 bar
210
-
211
- Add our bare repo as a remote:
212
-
213
- $ git remote add test ../tinyci-example-bare
214
-
215
- Push the commit and watch tinyci in action:
216
-
217
- $ git push test master
218
-
219
- Counting objects: 3, done.
220
- Delta compression using up to 4 threads.
221
- Compressing objects: 100% (2/2), done.
222
- Writing objects: 100% (3/3), 268 bytes | 0 bytes/s, done.
223
- Total 3 (delta 1), reused 0 (delta 0)
224
- remote: [09:49:53] Commit: 22c36d0c1213361d06b385d2b55648985347e1f4
225
- remote: [09:49:53] Cleaning...
226
- remote: [09:49:53] Exporting...
227
- remote: [09:49:53] Building...
228
- remote: [09:49:53] Testing...
229
- remote: [09:49:53] foo bar
230
- remote: [09:49:53] Finished 22c36d0c1213361d06b385d2b55648985347e1f4
231
- remote: [09:49:53] Commit: cebb4ec18b89f093c7cdeb909c2c340708052575
232
- remote: [09:49:53] Cleaning...
233
- remote: [09:49:53] Exporting...
234
- remote: [09:49:53] Building...
235
- remote: [09:49:53] Testing...
236
- remote: [09:49:53] foo bar
237
- remote: [09:49:53] Finished cebb4ec18b89f093c7cdeb909c2c340708052575
238
- To ../tinyci-example-bare
239
- 22c36d0..cebb4ec master -> master
174
+ There is an example project available at https://github.com/JonnieCache/tinyci-example.
240
175
 
241
- Here we are seeing TinyCI testing both the initial commit that is present in the github repo, an then the new commit that we just made. Breaking the test to see the failure output is left as an exercise for the reader.
176
+ See that repo for a walkthrough demonstrating various TinyCI features.
242
177
 
243
178
  ### Contributing
244
179
 
data/lib/tinyci/cli.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  require 'tinyci/version'
2
2
  require 'tinyci/scheduler'
3
3
  require 'tinyci/installer'
4
+ require 'tinyci/compactor'
4
5
  require 'tinyci/git_utils'
5
6
  require 'optparse'
7
+ require 'pidfile'
6
8
 
7
9
  module TinyCI
8
10
  # Defines the CLI interface. Uses OptionParser.
@@ -29,6 +31,12 @@ module TinyCI
29
31
  'install' => OptionParser.new do |o|
30
32
  o.banner = "Usage: install [options]"
31
33
  o.on("-q", "--[no-]quiet", "quietly run") {|v| opts[:quiet] = v}
34
+ end,
35
+ 'compact' => OptionParser.new do |o|
36
+ o.banner = "Usage: compact [options]"
37
+ o.on("-n", "--num-builds-to-leave <NUM>", "number of builds to leave in place, starting from the most recent") {|n| opts[:num_builds_to_leave] = n}
38
+ o.on("-b", "--builds-to-leave <BUILDS>", "specific build directories to leave in place, comma-separated") {|b| opts[:builds_to_leave] = b.split(',')}
39
+ o.on("-q", "--[no-]quiet", "quietly run") {|v| opts[:quiet] = v}
32
40
  end
33
41
  }
34
42
 
@@ -40,6 +48,7 @@ Global options:
40
48
  Available commands:
41
49
  run build and test the repo
42
50
  install install the git hook into the current repository
51
+ compact compress old build artifacts
43
52
  version print the TinyCI version number
44
53
  TXT
45
54
  if argv[0] == '--help'
@@ -95,6 +104,12 @@ TXT
95
104
  TinyCI::Installer.new(logger: logger, working_dir: opts[:dir]).write!
96
105
  end
97
106
 
107
+ def self.do_compact(opts)
108
+ logger = MultiLogger.new(quiet: opts[:quiet])
109
+
110
+ TinyCI::Compactor.new(logger: logger, working_dir: opts[:dir], num_builds_to_leave: opts[:num_builds_to_leave], builds_to_leave: opts[:builds_to_leave]).compact!
111
+ end
112
+
98
113
  def do_version(opts)
99
114
  puts TinyCI::VERSION
100
115
 
@@ -0,0 +1,99 @@
1
+ require 'fileutils'
2
+ require 'tinyci/git_utils'
3
+ require 'zlib'
4
+ require 'rubygems/package'
5
+ require 'find'
6
+
7
+ module TinyCI
8
+
9
+ # Tool for compressing old builds into .tar.gz files
10
+ class Compactor
11
+ include GitUtils
12
+ include Subprocesses
13
+
14
+ BLOCKSIZE_TO_READ = 1024 * 1000
15
+
16
+ # Constructor
17
+ #
18
+ # @param [String] working_dir The directory from which to run.
19
+ # @param [Integer] num_builds_to_leave How many builds not to compact, starting from the newest
20
+ # @param [String] builds_to_leave Comma-separated list of build directory names not to compact
21
+ # @param [Logger] logger Logger object
22
+ def initialize(working_dir: nil, num_builds_to_leave: nil, builds_to_leave: nil, logger: nil)
23
+ @logger = logger
24
+ @working_dir = working_dir || repo_root
25
+ @num_builds_to_leave = (num_builds_to_leave || 1).to_i
26
+ @builds_to_leave = builds_to_leave || []
27
+ end
28
+
29
+ # Compress and delete the build directories
30
+ def compact!
31
+ unless inside_repository?
32
+ log_error "not currently in a git repository"
33
+ return false
34
+ end
35
+
36
+ directories_to_compact.each do |dir|
37
+ compress_directory dir
38
+ FileUtils.rm_rf builds_dir(dir)
39
+
40
+ log_info "Compacted #{archive_path(dir)}"
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ # Build the list of directories to compact according to the options
47
+ def directories_to_compact
48
+ builds = Dir.entries builds_dir
49
+ builds.select! {|e| File.directory? builds_dir(e) }
50
+ builds.reject! {|e| %w{. ..}.include? e }
51
+ builds.sort!
52
+
53
+ builds = builds[0..-(@num_builds_to_leave+1)]
54
+ builds.reject! {|e| @builds_to_leave.include?(e) || @builds_to_leave.include?(builds_dir(e, 'export'))}
55
+
56
+ builds
57
+ end
58
+
59
+ # Get the location of the builds directory
60
+ def builds_dir(*path_segments)
61
+ File.join @working_dir, 'builds/', *path_segments
62
+ end
63
+
64
+ # Build the path for a compressed archive
65
+ def archive_path(dir)
66
+ File.join(builds_dir, dir+".tar.gz")
67
+ end
68
+
69
+ # Create a .tar.gz file from a directory
70
+ # Done in pure ruby to ensure portability
71
+ def compress_directory(dir)
72
+ File.open archive_path(dir), 'wb' do |oarchive_path|
73
+ Zlib::GzipWriter.wrap oarchive_path do |gz|
74
+ Gem::Package::TarWriter.new gz do |tar|
75
+ Find.find "#{builds_dir}/"+dir do |f|
76
+ relative_path = f.sub "#{builds_dir}/", ""
77
+ mode = File.stat(f).mode
78
+ size = File.stat(f).size
79
+
80
+ if File.directory? f
81
+ tar.mkdir relative_path, mode
82
+ else
83
+ tar.add_file_simple relative_path, mode, size do |tio|
84
+ File.open f, 'rb' do |rio|
85
+ while buffer = rio.read(BLOCKSIZE_TO_READ)
86
+ tio.write buffer
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ end
98
+ end
99
+ end
data/lib/tinyci/runner.rb CHANGED
@@ -83,7 +83,7 @@ module TinyCI
83
83
  raise e if ENV['TINYCI_ENV'] == 'test'
84
84
 
85
85
  log_error e
86
- log_error e.backtrace
86
+ log_debug e.backtrace
87
87
 
88
88
  return false
89
89
  ensure
@@ -101,7 +101,7 @@ module TinyCI
101
101
  raise e if ENV['TINYCI_ENV'] == 'test'
102
102
 
103
103
  log_error e
104
- log_error e.backtrace
104
+ log_debug e.backtrace
105
105
 
106
106
  return false
107
107
  ensure
@@ -116,7 +116,7 @@ module TinyCI
116
116
  raise e if ENV['TINYCI_ENV'] == 'test'
117
117
 
118
118
  log_error e
119
- log_error e.backtrace
119
+ log_debug e.backtrace
120
120
  return false
121
121
  end
122
122
 
@@ -182,10 +182,12 @@ module TinyCI
182
182
  Time.at execute(git_cmd('show', '-s', '--format=%ct', @commit)).to_i
183
183
  end
184
184
 
185
+ # Ensure a path exists
185
186
  def ensure_path(path)
186
187
  execute 'mkdir', '-p', path
187
188
  end
188
189
 
190
+ # Delete the export path
189
191
  def clean
190
192
  FileUtils.rm_rf export_path
191
193
  end
@@ -43,7 +43,7 @@ module TinyCI
43
43
  pid = PidFile.new(pidfile: 'tinyci.pid', piddir: @working_dir)
44
44
 
45
45
  result = if @commit
46
- run_commit @commit
46
+ run_commit get_commit @commit
47
47
  else
48
48
  run_all_commits
49
49
  end
@@ -60,16 +60,15 @@ module TinyCI
60
60
  # @return [Array<String>] the sha1 hashes in reverse order of creation time
61
61
  def get_commits
62
62
  log = execute(git_cmd('log', '--notes=tinyci*', '--format=%H %ct %N§§§', '--reverse'))
63
-
64
63
  lines = log.split("§§§")
65
- lines.map do |line|
66
- parts = line.split(' ')
67
- {
68
- sha: parts[0],
69
- time: parts[1],
70
- result: parts[2]
71
- }
72
- end.select {|c| c[:result].nil?}
64
+
65
+ lines.map {|l| format_commit_data(l)}.select {|c| c[:result].nil?}
66
+ end
67
+
68
+ def get_commit(sha)
69
+ data = execute(git_cmd('show', '--quiet', '--notes=tinyci*', "--format=%H %ct", sha))
70
+
71
+ format_commit_data(data)
73
72
  end
74
73
 
75
74
  # Instantiates {Runner} for a given git object, runs it, and stores the result
@@ -84,6 +83,15 @@ module TinyCI
84
83
  set_result(commit, result)
85
84
  end
86
85
 
86
+ def format_commit_data(data)
87
+ parts = data.split(' ')
88
+ {
89
+ sha: parts[0],
90
+ time: parts[1],
91
+ result: parts[2]
92
+ }
93
+ end
94
+
87
95
  # Repeatedly gets the list of eligable commits and runs TinyCI against them until there are no more remaining
88
96
  def run_all_commits
89
97
  commits = get_commits
@@ -21,7 +21,7 @@ module TinyCI
21
21
 
22
22
  unless status.success?
23
23
  log_error output
24
- raise SubprocessError.new(label, command.join(' '), status.to_i)
24
+ raise SubprocessError.new(label, command.join(' '), status)
25
25
  end
26
26
 
27
27
  output.chomp
@@ -43,7 +43,7 @@ module TinyCI
43
43
  status = waiter.value
44
44
  unless status.success?
45
45
  log_error output
46
- raise SubprocessError.new(label, commands[i].join(' '), status.to_i)
46
+ raise SubprocessError.new(label, commands[i].join(' '), status)
47
47
  end
48
48
  end
49
49
 
@@ -1,3 +1,3 @@
1
1
  module TinyCI
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tinyci
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Davies
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-13 00:00:00.000000000 Z
11
+ date: 2018-10-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -233,8 +233,10 @@ files:
233
233
  - ".rspec"
234
234
  - ".rubocop.yml"
235
235
  - ".ruby-version"
236
+ - ".tinyci.yml"
236
237
  - ".yardopts"
237
238
  - CHANGELOG.md
239
+ - Dockerfile
238
240
  - Gemfile
239
241
  - Gemfile.lock
240
242
  - Guardfile
@@ -247,6 +249,7 @@ files:
247
249
  - lib/tinyci/builders/script_builder.rb
248
250
  - lib/tinyci/builders/test_builder.rb
249
251
  - lib/tinyci/cli.rb
252
+ - lib/tinyci/compactor.rb
250
253
  - lib/tinyci/config.rb
251
254
  - lib/tinyci/executor.rb
252
255
  - lib/tinyci/git_utils.rb
@@ -271,7 +274,7 @@ metadata:
271
274
  allowed_push_host: https://rubygems.org
272
275
  post_install_message: " _____ _ _____ _____\n/__ (_)_ __ _ _ /
273
276
  ___/ /_ _/\n | || | '_ \\| | | |/ / / /\n | || | | | | |_| / /___/\\/ /_
274
- \ \n |_||_|_| |_|\\__, \\____/\\____/ 0.2.0\n |___/\n\n"
277
+ \ \n |_||_|_| |_|\\__, \\____/\\____/ 0.3.0\n |___/\n\n"
275
278
  rdoc_options: []
276
279
  require_paths:
277
280
  - lib