ufo 2.2.2 → 2.3.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 +4 -4
- data/.gitignore +19 -5
- data/.rspec +0 -1
- data/CHANGELOG.md +6 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +7 -5
- data/Guardfile +16 -9
- data/LICENSE.txt +1 -1
- data/Rakefile +1 -1
- data/{bin → exe}/ufo +3 -5
- data/lib/starter_project/ufo/task_definitions.rb +19 -16
- data/lib/ufo.rb +5 -3
- data/lib/ufo/{aws_services.rb → aws_service.rb} +1 -1
- data/lib/ufo/cli.rb +13 -1
- data/lib/ufo/command.rb +8 -7
- data/lib/ufo/completer.rb +139 -0
- data/lib/ufo/completer/script.rb +6 -0
- data/lib/ufo/completer/script.sh +10 -0
- data/lib/ufo/completion.rb +15 -0
- data/lib/ufo/{defaults.rb → default.rb} +10 -10
- data/lib/ufo/destroy.rb +2 -2
- data/lib/ufo/docker/builder.rb +5 -3
- data/lib/ufo/docker/cleaner.rb +2 -2
- data/lib/ufo/dsl/helper.rb +7 -2
- data/lib/ufo/ecr/auth.rb +1 -1
- data/lib/ufo/ecr/cleaner.rb +3 -3
- data/lib/ufo/env.rb +3 -3
- data/lib/ufo/help/completion.md +22 -0
- data/lib/ufo/help/completion_script.md +3 -0
- data/lib/ufo/help/completions.md +16 -0
- data/lib/ufo/help/completions_script.md +1 -0
- data/lib/ufo/help/hello.md +5 -0
- data/lib/ufo/help/sub/goodbye.md +5 -0
- data/lib/ufo/log_group.rb +1 -1
- data/lib/ufo/scale.rb +2 -2
- data/lib/ufo/{settings.rb → setting.rb} +1 -1
- data/lib/ufo/ship.rb +2 -2
- data/lib/ufo/sub.rb +12 -0
- data/lib/ufo/task.rb +2 -2
- data/lib/ufo/tasks/register.rb +1 -1
- data/lib/ufo/version.rb +1 -1
- data/spec/lib/cli_spec.rb +8 -8
- data/spec/spec_helper.rb +17 -11
- data/ufo.gemspec +12 -11
- metadata +32 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df0785744573abcd889a7d125e002395ed402a11628844cbb02792579c651427
|
4
|
+
data.tar.gz: c707e64b786e5f4bf7aed4a8e64ae0b8ad1f37231b0ac2259523c707ef139932
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 126232930ff21ac0a23daf5a9ff430c268792c6eeb986998794ff641f3ba6c1cd02e186d4924c2cad0ef268a1956b1d3aff013b348188364475103203aec1fbd
|
7
|
+
data.tar.gz: dfdabc75f052471f0539e31196ec9474610ab51f82841db05685a24135f40727f6377787a94536e4e38315c005f7f98398a008c25c713e1c8ac5296dbf7ada0e
|
data/.gitignore
CHANGED
@@ -1,5 +1,19 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
_yardoc
|
7
|
+
coverage
|
8
|
+
doc/
|
9
|
+
InstalledFiles
|
10
|
+
lib/bundler/man
|
11
|
+
pkg
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/fixtures/hi
|
15
|
+
spec/fixtures/home
|
16
|
+
spec/reports
|
17
|
+
test/tmp
|
18
|
+
test/version_tmp
|
19
|
+
tmp
|
data/.rspec
CHANGED
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,12 @@
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
This project *tries* to adhere to [Semantic Versioning](http://semver.org/), even before v1.0.
|
5
5
|
|
6
|
+
## [2.2.3]
|
7
|
+
- eval $(ufo completion_script) for tab auto-completion
|
8
|
+
- default task_defintion template fixes: add ecs/ to awslogs_group, add helper.current_region
|
9
|
+
- move bin/ufo to exe/ufo
|
10
|
+
- rename: AwsServices to AwsService, Defaults to Default, Settings to Setting
|
11
|
+
|
6
12
|
## [2.2.2]
|
7
13
|
- Remove role passed to create_service. Fixes ufo ship when target-group-arn is provided.
|
8
14
|
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
ufo (2.
|
4
|
+
ufo (2.2.2)
|
5
5
|
aws-sdk-cloudwatchlogs
|
6
6
|
aws-sdk-ec2
|
7
|
+
aws-sdk-ecr
|
7
8
|
aws-sdk-ecs
|
8
9
|
aws-sdk-elasticloadbalancingv2
|
9
10
|
colorize
|
10
11
|
deep_merge
|
11
|
-
hashie
|
12
12
|
plissken
|
13
13
|
thor
|
14
14
|
|
@@ -23,7 +23,10 @@ GEM
|
|
23
23
|
aws-partitions (~> 1.0)
|
24
24
|
aws-sigv4 (~> 1.0)
|
25
25
|
jmespath (~> 1.0)
|
26
|
-
aws-sdk-ec2 (1.
|
26
|
+
aws-sdk-ec2 (1.26.0)
|
27
|
+
aws-sdk-core (~> 3)
|
28
|
+
aws-sigv4 (~> 1.0)
|
29
|
+
aws-sdk-ecr (1.2.0)
|
27
30
|
aws-sdk-core (~> 3)
|
28
31
|
aws-sigv4 (~> 1.0)
|
29
32
|
aws-sdk-ecs (1.8.0)
|
@@ -40,7 +43,6 @@ GEM
|
|
40
43
|
deep_merge (1.2.1)
|
41
44
|
diff-lcs (1.3)
|
42
45
|
docile (1.1.5)
|
43
|
-
hashie (3.5.7)
|
44
46
|
jmespath (1.3.1)
|
45
47
|
json (2.1.0)
|
46
48
|
plissken (1.2.0)
|
@@ -69,7 +71,7 @@ PLATFORMS
|
|
69
71
|
ruby
|
70
72
|
|
71
73
|
DEPENDENCIES
|
72
|
-
bundler
|
74
|
+
bundler
|
73
75
|
byebug
|
74
76
|
codeclimate-test-reporter
|
75
77
|
rake
|
data/Guardfile
CHANGED
@@ -1,12 +1,19 @@
|
|
1
|
-
guard
|
2
|
-
watch(
|
3
|
-
watch(
|
4
|
-
watch(%r{^lib/ufo/(.+)\.rb$}) { "spec/ufo_spec.rb" }
|
5
|
-
watch('spec/spec_helper.rb') { "spec/ufo_spec.rb" }
|
6
|
-
watch(%r{^lib/ufo/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
1
|
+
guard "bundler", cmd: "bundle" do
|
2
|
+
watch("Gemfile")
|
3
|
+
watch(/^.+\.gemspec/)
|
7
4
|
end
|
8
5
|
|
9
|
-
guard
|
10
|
-
|
11
|
-
|
6
|
+
guard :rspec, cmd: "bundle exec rspec" do
|
7
|
+
require "guard/rspec/dsl"
|
8
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
9
|
+
|
10
|
+
# RSpec files
|
11
|
+
rspec = dsl.rspec
|
12
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
13
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
14
|
+
watch(rspec.spec_files)
|
15
|
+
|
16
|
+
# Ruby files
|
17
|
+
ruby = dsl.ruby
|
18
|
+
dsl.watch_spec_files_for(ruby.lib_files)
|
12
19
|
end
|
data/LICENSE.txt
CHANGED
data/Rakefile
CHANGED
data/{bin → exe}/ufo
RENAMED
@@ -7,10 +7,8 @@ Signal.trap("INT") {
|
|
7
7
|
exit
|
8
8
|
}
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
require 'ufo'
|
14
|
-
require 'ufo/cli'
|
10
|
+
$:.unshift(File.expand_path("../../lib", __FILE__))
|
11
|
+
require "ufo"
|
12
|
+
require "ufo/cli"
|
15
13
|
|
16
14
|
Ufo::CLI.start(ARGV)
|
@@ -3,10 +3,11 @@
|
|
3
3
|
# Some of helpers get data from the Dockerfile and some are from other places.
|
4
4
|
# Here's a summary of the some helpers:
|
5
5
|
#
|
6
|
-
# full_image_name
|
7
|
-
# dockerfile_port
|
8
|
-
# env_vars(text)
|
9
|
-
# env_file(path)
|
6
|
+
# helper.full_image_name
|
7
|
+
# helper.dockerfile_port
|
8
|
+
# helper.env_vars(text)
|
9
|
+
# helper.env_file(path)
|
10
|
+
# helper.current_region
|
10
11
|
#
|
11
12
|
# More info: http://ufoships.com/docs/helpers/
|
12
13
|
#
|
@@ -16,10 +17,12 @@ task_definition "<%= @app %>-web" do
|
|
16
17
|
family: task_definition_name,
|
17
18
|
name: "web",
|
18
19
|
container_port: helper.dockerfile_port,
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
|
20
|
+
# Comment out awslogs_* if you do not want logs to be sent to CloudWatch.
|
21
|
+
# Strongly recommended to use CloudWatch/centralized logging.
|
22
|
+
# Ufo automatically creates the log group as part of deployment.
|
23
|
+
awslogs_group: "ecs/<%= @app %>-web",
|
24
|
+
awslogs_stream_prefix: "<%= @app %>",
|
25
|
+
awslogs_region: helper.current_region,
|
23
26
|
# command: ["bin/web"] # IMPORTANT: change or create a bin/web file
|
24
27
|
)
|
25
28
|
end
|
@@ -29,10 +32,10 @@ task_definition "<%= @app %>-worker" do
|
|
29
32
|
variables(
|
30
33
|
family: task_definition_name,
|
31
34
|
name: "worker",
|
32
|
-
#
|
33
|
-
|
34
|
-
|
35
|
-
|
35
|
+
# Comment out awslogs_* if you do not want logs to be sent to CloudWatch.
|
36
|
+
awslogs_group: "ecs/<%= @app %>-worker",
|
37
|
+
awslogs_stream_prefix: "<%= @app %>",
|
38
|
+
awslogs_region: helper.current_region,
|
36
39
|
# command: ["bin/worker"] # IMPORTANT: change or create a bin/worker file
|
37
40
|
)
|
38
41
|
end
|
@@ -42,10 +45,10 @@ task_definition "<%= @app %>-clock" do
|
|
42
45
|
variables(
|
43
46
|
family: task_definition_name,
|
44
47
|
name: "clock",
|
45
|
-
#
|
46
|
-
|
47
|
-
|
48
|
-
|
48
|
+
# Comment out awslogs_* if you do not want logs to be sent to CloudWatch.
|
49
|
+
awslogs_group: "ecs/<%= @app %>-clock",
|
50
|
+
awslogs_stream_prefix: "<%= @app %>",
|
51
|
+
awslogs_region: helper.current_region,
|
49
52
|
# command: ["bin/clock"] # IMPORTANT: change or create a bin/clock file
|
50
53
|
)
|
51
54
|
end
|
data/lib/ufo.rb
CHANGED
@@ -6,10 +6,10 @@ require 'fileutils'
|
|
6
6
|
|
7
7
|
module Ufo
|
8
8
|
autoload :Env, 'ufo/env'
|
9
|
-
autoload :
|
10
|
-
autoload :
|
9
|
+
autoload :Default, 'ufo/default'
|
10
|
+
autoload :AwsService, 'ufo/aws_service'
|
11
11
|
autoload :Command, 'ufo/command'
|
12
|
-
autoload :
|
12
|
+
autoload :Setting, 'ufo/setting'
|
13
13
|
autoload :Util, 'ufo/util'
|
14
14
|
autoload :Init, 'ufo/init'
|
15
15
|
autoload :CLI, 'ufo/cli'
|
@@ -24,6 +24,8 @@ module Ufo
|
|
24
24
|
autoload :Docker, 'ufo/docker'
|
25
25
|
autoload :Ecr, 'ufo/ecr'
|
26
26
|
autoload :Tasks, 'ufo/tasks'
|
27
|
+
autoload :Completion, "ufo/completion"
|
28
|
+
autoload :Completer, "ufo/completer"
|
27
29
|
end
|
28
30
|
|
29
31
|
Ufo::Env.setup!
|
data/lib/ufo/cli.rb
CHANGED
@@ -35,7 +35,7 @@ module Ufo
|
|
35
35
|
option :wait, type: :boolean, desc: "Wait for deployment to complete", default: false
|
36
36
|
option :pretty, type: :boolean, default: true, desc: "Pretty format the json for the task definitions"
|
37
37
|
option :stop_old_tasks, type: :boolean, default: false, desc: "Stop old tasks after waiting for deploying to complete"
|
38
|
-
option :ecr_keep, type: :numeric, desc: "ECR specific cleanup of old images. Specifies how many images to keep. Only runs if the images are ECR images. Defaults
|
38
|
+
option :ecr_keep, type: :numeric, desc: "ECR specific cleanup of old images. Specifies how many images to keep. Only runs if the images are ECR images. Defaults keeps all images."
|
39
39
|
end
|
40
40
|
|
41
41
|
desc "ship [SERVICE]", "builds and ships container image to the ECS service"
|
@@ -95,6 +95,18 @@ module Ufo
|
|
95
95
|
Scale.new(service, count, options).update
|
96
96
|
end
|
97
97
|
|
98
|
+
desc "completion *PARAMS", "prints words for auto-completion"
|
99
|
+
long_desc Help.text("completion")
|
100
|
+
def completion(*params)
|
101
|
+
Completer.new(CLI, *params).run
|
102
|
+
end
|
103
|
+
|
104
|
+
desc "completion_script", "generates script that can be eval to setup auto-completion", hide: true
|
105
|
+
long_desc Help.text("completion_script")
|
106
|
+
def completion_script
|
107
|
+
Completer::Script.generate
|
108
|
+
end
|
109
|
+
|
98
110
|
desc "version", "Prints version number of installed ufo"
|
99
111
|
def version
|
100
112
|
puts VERSION
|
data/lib/ufo/command.rb
CHANGED
@@ -18,23 +18,24 @@ module Ufo
|
|
18
18
|
class << self
|
19
19
|
def dispatch(m, args, options, config)
|
20
20
|
# Allow calling for help via:
|
21
|
-
# ufo
|
22
|
-
# ufo
|
23
|
-
# ufo
|
24
|
-
# ufo
|
21
|
+
# ufo command help
|
22
|
+
# ufo command -h
|
23
|
+
# ufo command --help
|
24
|
+
# ufo command -D
|
25
25
|
#
|
26
|
-
# as well thor's
|
26
|
+
# as well thor's normal way:
|
27
27
|
#
|
28
|
-
# ufo help
|
28
|
+
# ufo help command
|
29
29
|
help_flags = Thor::HELP_MAPPINGS + ["help"]
|
30
30
|
if args.length > 1 && !(args & help_flags).empty?
|
31
31
|
args -= help_flags
|
32
32
|
args.insert(-2, "help")
|
33
33
|
end
|
34
34
|
|
35
|
+
# ufo version
|
35
36
|
# ufo --version
|
36
37
|
# ufo -v
|
37
|
-
version_flags = ["
|
38
|
+
version_flags = ["--version", "-v"]
|
38
39
|
if args.length == 1 && !(args & version_flags).empty?
|
39
40
|
args = ["version"]
|
40
41
|
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
# Code Explanation. This is mainly focused on the run method.
|
2
|
+
#
|
3
|
+
# There are 3 main branches of logic for completion:
|
4
|
+
#
|
5
|
+
# 1. top-level commands - when there are zero completed words
|
6
|
+
# 2. params completion - when a command has some required params
|
7
|
+
# 3. options completion - when we have finished auto-completing the top-level command and required params, the rest of the completion words will be options
|
8
|
+
#
|
9
|
+
# Terms:
|
10
|
+
#
|
11
|
+
# params - these are params in the command itself. Example: for the method `scale(service, count)` the params would be `service, count`.
|
12
|
+
# options - these are cli options flags. Examples: --noop, --verbose
|
13
|
+
#
|
14
|
+
# When we are done processing method params, the completion will be only options. When the detected params size is greater than the arity we are have finished auto-completing the parameters in the method declaration. For example, say you had a method for a CLI command with the following form:
|
15
|
+
#
|
16
|
+
# scale(service, count) = arity of 2
|
17
|
+
#
|
18
|
+
# ufo scale service count [TAB] # there are 3 params including the "scale" command
|
19
|
+
#
|
20
|
+
# So the completion will be something like:
|
21
|
+
#
|
22
|
+
# --noop --verbose etc
|
23
|
+
#
|
24
|
+
# A note about artity values:
|
25
|
+
#
|
26
|
+
# We are using the arity of the command method to determine if we have finish auto-completing the params completion. When the ruby method has a splat param, it's arity will be negative. Here are some example methods and their arities.
|
27
|
+
#
|
28
|
+
# ship(service) = 1
|
29
|
+
# scale(service, count) = 2
|
30
|
+
# ships(*services) = -1
|
31
|
+
# foo(example, *rest) = -2
|
32
|
+
#
|
33
|
+
# Fortunately, negative and positive arity values are processed the same way. So we take simply take the abs of the arity.
|
34
|
+
#
|
35
|
+
# To test:
|
36
|
+
#
|
37
|
+
# ufo completion
|
38
|
+
# ufo completion hello
|
39
|
+
# ufo completion hello name
|
40
|
+
# ufo completion hello name --
|
41
|
+
# ufo completion hello name --noop
|
42
|
+
#
|
43
|
+
# ufo completion
|
44
|
+
# ufo completion sub:goodbye
|
45
|
+
# ufo completion sub:goodbye name
|
46
|
+
#
|
47
|
+
# Note when testing, the first top-level word must be an exact match
|
48
|
+
#
|
49
|
+
# ufo completion hello # works fine
|
50
|
+
# ufo completion he # incomplete, this will just break
|
51
|
+
#
|
52
|
+
# The completion assumes that the top-level word that is being passed in
|
53
|
+
# from completor/scripts.sh will always match exactly. This must be the
|
54
|
+
# case. For parameters, the word does not have to match exactly.
|
55
|
+
#
|
56
|
+
module Ufo
|
57
|
+
class Completer
|
58
|
+
autoload :Script, 'ufo/completer/script'
|
59
|
+
|
60
|
+
def initialize(command_class, *params)
|
61
|
+
@params = params
|
62
|
+
@current_command = @params[0]
|
63
|
+
@command_class = command_class # CLI initiall
|
64
|
+
end
|
65
|
+
|
66
|
+
def run
|
67
|
+
if subcommand?(@current_command)
|
68
|
+
subcommand_class = @command_class.subcommand_classes[@current_command]
|
69
|
+
@params.shift # destructive
|
70
|
+
Completer.new(subcommand_class, *@params).run # recursively use subcommand
|
71
|
+
return
|
72
|
+
end
|
73
|
+
|
74
|
+
# full command has been found!
|
75
|
+
unless found?(@current_command)
|
76
|
+
puts all_commands
|
77
|
+
return
|
78
|
+
end
|
79
|
+
|
80
|
+
# will only get to here if command aws found (above)
|
81
|
+
arity = @command_class.instance_method(@current_command).arity.abs
|
82
|
+
if @params.size <= arity
|
83
|
+
puts params_completion
|
84
|
+
else
|
85
|
+
puts options_completion
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def subcommand?(command)
|
90
|
+
@command_class.subcommands.include?(command)
|
91
|
+
end
|
92
|
+
|
93
|
+
def found?(command)
|
94
|
+
public_methods = @command_class.public_instance_methods - Object.methods
|
95
|
+
command && public_methods.include?(command.to_sym)
|
96
|
+
end
|
97
|
+
|
98
|
+
# all top-level commands
|
99
|
+
def all_commands
|
100
|
+
commands = @command_class.all_commands.reject do |k,v|
|
101
|
+
v.is_a?(Thor::HiddenCommand)
|
102
|
+
end
|
103
|
+
commands.keys
|
104
|
+
end
|
105
|
+
|
106
|
+
def params_completion
|
107
|
+
method_params = @command_class.instance_method(@current_command).parameters
|
108
|
+
# Example:
|
109
|
+
# >> Sub.instance_method(:goodbye).parameters
|
110
|
+
# => [[:req, :name]]
|
111
|
+
# >>
|
112
|
+
method_params.map!(&:last)
|
113
|
+
|
114
|
+
offset = @params.size - 1
|
115
|
+
offset_params = method_params[offset..-1]
|
116
|
+
method_params[offset..-1].first
|
117
|
+
end
|
118
|
+
|
119
|
+
def options_completion
|
120
|
+
used = ARGV.select { |a| a.include?('--') } # so we can remove used options
|
121
|
+
|
122
|
+
method_options = @command_class.all_commands[@current_command].options.keys
|
123
|
+
class_options = @command_class.class_options.keys
|
124
|
+
|
125
|
+
all_options = method_options + class_options + ['help']
|
126
|
+
|
127
|
+
all_options.map! { |o| "--#{o.to_s.gsub('_','-')}" }
|
128
|
+
filtered_options = all_options - used
|
129
|
+
filtered_options.uniq
|
130
|
+
end
|
131
|
+
|
132
|
+
# Useful for debugging. Using puts messes up completion.
|
133
|
+
def log(msg)
|
134
|
+
File.open("/tmp/complete.log", "a") do |file|
|
135
|
+
file.puts(msg)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Ufo
|
2
|
+
class Completion < Command
|
3
|
+
desc "script", "generates script that can be eval to setup auto-completion"
|
4
|
+
long_desc Help.text("completion:script")
|
5
|
+
def script
|
6
|
+
Completer::Script.generate
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "completions *PARAMS", "prints words for auto-completion"
|
10
|
+
long_desc Help.text("completion:list")
|
11
|
+
def list(*params)
|
12
|
+
Completer.new(*params).run
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -7,15 +7,15 @@ module Ufo
|
|
7
7
|
# end
|
8
8
|
#
|
9
9
|
# So @options must be set
|
10
|
-
module
|
10
|
+
module Default
|
11
11
|
# The default cluster normally defaults to the UFO_ENV value.
|
12
12
|
# But it can be overriden by ufo/settings.yml ufo_env_cluster_map
|
13
13
|
#
|
14
|
-
#
|
14
|
+
# More info: http://ufoships.com/docs/settings/
|
15
15
|
def default_cluster
|
16
16
|
#
|
17
17
|
|
18
|
-
map =
|
18
|
+
map = setting.data["ufo_env_cluster_map"]
|
19
19
|
if map
|
20
20
|
ecs_cluster = map[UFO_ENV] || map["default"]
|
21
21
|
end
|
@@ -25,23 +25,23 @@ module Ufo
|
|
25
25
|
|
26
26
|
# These default service values only are used when a service is created by `ufo`
|
27
27
|
def default_maximum_percent
|
28
|
-
Integer(
|
28
|
+
Integer(new_service_setting["maximum_percent"] || 200)
|
29
29
|
end
|
30
30
|
|
31
31
|
def default_minimum_healthy_percent
|
32
|
-
Integer(
|
32
|
+
Integer(new_service_setting["minimum_healthy_percent"] || 100)
|
33
33
|
end
|
34
34
|
|
35
35
|
def default_desired_count
|
36
|
-
Integer(
|
36
|
+
Integer(new_service_setting["desired_count"] || 1)
|
37
37
|
end
|
38
38
|
|
39
|
-
def
|
40
|
-
|
39
|
+
def new_service_setting
|
40
|
+
setting.data["new_service"] || {}
|
41
41
|
end
|
42
42
|
|
43
|
-
def
|
44
|
-
@
|
43
|
+
def setting
|
44
|
+
@setting ||= Setting.new(@options[:project_root])
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
data/lib/ufo/destroy.rb
CHANGED
data/lib/ufo/docker/builder.rb
CHANGED
@@ -78,7 +78,7 @@ module Ufo
|
|
78
78
|
|
79
79
|
# full_image - does not include the tag
|
80
80
|
def image_name
|
81
|
-
|
81
|
+
setting.data["image"]
|
82
82
|
end
|
83
83
|
|
84
84
|
# full_image - includes the tag
|
@@ -87,6 +87,8 @@ module Ufo
|
|
87
87
|
return generate_name # name already has a newline
|
88
88
|
end
|
89
89
|
|
90
|
+
return "tongueroo/hi:ufo-12345678" if ENV['TEST']
|
91
|
+
|
90
92
|
unless File.exist?(docker_name_path)
|
91
93
|
puts "Unable to find #{docker_name_path} which contains the last docker image name that was used as a part of `ufo docker build`. Please run `ufo docker build` first."
|
92
94
|
exit 1
|
@@ -125,8 +127,8 @@ module Ufo
|
|
125
127
|
@git_sha.strip!
|
126
128
|
end
|
127
129
|
|
128
|
-
def
|
129
|
-
@
|
130
|
+
def setting
|
131
|
+
@setting ||= Setting.new(@project_root)
|
130
132
|
end
|
131
133
|
|
132
134
|
def update_dockerfile
|
data/lib/ufo/docker/cleaner.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
module Ufo
|
2
2
|
class Docker::Cleaner
|
3
3
|
include Util
|
4
|
-
include
|
4
|
+
include Default
|
5
5
|
|
6
6
|
def initialize(docker_image_name, options)
|
7
7
|
# docker_image_name does not containg the tag
|
8
8
|
# Example: 123456789.dkr.ecr.us-east-1.amazonaws.com/image
|
9
9
|
@docker_image_name = docker_image_name
|
10
10
|
@options = options
|
11
|
-
@keep = options[:keep] ||
|
11
|
+
@keep = options[:keep] || setting.data["clean_keep"] || 3
|
12
12
|
@tag_prefix = options[:tag_prefix] || "ufo"
|
13
13
|
end
|
14
14
|
|
data/lib/ufo/dsl/helper.rb
CHANGED
@@ -59,8 +59,13 @@ module Ufo
|
|
59
59
|
env_vars(text)
|
60
60
|
end
|
61
61
|
|
62
|
-
def
|
63
|
-
|
62
|
+
def current_region
|
63
|
+
return 'us-east-1' if ENV['TEST']
|
64
|
+
@current_region ||= `aws configure get region`.strip rescue 'us-east-1'
|
65
|
+
end
|
66
|
+
|
67
|
+
def setting
|
68
|
+
@setting ||= Setting.new(@project_root)
|
64
69
|
end
|
65
70
|
|
66
71
|
def parse_for_dockerfile_port(dockerfile_path)
|
data/lib/ufo/ecr/auth.rb
CHANGED
data/lib/ufo/ecr/cleaner.rb
CHANGED
@@ -5,15 +5,15 @@ require "json"
|
|
5
5
|
# ufo ship app-web --cluster prod --noop
|
6
6
|
module Ufo
|
7
7
|
class Ecr::Cleaner
|
8
|
-
include
|
9
|
-
include
|
8
|
+
include AwsService
|
9
|
+
include Default
|
10
10
|
|
11
11
|
def initialize(docker_image_name, options={})
|
12
12
|
# docker_image_name does not containg the tag
|
13
13
|
# Example: 123456789.dkr.ecr.us-east-1.amazonaws.com/image
|
14
14
|
@docker_image_name = docker_image_name
|
15
15
|
@options = options
|
16
|
-
@keep = options[:ecr_keep] ||
|
16
|
+
@keep = options[:ecr_keep] || setting.data["ecr_keep"]
|
17
17
|
@tag_prefix = options[:tag_prefix] || "ufo"
|
18
18
|
end
|
19
19
|
|
data/lib/ufo/env.rb
CHANGED
@@ -3,9 +3,9 @@ class Ufo::Env
|
|
3
3
|
# Ensures that UFO_ENV is always set to a default value.
|
4
4
|
# For Ufo::Env.setup! we do not need to check if we're in a ufo project
|
5
5
|
# Because we could not be at first. For example when: ufo init is first called.
|
6
|
-
# Other uses of Ufo::
|
7
|
-
|
8
|
-
map =
|
6
|
+
# Other uses of Ufo::Setting assumes that we should be in a ufo project.
|
7
|
+
setting = Ufo::Setting.new(project_root, false).data
|
8
|
+
map = setting['aws_profile_ufo_env_map']
|
9
9
|
|
10
10
|
if map
|
11
11
|
ufo_env = map[ENV['AWS_PROFILE']] || map['default']
|
@@ -0,0 +1,22 @@
|
|
1
|
+
Example:
|
2
|
+
|
3
|
+
ufo completion
|
4
|
+
|
5
|
+
Prints words for TAB auto-completion.
|
6
|
+
|
7
|
+
Examples:
|
8
|
+
|
9
|
+
ufo completion
|
10
|
+
ufo completion hello
|
11
|
+
ufo completion hello name
|
12
|
+
|
13
|
+
To enable, TAB auto-completion add the following to your profile:
|
14
|
+
|
15
|
+
eval $(ufo completion script)
|
16
|
+
|
17
|
+
Auto-completion example usage:
|
18
|
+
|
19
|
+
ufo [TAB]
|
20
|
+
ufo hello [TAB]
|
21
|
+
ufo hello name [TAB]
|
22
|
+
ufo hello name --[TAB]
|
@@ -0,0 +1,16 @@
|
|
1
|
+
Provides completions words.
|
2
|
+
|
3
|
+
Examples:
|
4
|
+
|
5
|
+
ufo completions ship service --mute
|
6
|
+
|
7
|
+
Add this to your profile:
|
8
|
+
|
9
|
+
eval $(ufo completions-script)
|
10
|
+
|
11
|
+
Auto-completion example usage:
|
12
|
+
|
13
|
+
ufo ship [TAB]
|
14
|
+
ufo ship service [TAB]
|
15
|
+
ufo ship service --mute[TAB]
|
16
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
eval $(ufo completions_script)
|
data/lib/ufo/log_group.rb
CHANGED
data/lib/ufo/scale.rb
CHANGED
data/lib/ufo/ship.rb
CHANGED
data/lib/ufo/sub.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
module Ufo
|
2
|
+
class Sub < Command
|
3
|
+
|
4
|
+
desc "goodbye NAME", "say goodbye to NAME"
|
5
|
+
long_desc Help.text("sub:goodbye")
|
6
|
+
option :from, desc: "from person"
|
7
|
+
def goodbye(name="you")
|
8
|
+
puts "from: #{options[:from]}" if options[:from]
|
9
|
+
puts "Goodbye #{name}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/ufo/task.rb
CHANGED
data/lib/ufo/tasks/register.rb
CHANGED
data/lib/ufo/version.rb
CHANGED
data/spec/lib/cli_spec.rb
CHANGED
@@ -15,31 +15,31 @@ describe Ufo::CLI do
|
|
15
15
|
describe "ufo" do
|
16
16
|
context "docker" do
|
17
17
|
it "build builds image" do
|
18
|
-
out = execute("
|
18
|
+
out = execute("exe/ufo docker build #{@args}")
|
19
19
|
expect(out).to include("docker build -t tongueroo/hi")
|
20
20
|
end
|
21
21
|
|
22
22
|
it "tag shows the tag" do
|
23
|
-
out = execute("
|
23
|
+
out = execute("exe/ufo docker name #{@args}")
|
24
24
|
expect(out).to match(%r{tongueroo/hi:ufo-.{7}})
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
context "tasks" do
|
29
29
|
it "build builds task definition" do
|
30
|
-
out = execute("
|
30
|
+
out = execute("exe/ufo tasks build #{@args}")
|
31
31
|
expect(out).to include("Task Definitions built")
|
32
32
|
end
|
33
33
|
|
34
34
|
it "register it registers all the output task definitions" do
|
35
|
-
out = execute("
|
35
|
+
out = execute("exe/ufo tasks register #{@args}")
|
36
36
|
expect(out).to include("register")
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
40
|
context "ship" do
|
41
41
|
it "deploys software" do
|
42
|
-
out = execute("
|
42
|
+
out = execute("exe/ufo ship hi-web-prod #{@args} --no-wait")
|
43
43
|
# cannot look for Software shipped! because
|
44
44
|
# ship.deploy unless ENV['TEST'] # to allow me to quickly test CLI portion only
|
45
45
|
# just testing the CLI portion. The ship class itself is tested via ship_spec.rb
|
@@ -49,7 +49,7 @@ describe Ufo::CLI do
|
|
49
49
|
|
50
50
|
context "ships" do
|
51
51
|
it "deploys software to multiple services" do
|
52
|
-
out = execute("
|
52
|
+
out = execute("exe/ufo ships hi-web-prod hi-worker-prod #{@args} --no-wait")
|
53
53
|
# cannot look for Software shipped! because
|
54
54
|
# ship.deploy unless ENV['TEST'] # to allow me to quickly test CLI portion only
|
55
55
|
# just testing the CLI portion. The ship class itself is tested via ship_spec.rb
|
@@ -59,8 +59,8 @@ describe Ufo::CLI do
|
|
59
59
|
|
60
60
|
context "task" do
|
61
61
|
it "runs one time task" do
|
62
|
-
out = execute("
|
63
|
-
expect(out).to include("
|
62
|
+
out = execute("exe/ufo completion ship name")
|
63
|
+
expect(out).to include("--help")
|
64
64
|
end
|
65
65
|
end
|
66
66
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,30 +1,36 @@
|
|
1
|
-
ENV[
|
1
|
+
ENV["TEST"] = "1"
|
2
2
|
# Ensures aws api never called. Fixture home folder does not contain ~/.aws/credentails
|
3
3
|
ENV['HOME'] = "spec/fixtures/home"
|
4
4
|
|
5
|
+
# CodeClimate test coverage: https://docs.codeclimate.com/docs/configuring-test-coverage
|
6
|
+
# require 'simplecov'
|
7
|
+
# SimpleCov.start
|
8
|
+
|
5
9
|
require "pp"
|
6
10
|
require "byebug"
|
7
|
-
|
8
|
-
root = File.expand_path('../../', __FILE__)
|
11
|
+
root = File.expand_path("../", File.dirname(__FILE__))
|
9
12
|
require "#{root}/lib/ufo"
|
10
13
|
|
11
14
|
module Helpers
|
15
|
+
def create_starter_project_fixture
|
16
|
+
FileUtils.rm_rf("spec/fixtures/hi")
|
17
|
+
execute("exe/ufo init --app hi --image tongueroo/hi --project-root spec/fixtures/hi")
|
18
|
+
end
|
19
|
+
|
12
20
|
def execute(cmd)
|
13
|
-
puts "Running: #{cmd
|
21
|
+
puts "Running: #{cmd}" if show_command?
|
14
22
|
out = `#{cmd}`
|
15
|
-
puts out if
|
23
|
+
puts out if show_command?
|
16
24
|
out
|
17
25
|
end
|
18
26
|
|
19
|
-
|
20
|
-
|
21
|
-
|
27
|
+
# Added SHOW_COMMAND because DEBUG is also used by other libraries like
|
28
|
+
# bundler and it shows its internal debugging logging also.
|
29
|
+
def show_command?
|
30
|
+
ENV['DEBUG'] || ENV['SHOW_COMMAND']
|
22
31
|
end
|
23
32
|
end
|
24
33
|
|
25
34
|
RSpec.configure do |c|
|
26
35
|
c.include Helpers
|
27
|
-
|
28
|
-
c.before(:each) do
|
29
|
-
end
|
30
36
|
end
|
data/ufo.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
lib = File.expand_path(
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
4
|
+
require "ufo/version"
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "ufo"
|
@@ -10,25 +10,26 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.email = ["tongueroo@gmail.com"]
|
11
11
|
spec.description = %q{Build Docker Containers and Ship Them to AWS ECS}
|
12
12
|
spec.summary = %q{Build Docker Containers and Ship Them to AWS ECS}
|
13
|
-
spec.homepage = "
|
13
|
+
spec.homepage = "http://ufoships.com"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
16
|
spec.files = `git ls-files`.split($/)
|
17
|
-
spec.
|
17
|
+
spec.bindir = "exe"
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
20
|
spec.require_paths = ["lib"]
|
20
21
|
|
21
|
-
spec.add_dependency "
|
22
|
-
spec.add_dependency "hashie"
|
23
|
-
spec.add_dependency "colorize"
|
24
|
-
spec.add_dependency "deep_merge"
|
25
|
-
spec.add_dependency "aws-sdk-ecs"
|
22
|
+
spec.add_dependency "aws-sdk-cloudwatchlogs"
|
26
23
|
spec.add_dependency "aws-sdk-ec2"
|
24
|
+
spec.add_dependency "aws-sdk-ecr"
|
25
|
+
spec.add_dependency "aws-sdk-ecs"
|
27
26
|
spec.add_dependency "aws-sdk-elasticloadbalancingv2"
|
28
|
-
spec.add_dependency "
|
27
|
+
spec.add_dependency "colorize"
|
28
|
+
spec.add_dependency "deep_merge"
|
29
29
|
spec.add_dependency "plissken"
|
30
|
+
spec.add_dependency "thor"
|
30
31
|
|
31
|
-
spec.add_development_dependency "bundler"
|
32
|
+
spec.add_development_dependency "bundler"
|
32
33
|
spec.add_development_dependency "byebug"
|
33
34
|
spec.add_development_dependency "rake"
|
34
35
|
spec.add_development_dependency "rspec"
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ufo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tung Nguyen
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-02-
|
11
|
+
date: 2018-02-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: aws-sdk-cloudwatchlogs
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
@@ -25,7 +25,7 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: aws-sdk-ec2
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: aws-sdk-ecr
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
@@ -53,7 +53,7 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: aws-sdk-ecs
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
@@ -67,7 +67,7 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name: aws-sdk-
|
70
|
+
name: aws-sdk-elasticloadbalancingv2
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
@@ -81,7 +81,7 @@ dependencies:
|
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: colorize
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - ">="
|
@@ -95,7 +95,7 @@ dependencies:
|
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
98
|
+
name: deep_merge
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - ">="
|
@@ -109,7 +109,7 @@ dependencies:
|
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
112
|
+
name: plissken
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - ">="
|
@@ -123,7 +123,7 @@ dependencies:
|
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
126
|
+
name: thor
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
129
|
- - ">="
|
@@ -140,16 +140,16 @@ dependencies:
|
|
140
140
|
name: bundler
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
|
-
- - "
|
143
|
+
- - ">="
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: '
|
145
|
+
version: '0'
|
146
146
|
type: :development
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
|
-
- - "
|
150
|
+
- - ">="
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: '
|
152
|
+
version: '0'
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: byebug
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -210,7 +210,6 @@ files:
|
|
210
210
|
- LICENSE.txt
|
211
211
|
- README.md
|
212
212
|
- Rakefile
|
213
|
-
- bin/ufo
|
214
213
|
- docs/.gitignore
|
215
214
|
- docs/CNAME
|
216
215
|
- docs/Gemfile
|
@@ -311,6 +310,7 @@ files:
|
|
311
310
|
- docs/js/nav.js
|
312
311
|
- docs/quick-start.md
|
313
312
|
- docs/style.css
|
313
|
+
- exe/ufo
|
314
314
|
- lib/starter_project/.env
|
315
315
|
- lib/starter_project/Dockerfile
|
316
316
|
- lib/starter_project/bin/deploy
|
@@ -321,11 +321,15 @@ files:
|
|
321
321
|
- lib/starter_project/ufo/variables/development.rb
|
322
322
|
- lib/starter_project/ufo/variables/production.rb
|
323
323
|
- lib/ufo.rb
|
324
|
-
- lib/ufo/
|
324
|
+
- lib/ufo/aws_service.rb
|
325
325
|
- lib/ufo/cli.rb
|
326
326
|
- lib/ufo/command.rb
|
327
|
+
- lib/ufo/completer.rb
|
328
|
+
- lib/ufo/completer/script.rb
|
329
|
+
- lib/ufo/completer/script.sh
|
330
|
+
- lib/ufo/completion.rb
|
331
|
+
- lib/ufo/default.rb
|
327
332
|
- lib/ufo/default/settings.yml
|
328
|
-
- lib/ufo/defaults.rb
|
329
333
|
- lib/ufo/destroy.rb
|
330
334
|
- lib/ufo/docker.rb
|
331
335
|
- lib/ufo/docker/builder.rb
|
@@ -340,16 +344,22 @@ files:
|
|
340
344
|
- lib/ufo/ecr/cleaner.rb
|
341
345
|
- lib/ufo/env.rb
|
342
346
|
- lib/ufo/help.rb
|
347
|
+
- lib/ufo/help/completion.md
|
348
|
+
- lib/ufo/help/completion_script.md
|
349
|
+
- lib/ufo/help/completions.md
|
350
|
+
- lib/ufo/help/completions_script.md
|
343
351
|
- lib/ufo/help/destroy.md
|
344
352
|
- lib/ufo/help/docker.md
|
345
353
|
- lib/ufo/help/docker/base.md
|
346
354
|
- lib/ufo/help/docker/build.md
|
347
355
|
- lib/ufo/help/docker/clean.md
|
348
356
|
- lib/ufo/help/docker/name.md
|
357
|
+
- lib/ufo/help/hello.md
|
349
358
|
- lib/ufo/help/init.md
|
350
359
|
- lib/ufo/help/scale.md
|
351
360
|
- lib/ufo/help/ship.md
|
352
361
|
- lib/ufo/help/ships.md
|
362
|
+
- lib/ufo/help/sub/goodbye.md
|
353
363
|
- lib/ufo/help/task.md
|
354
364
|
- lib/ufo/help/tasks.md
|
355
365
|
- lib/ufo/help/tasks/build.md
|
@@ -357,8 +367,9 @@ files:
|
|
357
367
|
- lib/ufo/init.rb
|
358
368
|
- lib/ufo/log_group.rb
|
359
369
|
- lib/ufo/scale.rb
|
360
|
-
- lib/ufo/
|
370
|
+
- lib/ufo/setting.rb
|
361
371
|
- lib/ufo/ship.rb
|
372
|
+
- lib/ufo/sub.rb
|
362
373
|
- lib/ufo/task.rb
|
363
374
|
- lib/ufo/tasks.rb
|
364
375
|
- lib/ufo/tasks/builder.rb
|
@@ -375,7 +386,7 @@ files:
|
|
375
386
|
- spec/lib/task_spec.rb
|
376
387
|
- spec/spec_helper.rb
|
377
388
|
- ufo.gemspec
|
378
|
-
homepage:
|
389
|
+
homepage: http://ufoships.com
|
379
390
|
licenses:
|
380
391
|
- MIT
|
381
392
|
metadata: {}
|