samus 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 500fa4456778f282bf501ea9d1731a5199f0a2bd
4
- data.tar.gz: 1bfac1ac68d3be949d286dacdec5ef710609c2a8
3
+ metadata.gz: 2d0e11cb6836e13b5e668f722bd179d46b26ee3d
4
+ data.tar.gz: 33e0c0b7778b5e70b25425520f81ee268c02951e
5
5
  SHA512:
6
- metadata.gz: bb354e91c9058f483c8a339ffc9b0f331b152e92a548dd6516c86bd2a56e3caa308dcbad3d287f5cd4ffa2ebb423c438ee48929e8660ab60afb2174810532be2
7
- data.tar.gz: 21d5e9b38e12c614416c75eff044a8c94b49900f913a3e1e2635d6f86c6dcf6f50dd34ca6a3602700e2897a0c8373d967857e78f09048720dccc2118570d4617
6
+ metadata.gz: 7ddd01675f4c353aae8adcd31466dc74bb15d9df3c02e9db9be84f37895dd5672f84c32489b442a55a0afc40c55b5a2e89c61a3f13f7bec0990ac0a9d9fcc6b8
7
+ data.tar.gz: 11d1f94c34594257b77689ec82a21127921f88382c1d0f91176b4fe19f9758c1e131748f5202eb464bc073bdd4e73f511bb8fb39a23e8d7906d4971ba7f5b966
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Samus
1
+ # Samus <a href="http://badge.fury.io/rb/samus"><img src="https://badge.fury.io/rb/samus@2x.png" alt="Gem Version" height="18"></a> [![Code Climate](https://codeclimate.com/github/lsegal/samus.png)](https://codeclimate.com/github/lsegal/samus)
2
2
 
3
3
  Samus helps you automate the release of Open Source Software. Samus works
4
4
  through a manifest file to describe discrete steps that you typically perform
@@ -13,6 +13,14 @@ your code. That's right, Samus has a mechanism to share publishing credentials
13
13
  in a fairly secure way, so you can reliably publish releases from almost any
14
14
  machine.
15
15
 
16
+ ## Installing
17
+
18
+ Samus is a RubyGem and requires Ruby 1.9.x+. Installing is as easy as typing:
19
+
20
+ ```sh
21
+ $ gem install samus
22
+ ```
23
+
16
24
  ## Usage
17
25
 
18
26
  Samus is driven by a manifest file that describes the steps to perform when
@@ -22,9 +30,9 @@ can use it for both, it's your choice.
22
30
  ### Publishing
23
31
 
24
32
  If you can handle building all of your assets on your own, you can use Samus
25
- just to publish your code. Create a manifest file called manifest.json and
26
- put it in a directory with all of your assets. The manifest file is just a
27
- list of discrete actions like so (minus comments):
33
+ just to publish your code. Create a manifest file called `manifest.json` (it
34
+ must be named this way) and put it in a directory with all of your assets. The
35
+ manifest file is just a list of discrete actions like so (minus comments):
28
36
 
29
37
  ```js
30
38
  {
@@ -204,10 +212,11 @@ The above command creates:
204
212
 
205
213
  ### Commands
206
214
 
207
- Commands in Samus are just shell scripts. Samus passes all argument values
208
- (the keys from the "arguments" section of the manifest) in as environment
209
- variables with a prefixed underscore. For example, the `rake-task` command
210
- is just:
215
+ Commands in Samus are just shell scripts which execute from the workspace
216
+ or release directory (unless overridden by the build manifest). Samus passes
217
+ all argument values (the keys from the "arguments" section of the manifest) in
218
+ as environment variables with a prefixed underscore. For example, the
219
+ `rake-task` command is just:
211
220
 
212
221
  ```sh
213
222
  #!/bin/sh
@@ -217,6 +226,58 @@ rake $_task
217
226
 
218
227
  The `$_task` variable is the "task" argument from the manifest.
219
228
 
229
+ Note that commands must be executable (`chmod +x`) and have proper shebang
230
+ lines or they will not function.
231
+
232
+ #### Stages
233
+
234
+ Commands either live in the build/ or publish/ sub-directories under the
235
+ commands directory depending on whether they are for `samus build` or
236
+ `samus publish`. These are considered the respective "stages".
237
+
238
+ #### Special Variables
239
+
240
+ In addition to exposing arguments as underscored environment variables,
241
+ Samus also exposes a few special variables with double underscore prefixes:
242
+
243
+ * `__build_dir` - this variable refers to the temporary directory that the
244
+ release package is being built inside of. The files inside of this directory,
245
+ and *only* the files inside of this directory, will be built into the release
246
+ archive. If you write a build-time command that produces an output file which
247
+ is part of the release, you should make sure to move it into this directory.
248
+ * `__restore_file` - the restore file is a newline delimited file containing
249
+ branches and their original ref. All branches listed in this file will be
250
+ restored to the respective ref at the end of `samus build` regardless of
251
+ success status. If you make destructive modifications to existing branches
252
+ in the workspace repository, you should add the original ref for the branch
253
+ to this file.
254
+ * `__creds_*` - provides key, secret, and other values loaded from credentials.
255
+ See Credentials section for more information on how these are set.
256
+
257
+ #### Help Files
258
+
259
+ In order to integrate with `samus show-cmd <stage> <command>` syntax, your
260
+ command should include a file named `your-command.help.md` in the same directory
261
+ as the command script itself. These files are Markdown-formatted files and
262
+ should follow the same structure of the built-in command help files:
263
+
264
+ ```
265
+ Short description of command.
266
+
267
+ * Files:
268
+ * Description of what the command line arguments are
269
+
270
+ * Arguments:
271
+ * argname: Documentation for argument
272
+ ```
273
+
274
+ Notes:
275
+
276
+ * The first line of the help file is used as the summary in the `show-cmd`
277
+ listing.
278
+ * Never omit a section. If a command has no files or arguments, use "(none)"
279
+ as the list item text.
280
+
220
281
  ### Credentials
221
282
 
222
283
  Custom credentials are just flat files or executables in the `credentials/`
@@ -244,6 +305,110 @@ These values are read in by Samus and get exposed as `$__creds_key` and
244
305
  metadata as well, which would be included as `$__creds_name` (for the
245
306
  line "NAME: value").
246
307
 
308
+ ## Manifest File Format
309
+
310
+ The following section defines the manifest formats for the samus.json build
311
+ manifest as well as the manifest.json stored in release packages.
312
+
313
+ ### Base Format
314
+
315
+ The base format is defined as follows:
316
+
317
+ ```js
318
+ {
319
+ "actions": [
320
+ {
321
+ "action": "COMMAND_NAME", // [required] command name to execute
322
+ "files": ["file1", ...], // optional list of files
323
+ "arguments": { // optional map of arguments to pass to cmd
324
+ "key": "value", // each key is passed in as _key in ENV
325
+ // ... (optional) more keys ...
326
+ },
327
+ "pwd": "path" // optional path to execute command from
328
+ "credentials": "KEY", // optional credentials to load for cmd
329
+ },
330
+ // ... (optional) more action items ...
331
+ ]
332
+ }
333
+ ```
334
+
335
+ All manifests include a list of "actions", known individually as action items.
336
+ Each action item has a single required property, "action", which is the command
337
+ to execute for the action (found in `samus show-cmd`). An optional list of
338
+ files are passed into the command as command line arguments, and the "arguments"
339
+ property is a map of keys to values passed in as environment variables with a
340
+ "\_" prefix (key "foo" is set as environment variable "_foo"). Optional
341
+ credentials are loaded from the credentials directory.
342
+
343
+ ### Build Manifest Format
344
+
345
+ The build manifest format is similar to the above but allows for two extra keys
346
+ in each action item called "publish" and "condition".
347
+
348
+ #### "publish" Property
349
+
350
+ The "publish" property should contain the action item that is added to the
351
+ final manifest.json built into the release package if the action item is
352
+ evaluated (condition matches and command successfully executes). If a "files"
353
+ property is set on the parent action item, that property is copied into the
354
+ publish action by default, but it can be overridden.
355
+
356
+ Here is an example build manifest showing the added use of the "publish"
357
+ property:
358
+
359
+ ```js
360
+ {
361
+ "actions": [
362
+ {
363
+ "action": "readme-update",
364
+ "files": ["README.txt"],
365
+ "publish": {
366
+ "action": "readme-publish"
367
+ "arguments": {
368
+ "host": "www.mywebsite.com"
369
+ },
370
+ "credentials": "www.mywebsite.com"
371
+ }
372
+ },
373
+ {
374
+ "action": "readme-build",
375
+ "files": ["README.txt"],
376
+ "publish": {
377
+ "action": "readme-publish"
378
+ "arguments": {
379
+ "files": ["README.html"], // override files property
380
+ "host": "www.mywebsite.com"
381
+ },
382
+ "credentials": "www.mywebsite.com"
383
+ }
384
+ }
385
+ ]
386
+
387
+ }
388
+ ```
389
+
390
+ #### "condition" Property
391
+
392
+ The "condition" property is a Ruby expression that is evaluated for truthiness
393
+ to decide if the action item should be evaluated or skipped. A common use for
394
+ this is to take action based on the version (see "$version" variable section
395
+ below). The following example runs an action item only for version 2.0+ of a
396
+ release:
397
+
398
+ ```js
399
+ {
400
+ "action": "rake-task",
401
+ "arguments": { "task": "assets:package" },
402
+ "condition": "'$version' > '2.0'"
403
+ }
404
+ ```
405
+
406
+ #### "$version" Variable
407
+
408
+ A special variable "$version" is interpolated when loading the build manifest.
409
+ This variable can appear anywhere in the JSON document, and is interpolated
410
+ before any actions or conditions are evaluated.
411
+
247
412
  ## Contributing & TODO
248
413
 
249
414
  Please help by contributing commands that Samus can use to build or publish
data/bin/samus CHANGED
@@ -40,6 +40,7 @@ end
40
40
 
41
41
  dry_run = false
42
42
  zip_release = true
43
+ outfile = nil
43
44
  opts = OptionParser.new do |opts|
44
45
  opts.banner = "Usage: samus publish [options] <directory> [directory ...]\n"
45
46
  opts.banner += " samus build [options] <version> [build.json]\n"
@@ -54,6 +55,9 @@ opts = OptionParser.new do |opts|
54
55
  opts.on("--[no-]zip", "Zip release directory") do |zip|
55
56
  zip_release = zip
56
57
  end
58
+ opts.on("-o FILE", "--output", "The file (no extension) to generate") do |file|
59
+ outfile = file
60
+ end
57
61
  end
58
62
  end
59
63
  opts.parse!
@@ -79,7 +83,7 @@ elsif command == Samus::Builder
79
83
  $VERSION = $VERSION.sub(/^v/, '')
80
84
 
81
85
  (ARGV.empty? ? ['samus.json'] : ARGV).each do |file|
82
- command.new(file).build(dry_run, zip_release)
86
+ command.new(file).build(dry_run, zip_release, outfile)
83
87
  end
84
88
  else
85
89
  puts opts
@@ -1,3 +1,5 @@
1
1
  #!/bin/sh
2
2
 
3
+ set -e
4
+ git gc # might as well GC before archiving .git
3
5
  tar cfz $__build_dir/$1 .git $(git ls-files)
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- ARGV.each do |file|
3
+ ARGV.map {|f| Dir.glob(f) }.flatten.each do |file|
4
4
  contents = File.read(file)
5
5
  contents = contents.gsub(Regexp.new(ENV['_search']), ENV['_replace'])
6
6
  File.open(file, 'w') {|f| f.write(contents) }
@@ -0,0 +1,3 @@
1
+ #!/bin/sh
2
+
3
+ npm $_task $*
@@ -0,0 +1,7 @@
1
+ Runs a npm task.
2
+
3
+ Files:
4
+ * An optional list of files to run task on.
5
+
6
+ Arguments:
7
+ * task: the task to execute.
@@ -0,0 +1,3 @@
1
+ #!/bin/sh
2
+
3
+ samus build -o $__build_dir/$1 $_build_version ${_manifest}
@@ -0,0 +1,9 @@
1
+ Builds a separate Samus-backed repository as part of this Samus build.
2
+
3
+ Files:
4
+ * The archive name of the generated Samus release package.
5
+
6
+ Arguments:
7
+ * build_version: the version of the package to build.
8
+ * manifest: (optional) the name of the manifest to use when building the
9
+ manifest.
@@ -0,0 +1,3 @@
1
+ #!/bin/sh
2
+
3
+ samus publish $1
@@ -0,0 +1,7 @@
1
+ Publishes a Samus release package.
2
+
3
+ Files:
4
+ * The archive name of the generated Samus release package.
5
+
6
+ Arguments:
7
+ * (none)
@@ -16,12 +16,16 @@ module Samus
16
16
  @manifest = {}
17
17
  end
18
18
 
19
- def build(dry_run = false, zip_release = true)
19
+ def build(dry_run = false, zip_release = true, outfile = nil)
20
20
  orig_pwd = Dir.pwd
21
21
  manifest = {'version' => $VERSION, 'actions' => []}
22
22
  build_branch = "samus-release/v#{$VERSION}"
23
23
  orig_branch = `git symbolic-ref -q --short HEAD`.chomp
24
24
 
25
+ if `git diff --shortstat 2> /dev/null | tail -n1` != ""
26
+ Samus.error "Repository is dirty, it is too dangerous to continue."
27
+ end
28
+
25
29
  system "git checkout -qb #{build_branch} 2>/dev/null"
26
30
  remove_restore_file
27
31
 
@@ -41,14 +45,14 @@ module Samus
41
45
 
42
46
  Dir.chdir(build_dir) do
43
47
  generate_manifest(manifest)
44
- generate_release(orig_pwd, zip_release)
48
+ generate_release(orig_pwd, zip_release, outfile)
45
49
  end unless dry_run
46
50
  end
47
51
 
48
52
  ensure
49
53
  restore_git_repo
50
- system "git checkout -q #{orig_branch}"
51
- system "git branch -qD #{build_branch}"
54
+ system "git checkout -q #{orig_branch} 2>/dev/null"
55
+ system "git branch -qD #{build_branch} 2>/dev/null"
52
56
  end
53
57
 
54
58
  private
@@ -59,9 +63,9 @@ module Samus
59
63
  end
60
64
  end
61
65
 
62
- def generate_release(orig_pwd, zip_release = true)
63
- file = build_manifest['output'] || "release-v#{$VERSION}"
64
- file = File.join(orig_pwd, file)
66
+ def generate_release(orig_pwd, zip_release = true, outfile = nil)
67
+ file = outfile || build_manifest['output'] || "release-v#{$VERSION}"
68
+ file = File.join(orig_pwd, file) unless file[0] == '/'
65
69
  if zip_release
66
70
  file += '.tar.gz'
67
71
  system "tar cfz #{file} *"
@@ -4,16 +4,12 @@ module Samus
4
4
  def command_paths; @@command_paths end
5
5
 
6
6
  def list_commands(stage = nil)
7
- stages = {}
8
- command_paths.each do |path|
9
- Dir.glob(File.join(path, '*', '*')).each do |dir|
10
- type, name = *dir.split(File::SEPARATOR)[-2,2]
11
- next if name =~ /\.md$/
12
- next if stage && stage != type
13
- (stages[type] ||= []).push(new(type, name))
14
- end
15
- end
7
+ display_commands(collect_commands(stage))
8
+ end
16
9
 
10
+ private
11
+
12
+ def display_commands(stages)
17
13
  puts "Commands:"
18
14
  puts ""
19
15
  stages.each do |type, commands|
@@ -25,6 +21,19 @@ module Samus
25
21
  puts ""
26
22
  end
27
23
  end
24
+
25
+ def collect_commands(stage)
26
+ stages = {}
27
+ command_paths.each do |path|
28
+ Dir.glob(File.join(path, '*', '*')).each do |dir|
29
+ type, name = *dir.split(File::SEPARATOR)[-2,2]
30
+ next if name =~ /\.md$/
31
+ next if stage && stage != type
32
+ (stages[type] ||= []).push(new(type, name))
33
+ end
34
+ end
35
+ stages
36
+ end
28
37
  end
29
38
 
30
39
  @@command_paths = [File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'commands'))]
@@ -66,10 +75,7 @@ module Samus
66
75
  exec_in_dir(pwd) do
67
76
  system(env, @full_path + " " + (arguments ? arguments.join(" ") : ""))
68
77
  end
69
- if $?.to_i != 0
70
- puts "[E] Last command failed with #{$?}#{allow_fail ? ' but allowFail=true' : ', exiting'}."
71
- exit($?.to_i) unless allow_fail
72
- end
78
+ report_error($?, allow_fail)
73
79
  end
74
80
  end
75
81
 
@@ -79,6 +85,12 @@ module Samus
79
85
 
80
86
  private
81
87
 
88
+ def report_error(exit_code, allow_fail)
89
+ return if exit_code.to_i == 0
90
+ puts "[E] Last command failed with #{exit_code}#{allow_fail ? ' but allowFail=true' : ', exiting'}."
91
+ exit(exit_code.to_i) unless allow_fail
92
+ end
93
+
82
94
  def exec_in_dir(dir, &block)
83
95
  dir ? Dir.chdir(dir, &block) : yield
84
96
  end
@@ -1,3 +1,3 @@
1
1
  module Samus
2
- VERSION = '1.0.0'
2
+ VERSION = '1.1.0'
3
3
  end
data/samus.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "actions": [
3
3
  {
4
4
  "action": "fs-sedfiles",
5
- "files": ["lib/samus/version.rb"],
5
+ "files": ["lib/*/version.rb"],
6
6
  "arguments": {
7
7
  "search": "VERSION = ['\"](.+?)['\"]",
8
8
  "replace": "VERSION = '$version'"
@@ -10,7 +10,7 @@
10
10
  },
11
11
  {
12
12
  "action": "git-commit",
13
- "files": ["lib/samus/version.rb"]
13
+ "files": ["lib/*/version.rb"]
14
14
  },
15
15
  {
16
16
  "action": "git-merge",
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: samus
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Loren Segal
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-02 00:00:00.000000000 Z
11
+ date: 2014-03-20 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email: lsegal@soen.ca
@@ -42,10 +42,14 @@ files:
42
42
  - commands/build/git-commit.help.md
43
43
  - commands/build/git-merge
44
44
  - commands/build/git-merge.help.md
45
+ - commands/build/npm-task
46
+ - commands/build/npm-task.help.md
45
47
  - commands/build/npm-test
46
48
  - commands/build/npm-test.help.md
47
49
  - commands/build/rake-task
48
50
  - commands/build/rake-task.help.md
51
+ - commands/build/samus-build
52
+ - commands/build/samus-build.help.md
49
53
  - commands/publish/cf-invalidate
50
54
  - commands/publish/cf-invalidate.help.md
51
55
  - commands/publish/gem-push
@@ -56,6 +60,8 @@ files:
56
60
  - commands/publish/npm-publish.help.md
57
61
  - commands/publish/s3-put
58
62
  - commands/publish/s3-put.help.md
63
+ - commands/publish/samus-publish
64
+ - commands/publish/samus-publish.help.md
59
65
  - lib/samus.rb
60
66
  - lib/samus/action.rb
61
67
  - lib/samus/build_action.rb