serverkit 0.0.2 → 0.0.3
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/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:
|