rakit 0.1.5 → 0.1.6

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
  SHA256:
3
- metadata.gz: 4cf9325de6845aa1235b153b42503a92c8604f447a6e6e402c891412a1157905
4
- data.tar.gz: ce566e52e4889d22eb42dff316fa989b414d34f4d0b14d9595b509e5913c702f
3
+ metadata.gz: 7270ecd6c8ca0f035dde641cc2c8713a9907f93fa837099b8b4bb5e96be528ac
4
+ data.tar.gz: eb0c02cd74eaa13bf8b9a3f4a6ac22506267c123138a0f718c9450c7f457432d
5
5
  SHA512:
6
- metadata.gz: c8da52aef46f781cdf227fc0494047bdbf64869ce7dea91797ca8a79f61d41fd3a490fdb332b10413b0b2be292c2f00e0b8c2703b944eeb57779a3a517327d94
7
- data.tar.gz: c9c856269882482e5e9f838e5f1f7ca89ca2ea951296cc0b24f46b642b641277bab3f833e38f670f00ad1b878cb14a678986c15b80db6a3029c0e6e1033a309d
6
+ metadata.gz: b83885ba425b9bef93ddc077a442da2ae567dd5986a7d7fc9260e3e09d5f05ff576d628c51ecdb8a70bd96766d6e9d6ec51c8fd7868014424aa537b45c41cec6
7
+ data.tar.gz: c520af4a3530456192f317e13f1b8f4d842d71be2eee8570a5d50047c389507288fff144536c089f10dcbd6d62ee58c5b90e506f715fbe6430dcb4502c2fac10
data/exe/rakit CHANGED
@@ -14,17 +14,28 @@ def usage_stderr(msg = nil)
14
14
  $stderr.puts " file list <directory> [--recursive] [--include-hidden] [--format console|json|proto-json]"
15
15
  $stderr.puts " file copy <source> <destination> [--overwrite] [--create-directories] [--format ...]"
16
16
  $stderr.puts " word-count <file>|--stdin --json-keys [--format console|json|proto-json] [options]"
17
- $stderr.puts " static-web-server <start|stop|running|publish> [options] [args]"
17
+ $stderr.puts " static-web-server <start|stop|running|publish|view> [options] [args]"
18
18
  $stderr.puts " start [--port PORT] Start server (idempotent)"
19
19
  $stderr.puts " stop Stop server"
20
20
  $stderr.puts " running Exit 0 if running, non-zero otherwise"
21
21
  $stderr.puts " publish <site_name> <source_dir> Publish static site"
22
+ $stderr.puts " view [path] Open path in browser (default /)"
22
23
  end
23
24
 
24
25
  def main(argv = ARGV)
25
26
  return usage_stderr("Expected subcommand.") if argv.empty?
26
27
 
27
28
  sub = argv[0]
29
+ if sub == "--version" || sub == "-v"
30
+ spec = Gem.loaded_specs["rakit"]
31
+ puts spec ? "#{spec.name} #{spec.version}" : "rakit (version unknown)"
32
+ return 0
33
+ end
34
+ if sub == "--help" || sub == "-h"
35
+ usage_stderr
36
+ return 0
37
+ end
38
+
28
39
  if sub == "file"
29
40
  argv.shift
30
41
  require "rakit/cli/file"
@@ -53,6 +64,7 @@ def main(argv = ARGV)
53
64
  end
54
65
  end
55
66
  Rakit::StaticWebServer.start(port: port)
67
+ puts "http://localhost:#{port}"
56
68
  return 0
57
69
  when "stop"
58
70
  Rakit::StaticWebServer.stop
@@ -68,6 +80,15 @@ def main(argv = ARGV)
68
80
  end
69
81
  Rakit::StaticWebServer.publish(site_name, source_dir)
70
82
  return 0
83
+ when "view"
84
+ path = argv.shift || "/"
85
+ begin
86
+ Rakit::StaticWebServer.view(path)
87
+ return 0
88
+ rescue RuntimeError => e
89
+ $stderr.puts e.message
90
+ return 1
91
+ end
71
92
  else
72
93
  usage_stderr(cmd ? "Unknown command: #{cmd}" : "Expected command after static-web-server.")
73
94
  return 1
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: rakit.azure.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+
8
+ descriptor_data = "\n\x11rakit.azure.proto\x12\x0brakit.azure\"L\n\x08Pipeline\x12\x0b\n\x03org\x18\x01 \x01(\t\x12\x0f\n\x07project\x18\x02 \x01(\t\x12\x13\n\x0bpipeline_id\x18\x03 \x01(\x05\x12\r\n\x05token\x18\x04 \x01(\t\"R\n\x18GetPipelineResultRequest\x12\'\n\x08pipeline\x18\x01 \x01(\x0b\x32\x15.rakit.azure.Pipeline\x12\r\n\x05token\x18\x02 \x01(\t\"C\n\x0ePipelineStatus\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0e\n\x06\x65rrors\x18\x02 \x03(\t\x12\x10\n\x08warnings\x18\x03 \x03(\t\"8\n\x0ePipelineResult\x12&\n\x04runs\x18\x01 \x03(\x0b\x32\x18.rakit.azure.PipelineRun\"\x97\x01\n\x0bPipelineRun\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\r\n\x05state\x18\x03 \x01(\t\x12\x0e\n\x06result\x18\x04 \x01(\t\x12\x14\n\x0c\x63reated_date\x18\x05 \x01(\t\x12\x15\n\rfinished_date\x18\x06 \x01(\t\x12\"\n\x06stages\x18\x07 \x03(\x0b\x32\x12.rakit.azure.Stage\"&\n\x05Issue\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0f\n\x07message\x18\x02 \x01(\t\"G\n\x03Job\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06result\x18\x02 \x01(\t\x12\"\n\x06issues\x18\x03 \x03(\x0b\x32\x12.rakit.azure.Issue\"i\n\x05Stage\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06result\x18\x02 \x01(\t\x12\x1e\n\x04jobs\x18\x03 \x03(\x0b\x32\x10.rakit.azure.Job\x12\"\n\x06issues\x18\x04 \x03(\x0b\x32\x12.rakit.azure.Issue\"`\n\x0eTimelineRecord\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04type\x18\x02 \x01(\t\x12\x0e\n\x06result\x18\x03 \x01(\t\x12\"\n\x06issues\x18\x04 \x03(\x0b\x32\x12.rakit.azure.Issue\"\xa8\x01\n\x14PipelineResultDetail\x12\x12\n\nsuccessful\x18\x01 \x01(\x08\x12\x0e\n\x06\x65rrors\x18\x02 \x01(\t\x12\x10\n\x08warnings\x18\x03 \x01(\t\x12%\n\x03run\x18\x04 \x01(\x0b\x32\x18.rakit.azure.PipelineRun\x12\x33\n\x0e\x66\x61iled_records\x18\x05 \x03(\x0b\x32\x1b.rakit.azure.TimelineRecord2i\n\x0ePipelineServer\x12W\n\x11GetPipelineResult\x12%.rakit.azure.GetPipelineResultRequest\x1a\x1b.rakit.azure.PipelineResultB\x0f\xea\x02\x0cRakit::Azureb\x06proto3"
9
+
10
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
11
+ pool.add_serialized_file(descriptor_data)
12
+
13
+ module Rakit
14
+ module Azure
15
+ Pipeline = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.azure.Pipeline").msgclass
16
+ GetPipelineResultRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.azure.GetPipelineResultRequest").msgclass
17
+ PipelineStatus = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.azure.PipelineStatus").msgclass
18
+ PipelineResult = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.azure.PipelineResult").msgclass
19
+ PipelineRun = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.azure.PipelineRun").msgclass
20
+ Issue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.azure.Issue").msgclass
21
+ Job = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.azure.Job").msgclass
22
+ Stage = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.azure.Stage").msgclass
23
+ TimelineRecord = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.azure.TimelineRecord").msgclass
24
+ PipelineResultDetail = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.azure.PipelineResultDetail").msgclass
25
+ end
26
+ end
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
  # Generated by the protocol buffer compiler. DO NOT EDIT!
3
- # source: example.proto
3
+ # source: rakit.example.proto
4
4
 
5
5
  require 'google/protobuf'
6
6
 
7
7
 
8
- descriptor_data = "\n\rexample.proto\x12\rrakit.example\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\" \n\rHelloResponse\x12\x0f\n\x07message\x18\x01 \x01(\tB\x13\xea\x02\x10Rakit::Generatedb\x06proto3"
8
+ descriptor_data = "\n\x13rakit.example.proto\x12\rrakit.example\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\" \n\rHelloResponse\x12\x0f\n\x07message\x18\x01 \x01(\tB\x13\xea\x02\x10Rakit::Generatedb\x06proto3"
9
9
 
10
10
  pool = ::Google::Protobuf::DescriptorPool.generated_pool
11
11
  pool.add_serialized_file(descriptor_data)
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: rakit.shell.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+
8
+ descriptor_data = "\n\x11rakit.shell.proto\x12\x0brakit.shell\"\x9a\x02\n\x07\x43ommand\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04\x61rgs\x18\x02 \x03(\t\x12\x19\n\x11working_directory\x18\x03 \x01(\t\x12\x17\n\x0ftimeout_seconds\x18\x04 \x01(\x05\x12\x1a\n\x12\x65xpected_exit_code\x18\x05 \x01(\x05\x12\x17\n\x0f\x65xpected_stdout\x18\x06 \x01(\t\x12\x17\n\x0f\x65xpected_stderr\x18\x07 \x01(\t\x12<\n\x13\x61\x63\x63\x65ptance_criteria\x18\x08 \x03(\x0b\x32\x1f.rakit.shell.AcceptanceCriteria\x12\x13\n\x0b\x65xit_status\x18\t \x01(\x05\x12\x0e\n\x06stdout\x18\n \x01(\t\x12\x0e\n\x06stderr\x18\x0b \x01(\t\"1\n\x12\x41\x63\x63\x65ptanceCriteria\x12\x0c\n\x04kind\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"-\n\nTestResult\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0e\n\x06\x65rrors\x18\x02 \x03(\t\"b\n\rFormatRequest\x12%\n\x07\x63ommand\x18\x01 \x01(\x0b\x32\x14.rakit.shell.Command\x12*\n\x06\x66ormat\x18\x02 \x01(\x0e\x32\x1a.rakit.shell.CommandFormat\" \n\x0e\x46ormatResponse\x12\x0e\n\x06output\x18\x01 \x01(\t*Z\n\rCommandFormat\x12\x1e\n\x1a\x43OMMAND_FORMAT_UNSPECIFIED\x10\x00\x12\x0c\n\x08ONE_LINE\x10\x01\x12\x0e\n\nMULTI_LINE\x10\x02\x12\x0b\n\x07\x43OMPACT\x10\x03\x32\xc1\x01\n\x0e\x43ommandService\x12\x35\n\x07\x45xecute\x12\x14.rakit.shell.Command\x1a\x14.rakit.shell.Command\x12\x35\n\x04Test\x12\x14.rakit.shell.Command\x1a\x17.rakit.shell.TestResult\x12\x41\n\x06\x46ormat\x12\x1a.rakit.shell.FormatRequest\x1a\x1b.rakit.shell.FormatResponseB\x0f\xea\x02\x0cRakit::Shellb\x06proto3"
9
+
10
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
11
+ pool.add_serialized_file(descriptor_data)
12
+
13
+ module Rakit
14
+ module Shell
15
+ Command = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.shell.Command").msgclass
16
+ AcceptanceCriteria = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.shell.AcceptanceCriteria").msgclass
17
+ TestResult = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.shell.TestResult").msgclass
18
+ FormatRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.shell.FormatRequest").msgclass
19
+ FormatResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.shell.FormatResponse").msgclass
20
+ CommandFormat = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.shell.CommandFormat").enummodule
21
+ end
22
+ end
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
  # Generated by the protocol buffer compiler. DO NOT EDIT!
3
- # source: static_web_server.proto
3
+ # source: rakit.static_web_server.proto
4
4
 
5
5
  require 'google/protobuf'
6
6
 
7
7
 
8
- descriptor_data = "\n\x17static_web_server.proto\x12\x17rakit.static_web_server\"T\n\x15StaticWebServerConfig\x12\x16\n\x0eroot_directory\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\r\x12\x15\n\rhttps_enabled\x18\x03 \x01(\x08\"=\n\x0ePublishRequest\x12\x11\n\tsite_name\x18\x01 \x01(\t\x12\x18\n\x10source_directory\x18\x02 \x01(\t\"1\n\rPublishResult\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0f\n\x07message\x18\x02 \x01(\t\"-\n\x0cServerStatus\x12\x0f\n\x07running\x18\x01 \x01(\x08\x12\x0c\n\x04port\x18\x02 \x01(\rB\x13\xea\x02\x10Rakit::Generatedb\x06proto3"
8
+ descriptor_data = "\n\x1drakit.static_web_server.proto\x12\x17rakit.static_web_server\"T\n\x15StaticWebServerConfig\x12\x16\n\x0eroot_directory\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\r\x12\x15\n\rhttps_enabled\x18\x03 \x01(\x08\"=\n\x0ePublishRequest\x12\x11\n\tsite_name\x18\x01 \x01(\t\x12\x18\n\x10source_directory\x18\x02 \x01(\t\"1\n\rPublishResult\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0f\n\x07message\x18\x02 \x01(\t\"-\n\x0cServerStatus\x12\x0f\n\x07running\x18\x01 \x01(\x08\x12\x0c\n\x04port\x18\x02 \x01(\rB\x13\xea\x02\x10Rakit::Generatedb\x06proto3"
9
9
 
10
10
  pool = ::Google::Protobuf::DescriptorPool.generated_pool
11
11
  pool.add_serialized_file(descriptor_data)
@@ -7,7 +7,7 @@ require "net/http"
7
7
  require "uri"
8
8
 
9
9
  begin
10
- require "generated/azure.devops_pb"
10
+ require "generated/rakit.azure_pb"
11
11
  rescue StandardError
12
12
  # google-protobuf not available or version conflict (e.g. running without bundle exec)
13
13
  end
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "google/protobuf"
5
+ require "rakit/file"
6
+
7
+ module Rakit
8
+ module CLI
9
+ module File
10
+ class << self
11
+ # @param argv [Array<String>] arguments after "file"
12
+ # @return [Integer] exit code
13
+ def run(argv)
14
+ return 1 if argv.empty?
15
+ sub = argv.shift
16
+ case sub
17
+ when "list" then run_list(argv)
18
+ when "copy" then run_copy(argv)
19
+ else
20
+ $stderr.puts "Unknown command: #{sub}. Use 'list' or 'copy'."
21
+ $stderr.puts " rakit file list <directory> [--recursive] [--include-hidden] [--format console|json|proto-json]"
22
+ $stderr.puts " rakit file copy <source> <destination> [--overwrite] [--create-directories] [--follow-symlinks] [--format ...]"
23
+ 1
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def run_list(argv)
30
+ opts = parse_list_argv(argv)
31
+ return 1 if opts[:error]
32
+ req = Rakit::File::ListRequest.new(
33
+ directory: opts[:directory],
34
+ recursive: opts[:recursive],
35
+ include_hidden: opts[:include_hidden],
36
+ config: Rakit::File::FileConfig.new(follow_symlinks: opts[:follow_symlinks])
37
+ )
38
+ result = Rakit::File.list(req)
39
+ render_list_result(result, opts[:format])
40
+ result.exit_code
41
+ end
42
+
43
+ def parse_list_argv(argv)
44
+ opts = { format: "console", recursive: false, include_hidden: false, follow_symlinks: false, directory: nil }
45
+ args = argv.dup
46
+ while (arg = args.shift)
47
+ case arg
48
+ when "--recursive" then opts[:recursive] = true
49
+ when "--include-hidden" then opts[:include_hidden] = true
50
+ when "--follow-symlinks" then opts[:follow_symlinks] = true
51
+ when "--format" then opts[:format] = args.shift || "console"
52
+ when /^--/
53
+ $stderr.puts "Unknown option: #{arg}"
54
+ opts[:error] = true
55
+ else
56
+ opts[:directory] = arg if opts[:directory].nil?
57
+ end
58
+ end
59
+ unless opts[:directory] && !opts[:directory].empty?
60
+ $stderr.puts "list requires <directory>"
61
+ opts[:error] = true
62
+ end
63
+ opts
64
+ end
65
+
66
+ def run_copy(argv)
67
+ opts = parse_copy_argv(argv)
68
+ return 1 if opts[:error]
69
+ req = Rakit::File::CopyRequest.new(
70
+ source: opts[:source],
71
+ destination: opts[:destination],
72
+ config: Rakit::File::FileConfig.new(
73
+ overwrite: opts[:overwrite],
74
+ create_directories: opts[:create_directories],
75
+ follow_symlinks: opts[:follow_symlinks]
76
+ )
77
+ )
78
+ result = Rakit::File.copy(req)
79
+ render_copy_result(result, opts[:format])
80
+ result.exit_code
81
+ end
82
+
83
+ def parse_copy_argv(argv)
84
+ opts = { format: "console", overwrite: false, create_directories: false, follow_symlinks: false, source: nil, destination: nil }
85
+ args = argv.dup
86
+ while (arg = args.shift)
87
+ case arg
88
+ when "--overwrite" then opts[:overwrite] = true
89
+ when "--create-directories" then opts[:create_directories] = true
90
+ when "--follow-symlinks" then opts[:follow_symlinks] = true
91
+ when "--format" then opts[:format] = args.shift || "console"
92
+ when /^--/
93
+ $stderr.puts "Unknown option: #{arg}"
94
+ opts[:error] = true
95
+ else
96
+ if opts[:source].nil?
97
+ opts[:source] = arg
98
+ elsif opts[:destination].nil?
99
+ opts[:destination] = arg
100
+ else
101
+ $stderr.puts "Unexpected argument: #{arg}"
102
+ opts[:error] = true
103
+ end
104
+ end
105
+ end
106
+ unless opts[:source] && opts[:destination]
107
+ $stderr.puts "copy requires <source> and <destination>"
108
+ opts[:error] = true
109
+ end
110
+ opts
111
+ end
112
+
113
+ def render_list_result(result, format)
114
+ $stderr.puts result.stderr if result.stderr && !result.stderr.empty? && !result.success
115
+ case format
116
+ when "json"
117
+ puts list_result_to_json(result)
118
+ when "proto-json"
119
+ puts Google::Protobuf.encode_json(result)
120
+ else
121
+ result.entries.each do |e|
122
+ puts "#{e.path}\t#{e.name}\t#{e.is_directory ? 'dir' : 'file'}"
123
+ end
124
+ end
125
+ end
126
+
127
+ def list_result_to_json(result)
128
+ h = {
129
+ success: result.success,
130
+ message: result.message.to_s,
131
+ entries: result.entries.map { |e| { path: e.path, name: e.name, is_directory: e.is_directory, is_symlink: e.is_symlink, size_bytes: e.size_bytes, modified_unix_ms: e.modified_unix_ms } },
132
+ exit_code: result.exit_code
133
+ }
134
+ JSON.generate(h)
135
+ end
136
+
137
+ def render_copy_result(result, format)
138
+ $stderr.puts result.stderr if result.stderr && !result.stderr.empty? && !result.success
139
+ case format
140
+ when "json"
141
+ puts copy_result_to_json(result)
142
+ when "proto-json"
143
+ puts Google::Protobuf.encode_json(result)
144
+ else
145
+ puts "Copied #{result.source} → #{result.destination}" if result.success
146
+ end
147
+ end
148
+
149
+ def copy_result_to_json(result)
150
+ h = {
151
+ success: result.success,
152
+ message: result.message.to_s,
153
+ source: result.source.to_s,
154
+ destination: result.destination.to_s,
155
+ exit_code: result.exit_code,
156
+ bytes_copied: result.bytes_copied
157
+ }
158
+ JSON.generate(h)
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
data/lib/rakit/file.rb ADDED
@@ -0,0 +1,181 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "generated/rakit.file_pb"
5
+
6
+ module Rakit
7
+ # Protobuf-first file operations (list directory, copy file). See specs/005-file-ops/contracts/ruby-api.md.
8
+ module File
9
+ class << self
10
+ # @param request [Rakit::File::ListRequest]
11
+ # @return [Rakit::File::ListResult]
12
+ def list(request)
13
+ dir_path = normalize_path(request.directory.to_s)
14
+ if dir_path.nil?
15
+ return error_list_result("Empty or invalid directory path", 1)
16
+ end
17
+ unless ::File.exist?(dir_path)
18
+ return error_list_result("Directory does not exist: #{dir_path}", 1)
19
+ end
20
+ unless ::File.directory?(dir_path)
21
+ return error_list_result("Not a directory: #{dir_path}", 1)
22
+ end
23
+
24
+ include_hidden = request.include_hidden
25
+ follow_symlinks = request.config&.follow_symlinks == true
26
+ entries = request.recursive ? list_entries_recursive(dir_path, include_hidden, follow_symlinks) : list_entries_one_dir(dir_path, include_hidden, follow_symlinks)
27
+
28
+ ListResult.new(
29
+ success: true,
30
+ message: "",
31
+ entries: entries,
32
+ exit_code: 0,
33
+ stderr: ""
34
+ )
35
+ rescue => e
36
+ error_list_result("#{e.message}", 1)
37
+ end
38
+
39
+ # @param request [Rakit::File::CopyRequest]
40
+ # @return [Rakit::File::CopyResult]
41
+ def copy(request)
42
+ config = request.config || FileConfig.new
43
+ src = normalize_path(request.source.to_s)
44
+ dest_raw = normalize_path(request.destination.to_s)
45
+
46
+ if src.nil? || dest_raw.nil?
47
+ return error_copy_result(request.source.to_s, request.destination.to_s, "Empty or invalid path", 1)
48
+ end
49
+ unless ::File.exist?(src)
50
+ return error_copy_result(src, dest_raw, "Source does not exist: #{src}", 1)
51
+ end
52
+ if ::File.directory?(src)
53
+ return error_copy_result(src, dest_raw, "Source is a directory (MVP: file only)", 1)
54
+ end
55
+
56
+ dest_path = resolve_copy_destination(src, dest_raw)
57
+ parent = ::File.dirname(dest_path)
58
+
59
+ unless ::File.directory?(parent)
60
+ if config.create_directories
61
+ FileUtils.mkdir_p(parent)
62
+ else
63
+ return error_copy_result(src, dest_path, "Parent directory does not exist: #{parent}", 1)
64
+ end
65
+ end
66
+
67
+ if ::File.file?(dest_path) && !config.overwrite
68
+ return error_copy_result(src, dest_path, "Destination file exists (use overwrite to replace)", 1)
69
+ end
70
+
71
+ bytes = perform_copy(src, dest_path, config)
72
+ CopyResult.new(
73
+ success: true,
74
+ message: "",
75
+ source: src,
76
+ destination: dest_path,
77
+ exit_code: 0,
78
+ stderr: "",
79
+ bytes_copied: bytes || 0
80
+ )
81
+ rescue => e
82
+ error_copy_result(request.source.to_s, request.destination.to_s, e.message, 1)
83
+ end
84
+
85
+ private
86
+
87
+ # T004: Path normalization. Returns expanded absolute path or nil if nil/empty.
88
+ def normalize_path(path, base_dir = nil)
89
+ return nil if path.nil?
90
+ s = path.to_s.strip
91
+ return nil if s.empty?
92
+ base = base_dir || Dir.pwd
93
+ ::File.expand_path(s, base)
94
+ end
95
+
96
+ def error_list_result(message, exit_code)
97
+ ListResult.new(success: false, message: message, entries: [], exit_code: exit_code, stderr: message)
98
+ end
99
+
100
+ def error_copy_result(source, destination, message, exit_code)
101
+ CopyResult.new(success: false, message: message, source: source.to_s, destination: destination.to_s, exit_code: exit_code, stderr: message)
102
+ end
103
+
104
+ # T005: List entries for one directory; sort by name; filter hidden; best-effort metadata.
105
+ def list_entries_one_dir(dir_path, include_hidden, follow_symlinks)
106
+ names = Dir.children(dir_path)
107
+ names.reject! { |n| n.start_with?(".") } unless include_hidden
108
+ names.sort!
109
+ names.map { |name| file_entry_for(::File.join(dir_path, name), name, follow_symlinks) }
110
+ end
111
+
112
+ def file_entry_for(abs_path, name, follow_symlinks)
113
+ stat = follow_symlinks ? (::File.stat(abs_path) rescue nil) : (::File.lstat(abs_path) rescue nil)
114
+ is_symlink = ::File.symlink?(abs_path)
115
+ is_dir = stat ? stat.directory? : false
116
+ size_bytes = (stat && stat.file?) ? (stat.size rescue 0) : 0
117
+ modified_unix_ms = stat ? (stat.mtime.to_f * 1000).to_i : 0
118
+ FileEntry.new(
119
+ path: abs_path,
120
+ name: name,
121
+ is_directory: is_dir,
122
+ is_symlink: is_symlink,
123
+ size_bytes: size_bytes,
124
+ modified_unix_ms: modified_unix_ms
125
+ )
126
+ rescue
127
+ FileEntry.new(path: abs_path, name: name, is_directory: false, is_symlink: false, size_bytes: 0, modified_unix_ms: 0)
128
+ end
129
+
130
+ # T006: Depth-first recursive list; children at each level sorted by name.
131
+ def list_entries_recursive(dir_path, include_hidden, follow_symlinks)
132
+ entries = list_entries_one_dir(dir_path, include_hidden, follow_symlinks)
133
+ result = []
134
+ entries.each do |entry|
135
+ result << entry
136
+ if entry.is_directory
137
+ result.concat(list_entries_recursive(entry.path, include_hidden, follow_symlinks))
138
+ end
139
+ end
140
+ result
141
+ end
142
+
143
+ # Resolve destination: if existing directory, copy into it with basename(source); else file path.
144
+ def resolve_copy_destination(source, destination)
145
+ return ::File.join(destination, ::File.basename(source)) if ::File.exist?(destination) && ::File.directory?(destination)
146
+ destination
147
+ end
148
+
149
+ # T007: Atomic copy where possible (temp then rename); respect follow_symlinks for source.
150
+ def perform_copy(source, dest_path, config)
151
+ if !config.follow_symlinks && ::File.symlink?(source)
152
+ # Copy symlink itself: create new symlink with same target
153
+ target = ::File.readlink(source)
154
+ ::File.delete(dest_path) if ::File.exist?(dest_path)
155
+ ::File.symlink(target, dest_path)
156
+ return 0 # best-effort bytes
157
+ end
158
+
159
+ content = ::File.binread(source)
160
+ dest_dir = ::File.dirname(dest_path)
161
+ temp_path = ::File.join(dest_dir, ".rakit_copy_#{Process.pid}_#{object_id}_#{::File.basename(dest_path)}")
162
+ bytes = nil
163
+ begin
164
+ ::File.write(temp_path, content)
165
+ bytes = content.bytesize
166
+ ::File.rename(temp_path, dest_path)
167
+ rescue Errno::EXDEV, Errno::EPERM
168
+ # Cross-filesystem or rename not allowed: fall back to overwrite
169
+ ::File.write(dest_path, content)
170
+ bytes = content.bytesize
171
+ ::File.delete(temp_path) if ::File.exist?(temp_path)
172
+ ensure
173
+ ::File.delete(temp_path) if ::File.exist?(temp_path)
174
+ end
175
+ bytes
176
+ rescue => e
177
+ raise "Failed to copy: #{e.message}"
178
+ end
179
+ end
180
+ end
181
+ end
data/lib/rakit/gem.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "fileutils"
4
+ require "json"
5
+ require "open3"
4
6
  require "rubygems/package"
5
7
 
6
8
  module Rakit
@@ -44,9 +46,8 @@ module Rakit
44
46
  raise "Gem not found: #{gem_path}. Run rake package first." unless ::File.file?(gem_path)
45
47
 
46
48
  base = ::File.basename(gem_path, ".gem")
47
- parts = base.split("-")
48
- version = parts.pop
49
- name = parts.join("-")
49
+ name, version = parse_gem_basename(base)
50
+ raise "Could not parse name/version from #{base}.gem" unless name && version
50
51
 
51
52
  if version_published?(name, version)
52
53
  warn "publish: Version #{version} of #{name} is already published on rubygems.org. Skipping push. Bump the version in the gemspec to publish again."
@@ -57,14 +58,86 @@ module Rakit
57
58
  raise "gem push failed" unless success
58
59
  end
59
60
 
61
+ # Parse "name-version" basename (no .gem) into [name, version].
62
+ # Version is the last hyphen-separated segment that looks like a version (e.g. 0.1.5).
63
+ def self.parse_gem_basename(base)
64
+ # Match name (may contain hyphens) and version (digits and dots, optional pre-release suffix).
65
+ m = base.match(/\A(.+)-(\d+(?:\.\d+)*(?:\.\w+)?)\z/)
66
+ m ? [m[1], m[2]] : nil
67
+ end
68
+
60
69
  def self.version_published?(name, version)
70
+ begin
71
+ return true if version_published_gem_list?(name, version)
72
+ rescue StandardError
73
+ # try API fallbacks
74
+ end
75
+ begin
76
+ return true if version_published_v2?(name, version)
77
+ rescue StandardError
78
+ # try v1 fallback
79
+ end
80
+ begin
81
+ return true if version_published_v1?(name, version)
82
+ rescue StandardError
83
+ nil
84
+ end
85
+ false
86
+ end
87
+
88
+ # Run `gem list NAME --remote` and check if version appears in the output.
89
+ def self.version_published_gem_list?(name, version)
90
+ out, err, status = Open3.capture3("gem", "list", name, "--remote")
91
+ return false unless status.success?
92
+ # Output format: "name (1.0.0, 0.9.0)" or "name (1.0.0)"
93
+ combined = "#{out}#{err}"
94
+ combined.each_line do |line|
95
+ next unless line.include?(name)
96
+ if line =~ /\s*#{Regexp.escape(name)}\s*\((.*)\)/
97
+ versions = Regexp.last_match(1).split(",").map(&:strip)
98
+ return true if versions.include?(version)
99
+ end
100
+ end
101
+ false
102
+ end
103
+
104
+ # GET /api/v2/rubygems/{name}/versions/{version}.json (follows redirects)
105
+ def self.version_published_v2?(name, version)
61
106
  require "net/http"
62
107
  require "uri"
63
108
  uri = URI("https://rubygems.org/api/v2/rubygems/#{URI::DEFAULT_PARSER.escape(name)}/versions/#{URI::DEFAULT_PARSER.escape(version)}.json")
64
- response = Net::HTTP.get_response(uri)
109
+ response = http_get_following_redirects(uri)
65
110
  response.is_a?(Net::HTTPSuccess)
66
- rescue StandardError
67
- false
111
+ end
112
+
113
+ # GET /api/v1/versions/{name}.json and check if version is in the list
114
+ def self.version_published_v1?(name, version)
115
+ require "net/http"
116
+ require "json"
117
+ require "uri"
118
+ uri = URI("https://rubygems.org/api/v1/versions/#{URI::DEFAULT_PARSER.escape(name)}.json")
119
+ response = http_get_following_redirects(uri)
120
+ return false unless response.is_a?(Net::HTTPSuccess)
121
+ list = JSON.parse(response.body)
122
+ list.is_a?(Array) && list.any? { |h| h["number"] == version }
123
+ end
124
+
125
+ def self.http_get_following_redirects(uri, limit: 5)
126
+ raise ArgumentError, "redirect limit exceeded" if limit <= 0
127
+ require "net/http"
128
+ response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https", open_timeout: 10, read_timeout: 10) do |http|
129
+ request = Net::HTTP::Get.new(uri)
130
+ request["User-Agent"] = "rakit (https://rubygems.org/gems/rakit)"
131
+ http.request(request)
132
+ end
133
+ case response
134
+ when Net::HTTPRedirection
135
+ location = response["location"]
136
+ next_uri = location.match?(/\Ahttps?:\/\//) ? URI(location) : URI.join(uri, location)
137
+ http_get_following_redirects(next_uri, limit: limit - 1)
138
+ else
139
+ response
140
+ end
68
141
  end
69
142
  end
70
143
  end
data/lib/rakit/hugo.rb ADDED
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ module Rakit
6
+ # Build Hugo static sites from source. Used by publish_docs and tests.
7
+ # Contract: specs/008-hugo-docs-site/contracts/ruby-api.md
8
+ module Hugo
9
+ class << self
10
+ attr_accessor :hugo_path
11
+
12
+ def hugo_path
13
+ @hugo_path ||= "hugo"
14
+ end
15
+
16
+ # @param site_dir [String] path to Hugo source (must exist and be a directory)
17
+ # @param out_dir [String] path for build output
18
+ # @return [true] on success
19
+ # @return [false] on failure (Hugo not found, build failed, or invalid site_dir)
20
+ def build(site_dir:, out_dir:)
21
+ site_dir = ::File.expand_path(site_dir)
22
+ out_dir = ::File.expand_path(out_dir)
23
+ return false unless ::File.directory?(site_dir)
24
+ return false if ::File.file?(site_dir)
25
+
26
+ FileUtils.mkdir_p(out_dir)
27
+ success = system(hugo_path, "-s", site_dir, "-d", out_dir, out: $stdout, err: $stderr)
28
+ return false unless success
29
+ return false unless ::File.directory?(out_dir) && (Dir.entries(out_dir) - %w[. ..]).any?
30
+
31
+ true
32
+ end
33
+
34
+ # @param site_dir [String] path to check
35
+ # @return [Boolean] true if config.toml or config.yaml exists under site_dir
36
+ def valid_site?(site_dir)
37
+ dir = ::File.expand_path(site_dir)
38
+ return false unless ::File.directory?(dir)
39
+ ::File.file?(::File.join(dir, "config.toml")) || ::File.file?(::File.join(dir, "config.yaml"))
40
+ end
41
+ end
42
+ end
43
+ end
data/lib/rakit/shell.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  require "open3"
4
4
  require "timeout"
5
- require "generated/shell_pb"
5
+ require "generated/rakit.shell_pb"
6
6
 
7
7
  module Rakit
8
8
  module Shell
@@ -1,28 +1,42 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "fileutils"
4
- require "generated/static_web_server_pb"
4
+ require "generated/rakit.static_web_server_pb"
5
5
 
6
6
  module Rakit
7
- # Publish static sites into a configurable root, regenerate a root index, and control a local HTTP server (start/stop/running).
8
- # CLI: +rakit static-web-server+ (start|stop|running|publish). See contracts/ruby-api.md and quickstart in specs/003-static-web-server/quickstart.md.
7
+ # Publish static sites into a configurable root (~/.rakit/wwwroot), regenerate a root index, and control a local HTTP server (start/stop/running).
8
+ # Host and port are configurable (host default 127.0.0.1, port 5099) and returned regardless of server state for URL building.
9
+ # CLI: +rakit static-web-server+ (start|stop|running|publish|view). See specs/003-static-web-server/contracts/ruby-api.md and specs/007-wwwroot-docs-hugo-view/contracts/ruby-api.md.
9
10
  module StaticWebServer
10
11
  SITE_NAME_REGEX = /\A[a-z0-9\-]+\z/.freeze
11
12
 
12
13
  class << self
13
- # @return [String] Static root directory (default ~/.rakit/www_root). Used by publish and server lifecycle.
14
+ # @return [String] Static root directory (default ~/.rakit/wwwroot). Used by publish and server lifecycle.
14
15
  attr_accessor :root
15
- # @return [Integer] Default port for start (default 5099). Used when no override passed to start.
16
+ # @return [String] Host for building URLs (default 127.0.0.1). Returned regardless of server running state.
17
+ attr_accessor :host
18
+ # @return [Integer] Default port for start (default 5099). Used when no override passed to start; returned regardless of server running state.
16
19
  attr_accessor :port
17
20
  end
18
21
 
19
- self.root = ::File.expand_path("~/.rakit/www_root")
22
+ self.root = ::File.expand_path("~/.rakit/wwwroot")
23
+ self.host = "127.0.0.1"
20
24
  self.port = 5099
21
25
 
22
26
  # T005: Validate site name; raise ArgumentError before any filesystem write.
27
+ # Single segment (e.g. "mysite") or multi-segment path (e.g. "louparslow/rakit"); each segment must match SITE_NAME_REGEX.
23
28
  def self.validate_site_name!(site_name)
24
- return if site_name.is_a?(String) && site_name.match?(SITE_NAME_REGEX)
25
- raise ArgumentError, "site_name must be lowercase alphanumeric and dashes only (e.g. my-site); got: #{site_name.inspect}"
29
+ validate_site_path!(site_name)
30
+ end
31
+
32
+ def self.validate_site_path!(site_name)
33
+ return if site_name.nil? || site_name.to_s.empty?
34
+ site_name.to_s.split(::File::SEPARATOR).each do |seg|
35
+ next if seg.empty?
36
+ unless seg.match?(SITE_NAME_REGEX)
37
+ raise ArgumentError, "site_name segment must be lowercase alphanumeric and dashes only (e.g. my-site); got: #{seg.inspect}"
38
+ end
39
+ end
26
40
  end
27
41
 
28
42
  # T006: PID file path for start/stop/running (research: ~/.rakit/static_web_server.pid).
@@ -49,26 +63,27 @@ module Rakit
49
63
  end
50
64
 
51
65
  # Publish static content from source_directory to root/site_name (atomic copy), then regenerate root index.
52
- # @param site_name [String] Must match \\A[a-z0-9\-]+\\z (lowercase, alphanumeric, dashes only).
66
+ # @param site_name [String] Single segment (e.g. "mysite") or path (e.g. "louparslow/rakit"); each segment must match \\A[a-z0-9\-]+\\z.
53
67
  # @param source_directory [String] Existing directory path; contents are copied (no traversal outside allowed paths).
54
68
  # @return [true] on success.
55
69
  # @raise [ArgumentError] for invalid site_name, missing/invalid source_directory, or root not writable.
56
70
  def self.publish(site_name, source_directory)
57
- validate_site_name!(site_name)
71
+ validate_site_path!(site_name)
58
72
  src = ::File.expand_path(source_directory)
59
73
  raise ArgumentError, "source_directory does not exist: #{source_directory}" unless ::File.exist?(src)
60
74
  raise ArgumentError, "source_directory is not a directory: #{source_directory}" unless ::File.directory?(src)
61
75
 
62
76
  ensure_root
63
- # Check root is writable before we do any copy (T015 / edge case).
64
77
  unless ::File.writable?(root)
65
78
  raise ArgumentError, "root directory is not writable: #{root}"
66
79
  end
67
80
 
68
81
  target = ::File.join(root, site_name)
69
- temp = ::File.join(root, ".tmp_#{site_name}_#{Process.pid}_#{rand(1_000_000)}")
82
+ temp_name = ".tmp_#{site_name.to_s.gsub(::File::SEPARATOR, '_')}_#{Process.pid}_#{rand(1_000_000)}"
83
+ temp = ::File.join(root, temp_name)
70
84
  FileUtils.mkdir_p(temp)
71
85
  FileUtils.cp_r(::File.join(src, "."), temp)
86
+ FileUtils.mkdir_p(::File.dirname(target))
72
87
  FileUtils.rm_rf(target)
73
88
  FileUtils.mv(temp, target)
74
89
  regenerate_root_index
@@ -102,6 +117,7 @@ module Rakit
102
117
  root_path = ::File.expand_path(root)
103
118
  pid = spawn(bin, root_path, "--port", p.to_s, out: ::File::NULL, err: ::File::NULL)
104
119
  Process.detach(pid)
120
+ FileUtils.mkdir_p(::File.dirname(pid_file_path))
105
121
  ::File.write(pid_file_path, pid.to_s)
106
122
  true
107
123
  end
@@ -144,6 +160,20 @@ module Rakit
144
160
  true
145
161
  end
146
162
 
163
+ # Open a path on the static server in the default browser. Ensures server is running (starts if not), builds URL, launches browser.
164
+ # @param relative_path [String] URL path (e.g. "/louparslow/rakit/" or "louparslow/rakit"); normalized to one leading slash.
165
+ # @return [true] on success.
166
+ # @raise [RuntimeError] if browser cannot be launched (e.g. headless), with message e.g. "Could not launch browser; display required?"
167
+ def self.view(relative_path)
168
+ start unless running?
169
+ path = relative_path.to_s.strip
170
+ path = "/#{path}" unless path.empty? || path.start_with?("/")
171
+ path = "/" if path.empty?
172
+ url = "http://#{host}:#{port}#{path}"
173
+ launch_browser(url)
174
+ true
175
+ end
176
+
147
177
  # T017: Write root/index.html listing all site subdirectories alphabetically with links.
148
178
  def self.regenerate_root_index
149
179
  entries = Dir.entries(root).sort.select do |e|
@@ -177,6 +207,20 @@ module Rakit
177
207
  rescue Errno::EADDRINUSE
178
208
  true
179
209
  end
210
+
211
+ def launch_browser(url)
212
+ cmd = case ::RbConfig::CONFIG["host_os"]
213
+ when /darwin|mac os/i
214
+ ["open", url]
215
+ when /mswin|mingw|windows/i
216
+ ["cmd", "/c", "start", "", url]
217
+ else
218
+ ["xdg-open", url]
219
+ end
220
+ system(*cmd, out: ::File::NULL, err: ::File::NULL)
221
+ return true if $?.success?
222
+ raise "Could not launch browser; display required?"
223
+ end
180
224
  end
181
225
  end
182
226
  end
data/lib/rakit.rb CHANGED
@@ -25,6 +25,7 @@ require_relative "rakit/protobuf"
25
25
  # Defer loading so rake tasks that don't need Shell (e.g. clobber) work without google-protobuf.
26
26
  autoload :Shell, "rakit/shell"
27
27
  require_relative "rakit/static_web_server"
28
+ require_relative "rakit/hugo"
28
29
  require_relative "rakit/word_count"
29
30
  require_relative "rakit/file"
30
31
  require_relative "rakit/azure/dev_ops"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rakit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - rakit
@@ -41,16 +41,22 @@ dependencies:
41
41
  name: google-protobuf
42
42
  requirement: !ruby/object:Gem::Requirement
43
43
  requirements:
44
- - - "~>"
44
+ - - ">="
45
45
  - !ruby/object:Gem::Version
46
46
  version: '3.25'
47
+ - - "<"
48
+ - !ruby/object:Gem::Version
49
+ version: '6'
47
50
  type: :runtime
48
51
  prerelease: false
49
52
  version_requirements: !ruby/object:Gem::Requirement
50
53
  requirements:
51
- - - "~>"
54
+ - - ">="
52
55
  - !ruby/object:Gem::Version
53
56
  version: '3.25'
57
+ - - "<"
58
+ - !ruby/object:Gem::Version
59
+ version: '6'
54
60
  - !ruby/object:Gem::Dependency
55
61
  name: rubyzip
56
62
  requirement: !ruby/object:Gem::Requirement
@@ -99,18 +105,21 @@ extensions: []
99
105
  extra_rdoc_files: []
100
106
  files:
101
107
  - exe/rakit
102
- - lib/generated/azure.devops_pb.rb
103
108
  - lib/generated/data_pb.rb
104
- - lib/generated/example_pb.rb
109
+ - lib/generated/rakit.azure_pb.rb
110
+ - lib/generated/rakit.example_pb.rb
105
111
  - lib/generated/rakit.file_pb.rb
112
+ - lib/generated/rakit.shell_pb.rb
113
+ - lib/generated/rakit.static_web_server_pb.rb
106
114
  - lib/generated/rakit.word_count_pb.rb
107
- - lib/generated/shell_pb.rb
108
- - lib/generated/static_web_server_pb.rb
109
115
  - lib/rakit.rb
110
116
  - lib/rakit/azure/dev_ops.rb
117
+ - lib/rakit/cli/file.rb
111
118
  - lib/rakit/cli/word_count.rb
119
+ - lib/rakit/file.rb
112
120
  - lib/rakit/gem.rb
113
121
  - lib/rakit/git.rb
122
+ - lib/rakit/hugo.rb
114
123
  - lib/rakit/protobuf.rb
115
124
  - lib/rakit/shell.rb
116
125
  - lib/rakit/static_web_server.rb
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
- # Generated by the protocol buffer compiler. DO NOT EDIT!
3
- # source: azure.devops.proto
4
-
5
- require 'google/protobuf'
6
-
7
-
8
- descriptor_data = "\n\x12\x61zure.devops.proto\x12\x0brakit.azure\"L\n\x08Pipeline\x12\x0b\n\x03org\x18\x01 \x01(\t\x12\x0f\n\x07project\x18\x02 \x01(\t\x12\x13\n\x0bpipeline_id\x18\x03 \x01(\x05\x12\r\n\x05token\x18\x04 \x01(\t\"R\n\x18GetPipelineResultRequest\x12\'\n\x08pipeline\x18\x01 \x01(\x0b\x32\x15.rakit.azure.Pipeline\x12\r\n\x05token\x18\x02 \x01(\t\"C\n\x0ePipelineStatus\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0e\n\x06\x65rrors\x18\x02 \x03(\t\x12\x10\n\x08warnings\x18\x03 \x03(\t\"8\n\x0ePipelineResult\x12&\n\x04runs\x18\x01 \x03(\x0b\x32\x18.rakit.azure.PipelineRun\"\x97\x01\n\x0bPipelineRun\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\r\n\x05state\x18\x03 \x01(\t\x12\x0e\n\x06result\x18\x04 \x01(\t\x12\x14\n\x0c\x63reated_date\x18\x05 \x01(\t\x12\x15\n\rfinished_date\x18\x06 \x01(\t\x12\"\n\x06stages\x18\x07 \x03(\x0b\x32\x12.rakit.azure.Stage\"&\n\x05Issue\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0f\n\x07message\x18\x02 \x01(\t\"G\n\x03Job\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06result\x18\x02 \x01(\t\x12\"\n\x06issues\x18\x03 \x03(\x0b\x32\x12.rakit.azure.Issue\"i\n\x05Stage\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06result\x18\x02 \x01(\t\x12\x1e\n\x04jobs\x18\x03 \x03(\x0b\x32\x10.rakit.azure.Job\x12\"\n\x06issues\x18\x04 \x03(\x0b\x32\x12.rakit.azure.Issue\"`\n\x0eTimelineRecord\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04type\x18\x02 \x01(\t\x12\x0e\n\x06result\x18\x03 \x01(\t\x12\"\n\x06issues\x18\x04 \x03(\x0b\x32\x12.rakit.azure.Issue\"\xa8\x01\n\x14PipelineResultDetail\x12\x12\n\nsuccessful\x18\x01 \x01(\x08\x12\x0e\n\x06\x65rrors\x18\x02 \x01(\t\x12\x10\n\x08warnings\x18\x03 \x01(\t\x12%\n\x03run\x18\x04 \x01(\x0b\x32\x18.rakit.azure.PipelineRun\x12\x33\n\x0e\x66\x61iled_records\x18\x05 \x03(\x0b\x32\x1b.rakit.azure.TimelineRecord2i\n\x0ePipelineServer\x12W\n\x11GetPipelineResult\x12%.rakit.azure.GetPipelineResultRequest\x1a\x1b.rakit.azure.PipelineResultB\x0f\xea\x02\x0cRakit::Azureb\x06proto3"
9
-
10
- pool = ::Google::Protobuf::DescriptorPool.generated_pool
11
- pool.add_serialized_file(descriptor_data)
12
-
13
- module Rakit
14
- module Azure
15
- Pipeline = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.azure.Pipeline").msgclass
16
- GetPipelineResultRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.azure.GetPipelineResultRequest").msgclass
17
- PipelineStatus = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.azure.PipelineStatus").msgclass
18
- PipelineResult = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.azure.PipelineResult").msgclass
19
- PipelineRun = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.azure.PipelineRun").msgclass
20
- Issue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.azure.Issue").msgclass
21
- Job = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.azure.Job").msgclass
22
- Stage = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.azure.Stage").msgclass
23
- TimelineRecord = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.azure.TimelineRecord").msgclass
24
- PipelineResultDetail = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.azure.PipelineResultDetail").msgclass
25
- end
26
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
- # Generated by the protocol buffer compiler. DO NOT EDIT!
3
- # source: shell.proto
4
-
5
- require 'google/protobuf'
6
-
7
-
8
- descriptor_data = "\n\x0bshell.proto\x12\x0brakit.shell\"\x9a\x02\n\x07\x43ommand\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04\x61rgs\x18\x02 \x03(\t\x12\x19\n\x11working_directory\x18\x03 \x01(\t\x12\x17\n\x0ftimeout_seconds\x18\x04 \x01(\x05\x12\x1a\n\x12\x65xpected_exit_code\x18\x05 \x01(\x05\x12\x17\n\x0f\x65xpected_stdout\x18\x06 \x01(\t\x12\x17\n\x0f\x65xpected_stderr\x18\x07 \x01(\t\x12<\n\x13\x61\x63\x63\x65ptance_criteria\x18\x08 \x03(\x0b\x32\x1f.rakit.shell.AcceptanceCriteria\x12\x13\n\x0b\x65xit_status\x18\t \x01(\x05\x12\x0e\n\x06stdout\x18\n \x01(\t\x12\x0e\n\x06stderr\x18\x0b \x01(\t\"1\n\x12\x41\x63\x63\x65ptanceCriteria\x12\x0c\n\x04kind\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"-\n\nTestResult\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0e\n\x06\x65rrors\x18\x02 \x03(\t\"b\n\rFormatRequest\x12%\n\x07\x63ommand\x18\x01 \x01(\x0b\x32\x14.rakit.shell.Command\x12*\n\x06\x66ormat\x18\x02 \x01(\x0e\x32\x1a.rakit.shell.CommandFormat\" \n\x0e\x46ormatResponse\x12\x0e\n\x06output\x18\x01 \x01(\t*Z\n\rCommandFormat\x12\x1e\n\x1a\x43OMMAND_FORMAT_UNSPECIFIED\x10\x00\x12\x0c\n\x08ONE_LINE\x10\x01\x12\x0e\n\nMULTI_LINE\x10\x02\x12\x0b\n\x07\x43OMPACT\x10\x03\x32\xc1\x01\n\x0e\x43ommandService\x12\x35\n\x07\x45xecute\x12\x14.rakit.shell.Command\x1a\x14.rakit.shell.Command\x12\x35\n\x04Test\x12\x14.rakit.shell.Command\x1a\x17.rakit.shell.TestResult\x12\x41\n\x06\x46ormat\x12\x1a.rakit.shell.FormatRequest\x1a\x1b.rakit.shell.FormatResponseB\x0f\xea\x02\x0cRakit::Shellb\x06proto3"
9
-
10
- pool = ::Google::Protobuf::DescriptorPool.generated_pool
11
- pool.add_serialized_file(descriptor_data)
12
-
13
- module Rakit
14
- module Shell
15
- Command = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.shell.Command").msgclass
16
- AcceptanceCriteria = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.shell.AcceptanceCriteria").msgclass
17
- TestResult = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.shell.TestResult").msgclass
18
- FormatRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.shell.FormatRequest").msgclass
19
- FormatResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.shell.FormatResponse").msgclass
20
- CommandFormat = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("rakit.shell.CommandFormat").enummodule
21
- end
22
- end