hammer_cli 0.0.18 → 0.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 +4 -4
- data/README.md +3 -314
- data/bin/hammer +45 -6
- data/config/cli.modules.d/module_config_template.yml +4 -0
- data/config/cli_config.template.yml +9 -11
- data/doc/developer_docs.md +1 -0
- data/doc/i18n.md +85 -0
- data/doc/installation.md +321 -0
- data/lib/hammer_cli.rb +3 -0
- data/lib/hammer_cli/abstract.rb +15 -24
- data/lib/hammer_cli/apipie/command.rb +13 -7
- data/lib/hammer_cli/apipie/options.rb +14 -16
- data/lib/hammer_cli/apipie/read_command.rb +6 -1
- data/lib/hammer_cli/apipie/resource.rb +48 -58
- data/lib/hammer_cli/apipie/write_command.rb +5 -1
- data/lib/hammer_cli/completer.rb +77 -21
- data/lib/hammer_cli/connection.rb +44 -0
- data/lib/hammer_cli/exception_handler.rb +15 -4
- data/lib/hammer_cli/exceptions.rb +6 -0
- data/lib/hammer_cli/i18n.rb +95 -0
- data/lib/hammer_cli/logger.rb +3 -3
- data/lib/hammer_cli/main.rb +12 -11
- data/lib/hammer_cli/modules.rb +19 -6
- data/lib/hammer_cli/options/normalizers.rb +42 -7
- data/lib/hammer_cli/options/option_definition.rb +2 -2
- data/lib/hammer_cli/output.rb +1 -0
- data/lib/hammer_cli/output/adapter/abstract.rb +20 -0
- data/lib/hammer_cli/output/adapter/base.rb +49 -78
- data/lib/hammer_cli/output/adapter/csv.rb +5 -5
- data/lib/hammer_cli/output/adapter/table.rb +41 -10
- data/lib/hammer_cli/output/dsl.rb +1 -1
- data/lib/hammer_cli/output/field_filter.rb +21 -0
- data/lib/hammer_cli/output/fields.rb +44 -78
- data/lib/hammer_cli/output/formatters.rb +38 -0
- data/lib/hammer_cli/settings.rb +28 -6
- data/lib/hammer_cli/shell.rb +58 -57
- data/lib/hammer_cli/utils.rb +14 -0
- data/lib/hammer_cli/validator.rb +5 -5
- data/lib/hammer_cli/version.rb +1 -1
- data/locale/Makefile +64 -0
- data/locale/hammer-cli.pot +203 -0
- data/locale/zanata.xml +29 -0
- data/test/unit/apipie/command_test.rb +42 -25
- data/test/unit/apipie/read_command_test.rb +10 -7
- data/test/unit/apipie/write_command_test.rb +9 -8
- data/test/unit/completer_test.rb +206 -21
- data/test/unit/connection_test.rb +68 -0
- data/test/unit/fixtures/apipie/architectures.json +153 -0
- data/test/unit/fixtures/apipie/documented.json +79 -0
- data/test/unit/fixtures/json_input/invalid.json +12 -0
- data/test/unit/fixtures/json_input/valid.json +12 -0
- data/test/unit/history_test.rb +71 -0
- data/test/unit/main_test.rb +9 -0
- data/test/unit/modules_test.rb +22 -6
- data/test/unit/options/field_filter_test.rb +27 -0
- data/test/unit/options/normalizers_test.rb +53 -0
- data/test/unit/output/adapter/base_test.rb +162 -10
- data/test/unit/output/adapter/csv_test.rb +16 -3
- data/test/unit/output/adapter/table_test.rb +97 -13
- data/test/unit/output/dsl_test.rb +74 -6
- data/test/unit/output/fields_test.rb +93 -62
- data/test/unit/output/formatters_test.rb +47 -0
- data/test/unit/settings_test.rb +35 -4
- data/test/unit/utils_test.rb +45 -0
- metadata +85 -4
- data/test/unit/apipie/fake_api.rb +0 -101
@@ -0,0 +1,68 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
describe HammerCLI::Connection do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
# clean up global settings
|
7
|
+
HammerCLI::Connection.drop_all
|
8
|
+
HammerCLI::Settings.load({:_params => {:interactive => false}})
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:connection) { HammerCLI::Connection }
|
12
|
+
|
13
|
+
class Connector < HammerCLI::AbstractConnector
|
14
|
+
|
15
|
+
attr_reader :url
|
16
|
+
|
17
|
+
def initialize(params)
|
18
|
+
@url = params[:url]
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return the conection" do
|
25
|
+
conn = connection.create(:test, {})
|
26
|
+
conn.must_be_kind_of HammerCLI::AbstractConnector
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should create the connection only once" do
|
30
|
+
conn1 = connection.create(:test, {})
|
31
|
+
conn2 = connection.create(:test, {})
|
32
|
+
conn1.must_equal conn2
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should test the connection" do
|
36
|
+
connection.exist?(:test).must_equal false
|
37
|
+
conn1 = connection.create(:test, {})
|
38
|
+
connection.exist?(:test).must_equal true
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should get the connection" do
|
42
|
+
conn1 = connection.create(:test, {})
|
43
|
+
conn2 = connection.get(:test)
|
44
|
+
conn1.must_equal conn2
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
it "should be able to drop all" do
|
49
|
+
conn1 = connection.create(:test, {})
|
50
|
+
connection.drop_all
|
51
|
+
conn2 = connection.create(:test, {})
|
52
|
+
conn1.wont_equal conn2 # TODO
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should drop the connection" do
|
56
|
+
conn1 = connection.create(:test, {})
|
57
|
+
connection.drop(:test)
|
58
|
+
conn2 = connection.create(:test, {})
|
59
|
+
conn1.wont_equal conn2
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should accept custom connector" do
|
63
|
+
conn = connection.create(:test, {:url => 'URL'}, :connector => Connector)
|
64
|
+
conn.must_be_kind_of Connector
|
65
|
+
conn.url.must_equal 'URL'
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
{
|
2
|
+
"docs": {
|
3
|
+
"api_url": "/api",
|
4
|
+
"copyright": "",
|
5
|
+
"doc_url": "/apidoc/v2",
|
6
|
+
"info": "Another API description",
|
7
|
+
"name": "Foreman",
|
8
|
+
"resources": {
|
9
|
+
"architectures": {
|
10
|
+
"api_url": "/api",
|
11
|
+
"doc_url": "/apidoc/v2/architectures",
|
12
|
+
"formats": null,
|
13
|
+
"full_description": null,
|
14
|
+
"methods": [
|
15
|
+
{
|
16
|
+
"apis": [
|
17
|
+
{
|
18
|
+
"api_url": "/api/architectures",
|
19
|
+
"http_method": "GET",
|
20
|
+
"short_description": "List all architectures."
|
21
|
+
}
|
22
|
+
],
|
23
|
+
"doc_url": "/apidoc/v2/architectures/index",
|
24
|
+
"errors": [],
|
25
|
+
"examples": [
|
26
|
+
"GET /api/architectures\n200\n[\n {\n \"architecture\": {\n \"name\": \"s390\",\n \"id\": 381564594,\n \"updated_at\": \"2012-12-18T15:24:42Z\",\n \"operatingsystem_ids\": [],\n \"created_at\": \"2012-12-18T15:24:42Z\"\n }\n },\n {\n \"architecture\": {\n \"name\": \"sparc\",\n \"id\": 331892513,\n \"updated_at\": \"2012-12-18T15:24:42Z\",\n \"operatingsystem_ids\": [\n 442321401\n ],\n \"created_at\": \"2012-12-18T15:24:42Z\"\n }\n },\n {\n \"architecture\": {\n \"name\": \"x86_64\",\n \"id\": 501905019,\n \"updated_at\": \"2012-12-18T15:24:42Z\",\n \"operatingsystem_ids\": [\n 331303656,\n 309172073,\n 1073012828\n ],\n \"created_at\": \"2012-12-18T15:24:42Z\"\n }\n }\n]"
|
27
|
+
],
|
28
|
+
"formats": null,
|
29
|
+
"full_description": "",
|
30
|
+
"name": "index",
|
31
|
+
"params": [
|
32
|
+
{
|
33
|
+
"allow_nil": false,
|
34
|
+
"description": "\n<p>filter results</p>\n",
|
35
|
+
"expected_type": "string",
|
36
|
+
"full_name": "search",
|
37
|
+
"name": "search",
|
38
|
+
"required": false,
|
39
|
+
"validator": "Must be String"
|
40
|
+
},
|
41
|
+
{
|
42
|
+
"allow_nil": false,
|
43
|
+
"description": "\n<p>sort results</p>\n",
|
44
|
+
"expected_type": "string",
|
45
|
+
"full_name": "order",
|
46
|
+
"name": "order",
|
47
|
+
"required": false,
|
48
|
+
"validator": "Must be String"
|
49
|
+
},
|
50
|
+
{
|
51
|
+
"allow_nil": false,
|
52
|
+
"description": "\n<p>paginate results</p>\n",
|
53
|
+
"expected_type": "string",
|
54
|
+
"full_name": "page",
|
55
|
+
"name": "page",
|
56
|
+
"required": false,
|
57
|
+
"validator": "Must be String"
|
58
|
+
},
|
59
|
+
{
|
60
|
+
"allow_nil": false,
|
61
|
+
"description": "\n<p>number of entries per request</p>\n",
|
62
|
+
"expected_type": "string",
|
63
|
+
"full_name": "per_page",
|
64
|
+
"name": "per_page",
|
65
|
+
"required": false,
|
66
|
+
"validator": "Must be String"
|
67
|
+
}
|
68
|
+
],
|
69
|
+
"see": []
|
70
|
+
},
|
71
|
+
{
|
72
|
+
"apis": [
|
73
|
+
{
|
74
|
+
"api_url": "/api/architectures/:id",
|
75
|
+
"http_method": "GET",
|
76
|
+
"short_description": "Show an architecture."
|
77
|
+
}
|
78
|
+
],
|
79
|
+
"doc_url": "/apidoc/v2/architectures/show",
|
80
|
+
"errors": [],
|
81
|
+
"examples": [
|
82
|
+
"GET /api/architectures/x86_64\n200\n{\n \"architecture\": {\n \"name\": \"x86_64\",\n \"id\": 501905019,\n \"updated_at\": \"2012-12-18T15:24:42Z\",\n \"operatingsystem_ids\": [\n 309172073,\n 1073012828,\n 331303656\n ],\n \"created_at\": \"2012-12-18T15:24:42Z\"\n }\n}"
|
83
|
+
],
|
84
|
+
"formats": null,
|
85
|
+
"full_description": "",
|
86
|
+
"name": "show",
|
87
|
+
"params": [
|
88
|
+
{
|
89
|
+
"allow_nil": false,
|
90
|
+
"description": "",
|
91
|
+
"expected_type": "string",
|
92
|
+
"full_name": "id",
|
93
|
+
"name": "id",
|
94
|
+
"required": true,
|
95
|
+
"validator": "Must be an identifier, string from 1 to 128 characters containing only alphanumeric characters, space, underscore(_), hypen(-) with no leading or trailing space."
|
96
|
+
}
|
97
|
+
],
|
98
|
+
"see": []
|
99
|
+
},
|
100
|
+
{
|
101
|
+
"apis": [
|
102
|
+
{
|
103
|
+
"api_url": "/api/architectures",
|
104
|
+
"http_method": "POST",
|
105
|
+
"short_description": "Create an architecture."
|
106
|
+
}
|
107
|
+
],
|
108
|
+
"doc_url": "/apidoc/v2/architectures/create",
|
109
|
+
"errors": [],
|
110
|
+
"examples": [
|
111
|
+
"POST /api/architectures\n{\n \"architecture\": {\n \"name\": \"i386\"\n }\n}\n200\n{\n \"architecture\": {\n \"name\": \"i386\",\n \"id\": 501905020,\n \"updated_at\": \"2012-12-18T15:24:43Z\",\n \"operatingsystem_ids\": [],\n \"created_at\": \"2012-12-18T15:24:43Z\"\n }\n}"
|
112
|
+
],
|
113
|
+
"formats": null,
|
114
|
+
"full_description": "",
|
115
|
+
"name": "create",
|
116
|
+
"params": [
|
117
|
+
{
|
118
|
+
"allow_nil": false,
|
119
|
+
"description": "",
|
120
|
+
"expected_type": "hash",
|
121
|
+
"full_name": "architecture",
|
122
|
+
"name": "architecture",
|
123
|
+
"params": [
|
124
|
+
{
|
125
|
+
"allow_nil": false,
|
126
|
+
"description": "",
|
127
|
+
"expected_type": "string",
|
128
|
+
"full_name": "architecture[name]",
|
129
|
+
"name": "name",
|
130
|
+
"required": true,
|
131
|
+
"validator": "Must be String"
|
132
|
+
},
|
133
|
+
{
|
134
|
+
"allow_nil": false,
|
135
|
+
"description": "\n<p>Operatingsystem ID\u2019s</p>\n",
|
136
|
+
"expected_type": "array",
|
137
|
+
"full_name": "architecture[operatingsystem_ids]",
|
138
|
+
"name": "operatingsystem_ids",
|
139
|
+
"required": false,
|
140
|
+
"validator": "Must be Array"
|
141
|
+
}
|
142
|
+
],
|
143
|
+
"required": true,
|
144
|
+
"validator": "Must be a Hash"
|
145
|
+
}
|
146
|
+
],
|
147
|
+
"see": []
|
148
|
+
}
|
149
|
+
]
|
150
|
+
}
|
151
|
+
}
|
152
|
+
}
|
153
|
+
}
|
@@ -0,0 +1,79 @@
|
|
1
|
+
{
|
2
|
+
"docs": {
|
3
|
+
"name": "Documented",
|
4
|
+
"api_url": "/api",
|
5
|
+
"version": "v2",
|
6
|
+
"short_description": null,
|
7
|
+
"full_description": null,
|
8
|
+
"doc_url": "/apidoc/v2/documented",
|
9
|
+
"resources": {
|
10
|
+
"documented": {
|
11
|
+
"methods": [
|
12
|
+
{
|
13
|
+
"name": "index",
|
14
|
+
"examples": [],
|
15
|
+
"errors": [],
|
16
|
+
"params": [
|
17
|
+
{
|
18
|
+
"allow_null": false,
|
19
|
+
"name": "se_arch_val-ue",
|
20
|
+
"full_name": "se_arch_val-ue_full_name",
|
21
|
+
"validator": "Must be String",
|
22
|
+
"description": "<p>filter results</p>",
|
23
|
+
"expected_type": "string",
|
24
|
+
"required": false
|
25
|
+
}
|
26
|
+
],
|
27
|
+
"full_description": ""
|
28
|
+
},
|
29
|
+
{
|
30
|
+
"name": "create",
|
31
|
+
"examples": [],
|
32
|
+
"errors": [],
|
33
|
+
"params": [
|
34
|
+
{
|
35
|
+
"allow_null": false,
|
36
|
+
"name": "documented",
|
37
|
+
"full_name": "documented",
|
38
|
+
"validator": "Must be a Hash",
|
39
|
+
"description": "",
|
40
|
+
"expected_type": "hash",
|
41
|
+
"required": true,
|
42
|
+
"params": [
|
43
|
+
{
|
44
|
+
"name": "name",
|
45
|
+
"allow_null": false,
|
46
|
+
"full_name": "documented[name]",
|
47
|
+
"validator": "Must be String",
|
48
|
+
"expected_type": "string",
|
49
|
+
"description": "",
|
50
|
+
"required": false
|
51
|
+
},
|
52
|
+
{
|
53
|
+
"name": "provider",
|
54
|
+
"allow_null": false,
|
55
|
+
"full_name": "documented[provider]",
|
56
|
+
"validator": "Must be String",
|
57
|
+
"expected_type": "string",
|
58
|
+
"description": "<p>Providers include Libvirt, Ovirt, EC2, Vmware, Openstack, Rackspace</p>",
|
59
|
+
"required": false
|
60
|
+
},
|
61
|
+
{
|
62
|
+
"name": "array_param",
|
63
|
+
"allow_null": false,
|
64
|
+
"full_name": "documented[array_param]",
|
65
|
+
"validator": "Must be Array",
|
66
|
+
"expected_type": "string",
|
67
|
+
"description": "",
|
68
|
+
"required": true
|
69
|
+
}
|
70
|
+
]
|
71
|
+
}
|
72
|
+
],
|
73
|
+
"full_description": ""
|
74
|
+
}
|
75
|
+
]
|
76
|
+
}
|
77
|
+
}
|
78
|
+
}
|
79
|
+
}
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
describe HammerCLI::ShellHistory do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
# Readline::HISOTRY does not implement #clear in Ruby 1.8
|
7
|
+
while not Readline::HISTORY.empty?
|
8
|
+
Readline::HISTORY.pop
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
let :history_file do
|
13
|
+
file = Tempfile.new('history')
|
14
|
+
file.puts "line 1"
|
15
|
+
file.puts "line 2"
|
16
|
+
file.close
|
17
|
+
file
|
18
|
+
end
|
19
|
+
|
20
|
+
let :new_file do
|
21
|
+
Tempfile.new('history')
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "loading old history" do
|
25
|
+
|
26
|
+
it "skips loading if the file does not exist" do
|
27
|
+
history = HammerCLI::ShellHistory.new(new_file.path)
|
28
|
+
|
29
|
+
Readline::HISTORY.to_a.must_equal []
|
30
|
+
end
|
31
|
+
|
32
|
+
it "preseeds readline's history" do
|
33
|
+
history = HammerCLI::ShellHistory.new(history_file.path)
|
34
|
+
|
35
|
+
Readline::HISTORY.to_a.must_equal ["line 1", "line 2"]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "saving history" do
|
40
|
+
it "creates history file if it does not exist" do
|
41
|
+
history = HammerCLI::ShellHistory.new(new_file.path)
|
42
|
+
history.push("some command ")
|
43
|
+
|
44
|
+
File.exist?(new_file.path).must_equal true
|
45
|
+
end
|
46
|
+
|
47
|
+
it "appends history to the given file" do
|
48
|
+
history = HammerCLI::ShellHistory.new(new_file.path)
|
49
|
+
history.push("some command ")
|
50
|
+
history.push("another command ")
|
51
|
+
|
52
|
+
new_file.read.must_equal "some command\nanother command\n"
|
53
|
+
end
|
54
|
+
|
55
|
+
it "appends to readline's history" do
|
56
|
+
history = HammerCLI::ShellHistory.new(history_file.path)
|
57
|
+
history.push("line 3")
|
58
|
+
|
59
|
+
Readline::HISTORY.to_a.must_equal ["line 1", "line 2", "line 3"]
|
60
|
+
end
|
61
|
+
|
62
|
+
it "doesn't save exit command" do
|
63
|
+
history = HammerCLI::ShellHistory.new(history_file.path)
|
64
|
+
history.push("exit ")
|
65
|
+
|
66
|
+
Readline::HISTORY.to_a.must_equal ["line 1", "line 2"]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
data/test/unit/main_test.rb
CHANGED
data/test/unit/modules_test.rb
CHANGED
@@ -18,7 +18,8 @@ describe HammerCLI::Modules do
|
|
18
18
|
before :each do
|
19
19
|
HammerCLI::Settings.clear
|
20
20
|
HammerCLI::Settings.load({
|
21
|
-
:
|
21
|
+
:tom => { :enable_module => true },
|
22
|
+
:jerry => { :enable_module => true },
|
22
23
|
})
|
23
24
|
|
24
25
|
@log_output = Logging::Appenders['__test__']
|
@@ -27,13 +28,22 @@ describe HammerCLI::Modules do
|
|
27
28
|
|
28
29
|
describe "names" do
|
29
30
|
it "must return list of modules" do
|
30
|
-
HammerCLI::Modules.names.must_equal ["hammer_cli_tom", "hammer_cli_jerry"]
|
31
|
+
HammerCLI::Modules.names.sort.must_equal ["hammer_cli_tom", "hammer_cli_jerry"].sort
|
31
32
|
end
|
32
33
|
|
33
34
|
it "must return empty array by default" do
|
34
35
|
HammerCLI::Settings.clear
|
35
36
|
HammerCLI::Modules.names.must_equal []
|
36
37
|
end
|
38
|
+
|
39
|
+
it "must work with old modules config" do
|
40
|
+
HammerCLI::Settings.clear
|
41
|
+
HammerCLI::Settings.load({
|
42
|
+
:tom => {},
|
43
|
+
:modules => ['hammer_cli_tom', 'hammer_cli_jerry'],
|
44
|
+
})
|
45
|
+
HammerCLI::Modules.names.sort.must_equal ["hammer_cli_tom", "hammer_cli_jerry"].sort
|
46
|
+
end
|
37
47
|
end
|
38
48
|
|
39
49
|
describe "find by name" do
|
@@ -89,21 +99,27 @@ describe HammerCLI::Modules do
|
|
89
99
|
describe "module not found" do
|
90
100
|
before :each do
|
91
101
|
HammerCLI::Modules.stubs(:require_module).raises(LoadError)
|
92
|
-
@error_msg = "ERROR Modules :
|
102
|
+
@error_msg = "ERROR Modules : Error while loading module hammer_cli_tom"
|
93
103
|
end
|
94
104
|
|
95
105
|
it "must log an error if the load! fails" do
|
96
|
-
|
106
|
+
capture_io do
|
107
|
+
proc { HammerCLI::Modules.load!("hammer_cli_tom") }.must_raise LoadError
|
108
|
+
end
|
97
109
|
@log_output.readline.strip.must_equal @error_msg
|
98
110
|
end
|
99
111
|
|
100
112
|
it "must log an error if the load fails" do
|
101
|
-
|
113
|
+
capture_io do
|
114
|
+
HammerCLI::Modules.load("hammer_cli_tom")
|
115
|
+
end
|
102
116
|
@log_output.readline.strip.must_equal @error_msg
|
103
117
|
end
|
104
118
|
|
105
119
|
it "must return false when load fails" do
|
106
|
-
|
120
|
+
capture_io do
|
121
|
+
HammerCLI::Modules.load("hammer_cli_tom").must_equal false
|
122
|
+
end
|
107
123
|
end
|
108
124
|
end
|
109
125
|
|