serverkit 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +57 -21
- data/examples/recipe.json +48 -0
- data/examples/recipe.rb +5 -0
- data/examples/recipe.yml +11 -11
- data/lib/serverkit/actions/apply.rb +3 -3
- data/lib/serverkit/actions/base.rb +2 -1
- data/lib/serverkit/actions/check.rb +2 -2
- data/lib/serverkit/recipe.rb +19 -11
- data/lib/serverkit/recipe_loader.rb +79 -0
- data/lib/serverkit/resources/base.rb +4 -1
- data/lib/serverkit/resources/file.rb +4 -6
- data/lib/serverkit/resources/git.rb +3 -3
- data/lib/serverkit/resources/homebrew_cask.rb +3 -3
- data/lib/serverkit/resources/package.rb +3 -3
- data/lib/serverkit/resources/service.rb +17 -0
- data/lib/serverkit/resources/symlink.rb +2 -2
- data/lib/serverkit/version.rb +1 -1
- data/lib/type_validator.rb +13 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0cb2f4173299cf4eec3b5b1004d1f006c0d211e0
|
4
|
+
data.tar.gz: 851e865ea88715d4eeaf697a7c053e6a5500b379
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 23cb9453fdd628b6b87448b94a075826ca9d14367e2fe49b17d237cff832665a9b9be0fc90d112883da2e494772292516327e6d41aeffb1955f33e9b7b819b65
|
7
|
+
data.tar.gz: 12382244676a0ea0749f9f15577352cfd3ab9df973393d7a970ae7facdc1a3f942d875830ca092d5c62dab9e0f976d65fdd7eda05785901f616aaa404cc39424
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## 0.0.3
|
2
|
+
- Support JSON, executable, and directory recipe
|
3
|
+
- Support service resource experimentally
|
4
|
+
- Validate attribute type
|
5
|
+
- Validate no resources recipe
|
6
|
+
- Rename resource.name with resource.id
|
7
|
+
- Rename package.package with package.name
|
8
|
+
|
1
9
|
## 0.0.2
|
2
10
|
- Add `serverkit validate` action
|
3
11
|
|
data/README.md
CHANGED
@@ -2,42 +2,78 @@
|
|
2
2
|
Configuration management toolkit for your infrastructure.
|
3
3
|
|
4
4
|
## Usage
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
This gem provides `serverkit` executable with 3 actions.
|
6
|
+
`validate` action validates your recipe format.
|
7
|
+
`check` action shows the difference between your recipe and the state of the target host.
|
8
|
+
`apply` action executes migration programs to fill-in the gaps.
|
8
9
|
|
9
|
-
|
10
|
+
```sh
|
10
11
|
serverkit validate --recipe=recipe.yml
|
11
|
-
|
12
|
-
# Check differences
|
13
12
|
serverkit check --recipe=recipe.yml
|
13
|
+
serverkit apply --recipe=recipe.yml
|
14
|
+
```
|
14
15
|
|
15
|
-
|
16
|
+
## Recipe
|
17
|
+
A recipe is the most fundamental configuration which defines the desired state of your server.
|
18
|
+
It is mostly a collection of resources, defined using certain patterns.
|
19
|
+
|
20
|
+
### Format
|
21
|
+
A recipe can be specified as a path to one of:
|
22
|
+
|
23
|
+
- JSON file
|
24
|
+
- YAML file named with \*.yaml or \*.yml
|
25
|
+
- Executable to output JSON
|
26
|
+
- Directory including recipe files recursively
|
27
|
+
|
28
|
+
```sh
|
16
29
|
serverkit apply --recipe=recipe.yml
|
30
|
+
serverkit apply --recipe=recipe.json
|
31
|
+
serverkit apply --recipe=recipe
|
32
|
+
serverkit apply --recipe=recipes/
|
17
33
|
```
|
18
34
|
|
19
35
|
### Example
|
36
|
+
This is an example recipe to install some packages, clone a git repository, and create a symlink.
|
37
|
+
|
20
38
|
```yaml
|
21
39
|
# recipe.yml
|
22
40
|
resources:
|
23
|
-
-
|
24
|
-
type:
|
25
|
-
|
26
|
-
-
|
27
|
-
type:
|
28
|
-
|
29
|
-
-
|
30
|
-
type: homebrew_cask
|
31
|
-
package: licecap
|
32
|
-
- name: install_alfred
|
33
|
-
type: homebrew_cask
|
34
|
-
package: alfred
|
35
|
-
- name: clone_dotfiles
|
41
|
+
- id: install_mysql
|
42
|
+
type: package
|
43
|
+
name: mysql
|
44
|
+
- id: install_redis
|
45
|
+
type: package
|
46
|
+
name: redis
|
47
|
+
- id: clone_dotfiles
|
36
48
|
type: git
|
37
49
|
repository: git@github.com:r7kamura/dotfiles.git
|
38
50
|
path: /Users/r7kamura/src/github.com/r7kamura/dotfiles
|
39
|
-
-
|
51
|
+
- id: symlink_zshrc
|
40
52
|
type: symlink
|
41
53
|
source: /Users/r7kamura/.zshrc
|
42
54
|
destination: /Users/r7kamura/src/github.com/r7kamura/dotfiles/linked/.zshrc
|
43
55
|
```
|
56
|
+
|
57
|
+
## Resource
|
58
|
+
A resource is a statement of configuration policy that describes the desired state for an item.
|
59
|
+
|
60
|
+
### Type
|
61
|
+
A resource must have a type property. Currently the following types are available:
|
62
|
+
|
63
|
+
- file
|
64
|
+
- git
|
65
|
+
- homebrew_cask
|
66
|
+
- homebrew
|
67
|
+
- package
|
68
|
+
- service
|
69
|
+
- symlink
|
70
|
+
|
71
|
+
### Example
|
72
|
+
An example package resource that has id, type, and name attributes.
|
73
|
+
|
74
|
+
```yaml
|
75
|
+
resources:
|
76
|
+
- id: install_mysql # id attirbute (This resource is identified by this unique id)
|
77
|
+
type: package # type attribute (Serverkit::Resources::Package class is used for this)
|
78
|
+
name: mysql # name attribute (package resource requires name attribute)
|
79
|
+
```
|
@@ -0,0 +1,48 @@
|
|
1
|
+
{
|
2
|
+
"hosts": [
|
3
|
+
"localhost"
|
4
|
+
],
|
5
|
+
"ssh": false,
|
6
|
+
"resources": [
|
7
|
+
{
|
8
|
+
"id": "install_mysql",
|
9
|
+
"type": "homebrew",
|
10
|
+
"name": "mysql"
|
11
|
+
},
|
12
|
+
{
|
13
|
+
"id": "install_redis",
|
14
|
+
"type": "homebrew",
|
15
|
+
"name": "redis"
|
16
|
+
},
|
17
|
+
{
|
18
|
+
"id": "install_licecap",
|
19
|
+
"type": "homebrew_cask",
|
20
|
+
"name": "licecap"
|
21
|
+
},
|
22
|
+
{
|
23
|
+
"id": "install_alfred",
|
24
|
+
"type": "homebrew_cask",
|
25
|
+
"name": "alfred"
|
26
|
+
},
|
27
|
+
{
|
28
|
+
"id": "clone_dotfiles",
|
29
|
+
"type": "git",
|
30
|
+
"repository": "git@github.com:r7kamura/dotfiles.git",
|
31
|
+
"path": "/Users/r7kamura/src/github.com/r7kamura/dotfiles"
|
32
|
+
},
|
33
|
+
{
|
34
|
+
"id": "symlink_zshrc",
|
35
|
+
"type": "symlink",
|
36
|
+
"source": "/Users/r7kamura/.zshrc",
|
37
|
+
"destination": "/Users/r7kamura/src/github.com/r7kamura/dotfiles/linked/.zshrc"
|
38
|
+
},
|
39
|
+
{
|
40
|
+
"id": "put_zshrc",
|
41
|
+
"type": "file",
|
42
|
+
"source": "/Users/r7kamura/src/github.com/r7kamura/dotfiles/linked/.zshrc",
|
43
|
+
"destination": "/Users/r7kamura/src/github.com/r7kamura/dotfiles/linked/.zshrc",
|
44
|
+
"user": "r7kamura",
|
45
|
+
"group": "staff"
|
46
|
+
}
|
47
|
+
]
|
48
|
+
}
|
data/examples/recipe.rb
ADDED
data/examples/recipe.yml
CHANGED
@@ -2,27 +2,27 @@ hosts:
|
|
2
2
|
- localhost
|
3
3
|
ssh: false
|
4
4
|
resources:
|
5
|
-
-
|
5
|
+
- id: install_mysql
|
6
6
|
type: homebrew
|
7
|
-
|
8
|
-
-
|
7
|
+
name: mysql
|
8
|
+
- id: install_redis
|
9
9
|
type: homebrew
|
10
|
-
|
11
|
-
-
|
10
|
+
name: redis
|
11
|
+
- id: install_licecap
|
12
12
|
type: homebrew_cask
|
13
|
-
|
14
|
-
-
|
13
|
+
name: licecap
|
14
|
+
- id: install_alfred
|
15
15
|
type: homebrew_cask
|
16
|
-
|
17
|
-
-
|
16
|
+
name: alfred
|
17
|
+
- id: clone_dotfiles
|
18
18
|
type: git
|
19
19
|
repository: git@github.com:r7kamura/dotfiles.git
|
20
20
|
path: /Users/r7kamura/src/github.com/r7kamura/dotfiles
|
21
|
-
-
|
21
|
+
- id: symlink_zshrc
|
22
22
|
type: symlink
|
23
23
|
source: /Users/r7kamura/.zshrc
|
24
24
|
destination: /Users/r7kamura/src/github.com/r7kamura/dotfiles/linked/.zshrc
|
25
|
-
-
|
25
|
+
- id: put_zshrc
|
26
26
|
type: file
|
27
27
|
source: /Users/r7kamura/src/github.com/r7kamura/dotfiles/linked/.zshrc
|
28
28
|
destination: /Users/r7kamura/src/github.com/r7kamura/dotfiles/linked/.zshrc
|
@@ -7,13 +7,13 @@ module Serverkit
|
|
7
7
|
recipe.resources.each do |resource|
|
8
8
|
resource.backend = backend
|
9
9
|
if resource.check
|
10
|
-
puts "[SKIP] #{resource.
|
10
|
+
puts "[SKIP] #{resource.id}"
|
11
11
|
else
|
12
12
|
resource.apply
|
13
13
|
if resource.check
|
14
|
-
puts "[DONE] #{resource.
|
14
|
+
puts "[DONE] #{resource.id}"
|
15
15
|
else
|
16
|
-
puts "[FAIL] #{resource.
|
16
|
+
puts "[FAIL] #{resource.id}"
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "serverkit/recipe"
|
2
|
+
require "serverkit/recipe_loader"
|
2
3
|
require "specinfra"
|
3
4
|
|
4
5
|
module Serverkit
|
@@ -31,7 +32,7 @@ module Serverkit
|
|
31
32
|
|
32
33
|
# @return [Serverkit::Recipe]
|
33
34
|
def recipe
|
34
|
-
@recipe ||=
|
35
|
+
@recipe ||= RecipeLoader.new(@options[:recipe]).load
|
35
36
|
end
|
36
37
|
end
|
37
38
|
end
|
data/lib/serverkit/recipe.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require "active_support/core_ext/hash/deep_merge"
|
1
2
|
require "active_support/core_ext/string/inflections"
|
2
3
|
require "serverkit/errors/invalid_recipe_type"
|
3
4
|
require "serverkit/errors/invalid_resources_type"
|
@@ -5,23 +6,16 @@ require "serverkit/resources/file"
|
|
5
6
|
require "serverkit/resources/git"
|
6
7
|
require "serverkit/resources/homebrew"
|
7
8
|
require "serverkit/resources/homebrew_cask"
|
9
|
+
require "serverkit/resources/service"
|
8
10
|
require "serverkit/resources/symlink"
|
9
11
|
require "yaml"
|
10
12
|
|
11
13
|
module Serverkit
|
12
14
|
class Recipe
|
13
|
-
class << self
|
14
|
-
# @param [String] path
|
15
|
-
def load_from_path(path)
|
16
|
-
recipe_data = YAML.load_file(path)
|
17
|
-
new(recipe_data)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
15
|
attr_reader :recipe_data
|
22
16
|
|
23
17
|
# @param [Hash] recipe_data
|
24
|
-
def initialize(recipe_data)
|
18
|
+
def initialize(recipe_data = {})
|
25
19
|
@recipe_data = recipe_data
|
26
20
|
end
|
27
21
|
|
@@ -44,6 +38,20 @@ module Serverkit
|
|
44
38
|
@recipe_data["hosts"]
|
45
39
|
end
|
46
40
|
|
41
|
+
# @param [Serverkit::Recipe] recipe
|
42
|
+
# @return [Serverkit::Recipe]
|
43
|
+
def merge(recipe)
|
44
|
+
self.class.new(
|
45
|
+
recipe_data.deep_merge(recipe.recipe_data) do |key, a, b|
|
46
|
+
if a.is_a?(Array)
|
47
|
+
a | b
|
48
|
+
else
|
49
|
+
b
|
50
|
+
end
|
51
|
+
end
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
47
55
|
# @return [Array<Serverkit::Resources::Base>]
|
48
56
|
# @todo Delegate to resource builder
|
49
57
|
def resources
|
@@ -89,9 +97,9 @@ module Serverkit
|
|
89
97
|
@recipe_data.is_a?(Hash)
|
90
98
|
end
|
91
99
|
|
92
|
-
# @return [Array<String
|
100
|
+
# @return [Array<String>, nil]
|
93
101
|
def resources_property
|
94
|
-
@recipe_data["resources"]
|
102
|
+
@recipe_data["resources"]
|
95
103
|
end
|
96
104
|
end
|
97
105
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
module Serverkit
|
4
|
+
class RecipeLoader
|
5
|
+
YAML_EXTNAMES = [".yaml", ".yml"]
|
6
|
+
|
7
|
+
# @param [String] path
|
8
|
+
def initialize(path)
|
9
|
+
@path = path
|
10
|
+
end
|
11
|
+
|
12
|
+
# @todo Care Error::ENOENT error
|
13
|
+
# @return [Serverkit::Recipe]
|
14
|
+
def load
|
15
|
+
if has_directory_path?
|
16
|
+
load_recipe_from_directory
|
17
|
+
else
|
18
|
+
Recipe.new(load_data)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# @return [String] This executable must print reicpe in JSON format into standard output
|
25
|
+
def execute
|
26
|
+
`#{@path}`
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [String]
|
30
|
+
def extname
|
31
|
+
@extname ||= File.extname(@path)
|
32
|
+
end
|
33
|
+
|
34
|
+
def has_directory_path?
|
35
|
+
File.directory?(@path)
|
36
|
+
end
|
37
|
+
|
38
|
+
def has_executable_path?
|
39
|
+
File.executable?(@path)
|
40
|
+
end
|
41
|
+
|
42
|
+
def has_yaml_path?
|
43
|
+
YAML_EXTNAMES.include?(extname)
|
44
|
+
end
|
45
|
+
|
46
|
+
def load_data
|
47
|
+
case
|
48
|
+
when has_executable_path?
|
49
|
+
load_data_from_executable
|
50
|
+
when has_yaml_path?
|
51
|
+
load_data_from_yaml
|
52
|
+
else
|
53
|
+
load_data_from_json
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def load_recipe_from_directory
|
58
|
+
load_recipes_from_directory.inject(Recipe.new, :merge)
|
59
|
+
end
|
60
|
+
|
61
|
+
def load_recipes_from_directory
|
62
|
+
Dir.glob(File.join(@path, "*")).sort.flat_map do |path|
|
63
|
+
self.class.new(path).load
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def load_data_from_executable
|
68
|
+
JSON.parse(execute)
|
69
|
+
end
|
70
|
+
|
71
|
+
def load_data_from_json
|
72
|
+
JSON.parse(File.read(@path))
|
73
|
+
end
|
74
|
+
|
75
|
+
def load_data_from_yaml
|
76
|
+
YAML.load_file(@path)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -1,4 +1,7 @@
|
|
1
1
|
require "active_model"
|
2
|
+
require "readable_validator"
|
3
|
+
require "required_validator"
|
4
|
+
require "type_validator"
|
2
5
|
|
3
6
|
module Serverkit
|
4
7
|
module Resources
|
@@ -18,7 +21,7 @@ module Serverkit
|
|
18
21
|
|
19
22
|
attr_accessor :backend
|
20
23
|
|
21
|
-
attribute :
|
24
|
+
attribute :id, required: true, type: String
|
22
25
|
|
23
26
|
# @param [Hash] attributes
|
24
27
|
def initialize(attributes)
|
@@ -1,15 +1,13 @@
|
|
1
1
|
require "digest"
|
2
|
-
require "readable_validator"
|
3
|
-
require "required_validator"
|
4
2
|
require "serverkit/resources/base"
|
5
3
|
|
6
4
|
module Serverkit
|
7
5
|
module Resources
|
8
6
|
class File < Base
|
9
|
-
attribute :destination, required: true
|
10
|
-
attribute :group
|
11
|
-
attribute :owner
|
12
|
-
attribute :source, readable: true, required: true
|
7
|
+
attribute :destination, required: true, type: String
|
8
|
+
attribute :group, type: String
|
9
|
+
attribute :owner, type: String
|
10
|
+
attribute :source, readable: true, required: true, type: String
|
13
11
|
|
14
12
|
def apply
|
15
13
|
send_file if file_sendable?
|
@@ -5,9 +5,9 @@ module Serverkit
|
|
5
5
|
class Git < Base
|
6
6
|
DEFAULT_STATUS = "cloned"
|
7
7
|
|
8
|
-
attribute :path, required: true
|
9
|
-
attribute :repository, required: true
|
10
|
-
attribute :status, default: DEFAULT_STATUS
|
8
|
+
attribute :path, required: true, type: String
|
9
|
+
attribute :repository, required: true, type: String
|
10
|
+
attribute :status, default: DEFAULT_STATUS, type: String
|
11
11
|
|
12
12
|
def apply
|
13
13
|
clone if clonable?
|
@@ -3,15 +3,15 @@ require "serverkit/resources/base"
|
|
3
3
|
module Serverkit
|
4
4
|
module Resources
|
5
5
|
class HomebrewCask < Base
|
6
|
-
attribute :
|
6
|
+
attribute :name, required: true, type: String
|
7
7
|
|
8
8
|
def apply
|
9
|
-
run_command("brew cask install #{
|
9
|
+
run_command("brew cask install #{name}")
|
10
10
|
end
|
11
11
|
|
12
12
|
# @return [true, false]
|
13
13
|
def check
|
14
|
-
check_command("/usr/local/bin/brew cask list -1 | grep -E '^#{
|
14
|
+
check_command("/usr/local/bin/brew cask list -1 | grep -E '^#{name}$'")
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -3,15 +3,15 @@ require "serverkit/resources/base"
|
|
3
3
|
module Serverkit
|
4
4
|
module Resources
|
5
5
|
class Package < Base
|
6
|
-
attribute :
|
6
|
+
attribute :name, required: true, type: String
|
7
7
|
|
8
8
|
def apply
|
9
|
-
run_command_from_identifier(:install,
|
9
|
+
run_command_from_identifier(:install, name)
|
10
10
|
end
|
11
11
|
|
12
12
|
# @return [true, false]
|
13
13
|
def check
|
14
|
-
check_command_from_identifier(:check_package_is_installed,
|
14
|
+
check_command_from_identifier(:check_package_is_installed, name)
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "serverkit/resources/base"
|
2
|
+
|
3
|
+
module Serverkit
|
4
|
+
module Resources
|
5
|
+
class Service < Base
|
6
|
+
attribute :name, required: true, type: String
|
7
|
+
|
8
|
+
def apply
|
9
|
+
run_command_from_identifier(:start, name)
|
10
|
+
end
|
11
|
+
|
12
|
+
def check
|
13
|
+
check_command_from_identifier(:check_service_is_running, name)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -3,8 +3,8 @@ require "serverkit/resources/base"
|
|
3
3
|
module Serverkit
|
4
4
|
module Resources
|
5
5
|
class Symlink < Base
|
6
|
-
attribute :destination, required: true
|
7
|
-
attribute :source, required: true
|
6
|
+
attribute :destination, required: true, type: String
|
7
|
+
attribute :source, required: true, type: String
|
8
8
|
|
9
9
|
def apply
|
10
10
|
run_command_from_identifier(:link_file_to, source, destination)
|
data/lib/serverkit/version.rb
CHANGED
@@ -0,0 +1,13 @@
|
|
1
|
+
require "active_model"
|
2
|
+
|
3
|
+
class TypeValidator < ActiveModel::EachValidator
|
4
|
+
def options
|
5
|
+
super.merge(allow_nil: true)
|
6
|
+
end
|
7
|
+
|
8
|
+
def validate_each(record, attribute, value)
|
9
|
+
unless value.is_a?(options[:with])
|
10
|
+
record.errors.add(attribute, "must be a #{options[:with]}, not #{value.class}")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: serverkit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryo Nakamura
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -154,6 +154,8 @@ files:
|
|
154
154
|
- README.md
|
155
155
|
- Rakefile
|
156
156
|
- bin/serverkit
|
157
|
+
- examples/recipe.json
|
158
|
+
- examples/recipe.rb
|
157
159
|
- examples/recipe.yml
|
158
160
|
- lib/readable_validator.rb
|
159
161
|
- lib/required_validator.rb
|
@@ -167,14 +169,17 @@ files:
|
|
167
169
|
- lib/serverkit/errors/invalid_recipe_type.rb
|
168
170
|
- lib/serverkit/errors/invalid_resources_type.rb
|
169
171
|
- lib/serverkit/recipe.rb
|
172
|
+
- lib/serverkit/recipe_loader.rb
|
170
173
|
- lib/serverkit/resources/base.rb
|
171
174
|
- lib/serverkit/resources/file.rb
|
172
175
|
- lib/serverkit/resources/git.rb
|
173
176
|
- lib/serverkit/resources/homebrew.rb
|
174
177
|
- lib/serverkit/resources/homebrew_cask.rb
|
175
178
|
- lib/serverkit/resources/package.rb
|
179
|
+
- lib/serverkit/resources/service.rb
|
176
180
|
- lib/serverkit/resources/symlink.rb
|
177
181
|
- lib/serverkit/version.rb
|
182
|
+
- lib/type_validator.rb
|
178
183
|
- serverkit.gemspec
|
179
184
|
homepage: https://github.com/r7kamura/serverkit
|
180
185
|
licenses:
|