makit 0.0.169 → 0.0.171

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.
Files changed (179) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +41 -41
  3. data/exe/makit +5 -5
  4. data/lib/makit/apache.rb +28 -28
  5. data/lib/makit/auto.rb +48 -48
  6. data/lib/makit/azure/blob_storage.rb +257 -257
  7. data/lib/makit/azure/cli.rb +284 -284
  8. data/lib/makit/azure-pipelines.rb +187 -187
  9. data/lib/makit/cli/base.rb +17 -17
  10. data/lib/makit/cli/build_commands.rb +500 -500
  11. data/lib/makit/cli/generators/base_generator.rb +74 -74
  12. data/lib/makit/cli/generators/dotnet_generator.rb +50 -50
  13. data/lib/makit/cli/generators/generator_factory.rb +49 -49
  14. data/lib/makit/cli/generators/node_generator.rb +50 -50
  15. data/lib/makit/cli/generators/ruby_generator.rb +77 -77
  16. data/lib/makit/cli/generators/rust_generator.rb +50 -50
  17. data/lib/makit/cli/generators/templates/dotnet_templates.rb +167 -167
  18. data/lib/makit/cli/generators/templates/node_templates.rb +161 -161
  19. data/lib/makit/cli/generators/templates/ruby/gemfile.rb +26 -26
  20. data/lib/makit/cli/generators/templates/ruby/gemspec.rb +41 -41
  21. data/lib/makit/cli/generators/templates/ruby/main_lib.rb +33 -33
  22. data/lib/makit/cli/generators/templates/ruby/rakefile.rb +35 -35
  23. data/lib/makit/cli/generators/templates/ruby/readme.rb +63 -63
  24. data/lib/makit/cli/generators/templates/ruby/test.rb +39 -39
  25. data/lib/makit/cli/generators/templates/ruby/test_helper.rb +29 -29
  26. data/lib/makit/cli/generators/templates/ruby/version.rb +29 -29
  27. data/lib/makit/cli/generators/templates/rust_templates.rb +128 -128
  28. data/lib/makit/cli/main.rb +78 -78
  29. data/lib/makit/cli/pipeline_commands.rb +311 -311
  30. data/lib/makit/cli/project_commands.rb +868 -868
  31. data/lib/makit/cli/repository_commands.rb +661 -661
  32. data/lib/makit/cli/strategy_commands.rb +207 -207
  33. data/lib/makit/cli/utility_commands.rb +521 -521
  34. data/lib/makit/commands/factory.rb +359 -359
  35. data/lib/makit/commands/middleware/base.rb +73 -73
  36. data/lib/makit/commands/middleware/cache.rb +248 -248
  37. data/lib/makit/commands/middleware/command_logger.rb +312 -312
  38. data/lib/makit/commands/middleware/validator.rb +269 -269
  39. data/lib/makit/commands/request.rb +316 -316
  40. data/lib/makit/commands/result.rb +323 -323
  41. data/lib/makit/commands/runner.rb +386 -386
  42. data/lib/makit/commands/strategies/base.rb +171 -171
  43. data/lib/makit/commands/strategies/child_process.rb +162 -162
  44. data/lib/makit/commands/strategies/factory.rb +136 -136
  45. data/lib/makit/commands/strategies/synchronous.rb +139 -139
  46. data/lib/makit/commands.rb +50 -50
  47. data/lib/makit/configuration/dotnet_project.rb +48 -48
  48. data/lib/makit/configuration/gitlab_helper.rb +61 -61
  49. data/lib/makit/configuration/project.rb +292 -292
  50. data/lib/makit/configuration/rakefile_helper.rb +43 -43
  51. data/lib/makit/configuration/step.rb +34 -34
  52. data/lib/makit/configuration/timeout.rb +74 -74
  53. data/lib/makit/configuration.rb +21 -21
  54. data/lib/makit/content/default_gitignore.rb +7 -7
  55. data/lib/makit/content/default_gitignore.txt +225 -225
  56. data/lib/makit/content/default_rakefile.rb +13 -13
  57. data/lib/makit/content/gem_rakefile.rb +16 -16
  58. data/lib/makit/context.rb +1 -1
  59. data/lib/makit/data.rb +49 -49
  60. data/lib/makit/directories.rb +170 -170
  61. data/lib/makit/directory.rb +262 -262
  62. data/lib/makit/docs/files.rb +89 -89
  63. data/lib/makit/docs/rake.rb +102 -102
  64. data/lib/makit/dotnet/cli.rb +224 -224
  65. data/lib/makit/dotnet/project.rb +217 -217
  66. data/lib/makit/dotnet/solution.rb +38 -38
  67. data/lib/makit/dotnet/solution_classlib.rb +239 -239
  68. data/lib/makit/dotnet/solution_console.rb +264 -264
  69. data/lib/makit/dotnet/solution_maui.rb +354 -354
  70. data/lib/makit/dotnet/solution_wasm.rb +275 -275
  71. data/lib/makit/dotnet/solution_wpf.rb +304 -304
  72. data/lib/makit/dotnet.rb +110 -110
  73. data/lib/makit/email.rb +90 -90
  74. data/lib/makit/environment.rb +142 -142
  75. data/lib/makit/examples/runner.rb +370 -370
  76. data/lib/makit/exceptions.rb +45 -45
  77. data/lib/makit/fileinfo.rb +32 -32
  78. data/lib/makit/files.rb +43 -43
  79. data/lib/makit/gems.rb +49 -49
  80. data/lib/makit/git/cli.rb +103 -103
  81. data/lib/makit/git/repository.rb +100 -100
  82. data/lib/makit/git.rb +104 -104
  83. data/lib/makit/github_actions.rb +202 -202
  84. data/lib/makit/gitlab/pipeline.rb +857 -857
  85. data/lib/makit/gitlab/pipeline_service_impl.rb +1535 -1535
  86. data/lib/makit/gitlab_runner.rb +59 -59
  87. data/lib/makit/humanize.rb +218 -218
  88. data/lib/makit/indexer.rb +47 -47
  89. data/lib/makit/io/filesystem.rb +111 -111
  90. data/lib/makit/io/filesystem_service_impl.rb +337 -337
  91. data/lib/makit/lint.rb +212 -212
  92. data/lib/makit/logging/configuration.rb +309 -309
  93. data/lib/makit/logging/format_registry.rb +84 -84
  94. data/lib/makit/logging/formatters/base.rb +39 -39
  95. data/lib/makit/logging/formatters/console_formatter.rb +140 -140
  96. data/lib/makit/logging/formatters/json_formatter.rb +65 -65
  97. data/lib/makit/logging/formatters/plain_text_formatter.rb +71 -71
  98. data/lib/makit/logging/formatters/text_formatter.rb +64 -64
  99. data/lib/makit/logging/log_request.rb +119 -119
  100. data/lib/makit/logging/logger.rb +199 -199
  101. data/lib/makit/logging/sinks/base.rb +91 -91
  102. data/lib/makit/logging/sinks/console.rb +72 -72
  103. data/lib/makit/logging/sinks/file_sink.rb +92 -92
  104. data/lib/makit/logging/sinks/structured.rb +123 -123
  105. data/lib/makit/logging/sinks/unified_file_sink.rb +296 -296
  106. data/lib/makit/logging.rb +578 -578
  107. data/lib/makit/markdown.rb +75 -75
  108. data/lib/makit/mp/basic_object_mp.rb +17 -17
  109. data/lib/makit/mp/command_mp.rb +13 -13
  110. data/lib/makit/mp/command_request.mp.rb +17 -17
  111. data/lib/makit/mp/project_mp.rb +199 -199
  112. data/lib/makit/mp/string_mp.rb +205 -205
  113. data/lib/makit/nuget.rb +536 -460
  114. data/lib/makit/podman/podman.rb +458 -458
  115. data/lib/makit/podman/podman_service_impl.rb +1081 -1081
  116. data/lib/makit/port.rb +32 -32
  117. data/lib/makit/process.rb +377 -377
  118. data/lib/makit/protoc.rb +112 -112
  119. data/lib/makit/rake/cli.rb +196 -196
  120. data/lib/makit/rake/trace_controller.rb +174 -174
  121. data/lib/makit/rake.rb +81 -81
  122. data/lib/makit/ruby/cli.rb +185 -185
  123. data/lib/makit/ruby.rb +25 -25
  124. data/lib/makit/rubygems.rb +137 -137
  125. data/lib/makit/secrets/azure_key_vault.rb +322 -322
  126. data/lib/makit/secrets/azure_secrets.rb +221 -221
  127. data/lib/makit/secrets/local_secrets.rb +72 -72
  128. data/lib/makit/secrets/secrets_manager.rb +105 -105
  129. data/lib/makit/secrets.rb +96 -96
  130. data/lib/makit/serializer.rb +130 -130
  131. data/lib/makit/services/builder.rb +186 -186
  132. data/lib/makit/services/error_handler.rb +226 -226
  133. data/lib/makit/services/repository_manager.rb +367 -367
  134. data/lib/makit/services/validator.rb +112 -112
  135. data/lib/makit/setup/classlib.rb +101 -101
  136. data/lib/makit/setup/gem.rb +268 -268
  137. data/lib/makit/setup/pages.rb +11 -11
  138. data/lib/makit/setup/razorclasslib.rb +101 -101
  139. data/lib/makit/setup/runner.rb +54 -54
  140. data/lib/makit/setup.rb +5 -5
  141. data/lib/makit/show.rb +110 -110
  142. data/lib/makit/storage.rb +126 -126
  143. data/lib/makit/symbols.rb +175 -175
  144. data/lib/makit/task_info.rb +130 -130
  145. data/lib/makit/tasks/at_exit.rb +15 -15
  146. data/lib/makit/tasks/build.rb +22 -22
  147. data/lib/makit/tasks/bump.rb +7 -7
  148. data/lib/makit/tasks/clean.rb +13 -13
  149. data/lib/makit/tasks/configure.rb +10 -10
  150. data/lib/makit/tasks/format.rb +10 -10
  151. data/lib/makit/tasks/hook_manager.rb +443 -443
  152. data/lib/makit/tasks/info.rb +368 -368
  153. data/lib/makit/tasks/init.rb +49 -49
  154. data/lib/makit/tasks/integrate.rb +60 -60
  155. data/lib/makit/tasks/pull_incoming.rb +13 -13
  156. data/lib/makit/tasks/secrets.rb +7 -7
  157. data/lib/makit/tasks/setup.rb +16 -16
  158. data/lib/makit/tasks/sync.rb +14 -14
  159. data/lib/makit/tasks/tag.rb +27 -27
  160. data/lib/makit/tasks/task_monkey_patch.rb +81 -81
  161. data/lib/makit/tasks/test.rb +22 -22
  162. data/lib/makit/tasks/update.rb +21 -21
  163. data/lib/makit/tasks/version.rb +6 -6
  164. data/lib/makit/tasks.rb +24 -24
  165. data/lib/makit/test_cache.rb +239 -239
  166. data/lib/makit/tree.rb +37 -37
  167. data/lib/makit/v1/configuration/project_service_impl.rb +370 -370
  168. data/lib/makit/v1/git/git_repository_service_impl.rb +295 -295
  169. data/lib/makit/v1/makit.v1_pb.rb +35 -35
  170. data/lib/makit/v1/makit.v1_services_pb.rb +27 -27
  171. data/lib/makit/v1/services/repository_manager_service_impl.rb +572 -572
  172. data/lib/makit/version.rb +661 -661
  173. data/lib/makit/version_util.rb +21 -21
  174. data/lib/makit/wix.rb +95 -95
  175. data/lib/makit/yaml.rb +29 -29
  176. data/lib/makit/zip.rb +17 -17
  177. data/lib/makit copy.rb +44 -44
  178. data/lib/makit.rb +121 -121
  179. metadata +2 -2
@@ -1,188 +1,188 @@
1
- module Makit
2
- class AzurePipelines
3
- def self.status(project_name: nil, org: nil, project: nil, pipeline_id: nil, pipeline_name: nil, pat: nil)
4
- require "net/http"
5
- require "uri"
6
- require "json"
7
-
8
- # Get organization and project from git remote or environment variables
9
- git_remote = `git remote get-url origin 2>/dev/null`.strip
10
- if git_remote =~ /dev\.azure\.com\/([^\/]+)\/([^\/]+)/
11
- org ||= $1
12
- project ||= $2
13
- else
14
- org ||= ENV["AZURE_DEVOPS_ORG"] || "DevOpsMusco"
15
- project ||= ENV["AZURE_DEVOPS_PROJECT"] || "Design"
16
- end
17
-
18
- # Pipeline ID can be set via environment variable, or we'll try to find it by name
19
- pipeline_id ||= ENV["AZURE_PIPELINE_ID"]
20
- pipeline_name ||= ENV["AZURE_PIPELINE_NAME"] || project_name
21
-
22
- # Display values if show_value is available (from raykit)
23
- if defined?(show_value)
24
- show_value "Organization", org
25
- show_value "Project", project
26
- show_value "Pipeline", pipeline_name
27
- end
28
-
29
- # Try to get access token from parameter, environment variable, or Azure CLI
30
- pat ||= ENV["AZURE_DEVOPS_PAT"]
31
- if pat.nil? || pat.empty?
32
- puts " AZURE_DEVOPS_PAT not set, attempting to use Azure CLI authentication..."
33
- begin
34
- # Get access token for Azure DevOps (resource ID: 499b84ac-1321-427f-aa5e-6d8b3c8c4123)
35
- token_output = `az account get-access-token --resource 499b84ac-1321-427f-aa5e-6d8b3c8c4123 --query accessToken -o tsv 2>&1`
36
- if $?.exitstatus == 0 && !token_output.strip.empty?
37
- pat = token_output.strip
38
- puts " Successfully obtained access token from Azure CLI"
39
- else
40
- raise "Azure CLI authentication failed"
41
- end
42
- rescue => e
43
- puts " Error: Could not get access token from Azure CLI"
44
- puts " Make sure you're logged in: az login"
45
- puts " Or set AZURE_DEVOPS_PAT: export AZURE_DEVOPS_PAT=your_personal_access_token"
46
- exit 1
47
- end
48
- end
49
-
50
- # Helper lambda to set authorization header (Azure AD tokens can use Bearer, PAT uses Basic)
51
- set_auth_header = lambda do |req, token|
52
- # Azure AD tokens are typically longer and can use Bearer auth
53
- # PAT tokens use Basic auth. Try Bearer first for longer tokens, Basic for shorter ones
54
- if token.length > 100
55
- req["Authorization"] = "Bearer #{token}"
56
- else
57
- req.basic_auth("", token)
58
- end
59
- end
60
-
61
- # If pipeline ID is not set, try to find it by name
62
- if pipeline_id.nil? || pipeline_id.empty?
63
- puts " Looking up pipeline ID for '#{pipeline_name}'..."
64
- uri = URI("https://dev.azure.com/#{org}/#{project}/_apis/pipelines?api-version=7.1")
65
- req = Net::HTTP::Get.new(uri)
66
- set_auth_header.call(req, pat)
67
- req["Content-Type"] = "application/json"
68
-
69
- res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
70
- http.request(req)
71
- end
72
-
73
- if res.is_a?(Net::HTTPSuccess)
74
- pipelines = JSON.parse(res.body)["value"]
75
- pipeline = pipelines.find { |p| p["name"] == pipeline_name || p["name"].include?(pipeline_name) }
76
- if pipeline
77
- pipeline_id = pipeline["id"].to_s
78
- puts " Found pipeline ID: #{pipeline_id}"
79
- else
80
- puts " Error: Could not find pipeline '#{pipeline_name}'"
81
- puts " Available pipelines: #{pipelines.map { |p| p["name"] }.join(", ")}"
82
- exit 1
83
- end
84
- else
85
- puts " Error: Failed to list pipelines: #{res.code} #{res.message}"
86
- exit 1
87
- end
88
- end
89
-
90
- # Get the latest pipeline run
91
- puts " Fetching latest pipeline run..."
92
- uri = URI("https://dev.azure.com/#{org}/#{project}/_apis/pipelines/#{pipeline_id}/runs")
93
- params = {
94
- "$top" => 1,
95
- "api-version" => "7.1",
96
- }
97
- uri.query = URI.encode_www_form(params)
98
-
99
- req = Net::HTTP::Get.new(uri)
100
- set_auth_header.call(req, pat)
101
- req["Content-Type"] = "application/json"
102
-
103
- res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
104
- http.request(req)
105
- end
106
-
107
- if res.is_a?(Net::HTTPSuccess)
108
- body = JSON.parse(res.body)
109
- if body["value"] && body["value"].length > 0
110
- run = body["value"].first
111
- result = run["result"] || "unknown"
112
- state = run["state"] || "unknown"
113
- build_number = run["name"] || run["id"].to_s
114
- finish_time = run["finishedDate"] || run["createdDate"] || "N/A"
115
- url = run["_links"] && run["_links"]["web"] ? run["_links"]["web"]["href"] : "https://dev.azure.com/#{org}/#{project}/_build/results?buildId=#{run["id"]}"
116
-
117
- puts " Latest Run:"
118
- puts " Build Number: #{build_number}"
119
- puts " State: #{state}"
120
- puts " Result: #{result}"
121
- puts " Finished: #{finish_time}"
122
- puts " URL: #{url}"
123
- else
124
- puts " No pipeline runs found yet."
125
- end
126
- else
127
- puts " Error: Failed to fetch pipeline runs: #{res.code} #{res.message}"
128
- if res.body
129
- error_body = JSON.parse(res.body) rescue nil
130
- if error_body && error_body["message"]
131
- puts " Message: #{error_body["message"]}"
132
- end
133
- end
134
- exit 1
135
- end
136
- end
137
- # Publishes a NuGet package to an Azure DevOps feed
138
- #
139
- # @param package_name [String] The name of the NuGet package
140
- # @param package_version [String] The version of the package
141
- # @param package_file [String] Path to the .nupkg file
142
- # @param feed_source [String] The name of the Azure DevOps feed
143
- # @param api_key [String, nil] Optional API key (defaults to "az" for Azure CLI)
144
- # @raise [RuntimeError] If the push fails and it's not a duplicate package error
145
- def self.publish(package_name:, package_version:, package_file:, feed_source:, api_key: "az")
146
- puts " Checking if package #{package_name} version #{package_version} already exists in feed..."
147
-
148
- # Check if package version already exists
149
- list_command = "dotnet nuget list \"#{package_name}\" --source \"#{feed_source}\" --api-key #{api_key}"
150
- list_output = `#{list_command} 2>&1`
151
- list_exit_code = $?.exitstatus
152
-
153
- if list_exit_code == 0 && list_output.include?(package_version)
154
- puts " Package #{package_name} version #{package_version} already exists in feed. Skipping push."
155
- elsif list_exit_code != 0 && list_output =~ /401|Unauthorized|credential/i
156
- puts " Authentication failed when checking feed. Will attempt to push anyway."
157
- puts " (To check manually, run: #{list_command} --interactive)"
158
- push_package(package_file: package_file, feed_source: feed_source, api_key: api_key, package_name: package_name, package_version: package_version)
159
- else
160
- puts " Package #{package_name} version #{package_version} not found in feed (or unable to verify). Attempting to push..."
161
- push_package(package_file: package_file, feed_source: feed_source, api_key: api_key, package_name: package_name, package_version: package_version)
162
- end
163
- end
164
-
165
- private
166
-
167
- def self.push_package(package_file:, feed_source:, api_key:, package_name:, package_version:)
168
- push_command = "dotnet nuget push \"#{package_file}\" --source \"#{feed_source}\" --api-key #{api_key} --skip-duplicate"
169
- push_output = `#{push_command} 2>&1`
170
- push_exit_code = $?.exitstatus
171
-
172
- if push_exit_code == 0
173
- puts " Package pushed successfully to #{feed_source} feed."
174
- elsif push_output =~ /already exists|conflict|409/i
175
- puts " Package #{package_name} version #{package_version} already exists in feed. This is expected."
176
- else
177
- puts " Error pushing package to #{feed_source} feed:"
178
- puts push_output
179
- puts ""
180
- puts " To retry manually, run:"
181
- puts " #{push_command} --interactive"
182
- puts ""
183
- raise "Failed to push package to #{feed_source} feed"
184
- end
185
- end
186
- end
187
- end
1
+ module Makit
2
+ class AzurePipelines
3
+ def self.status(project_name: nil, org: nil, project: nil, pipeline_id: nil, pipeline_name: nil, pat: nil)
4
+ require "net/http"
5
+ require "uri"
6
+ require "json"
7
+
8
+ # Get organization and project from git remote or environment variables
9
+ git_remote = `git remote get-url origin 2>/dev/null`.strip
10
+ if git_remote =~ /dev\.azure\.com\/([^\/]+)\/([^\/]+)/
11
+ org ||= $1
12
+ project ||= $2
13
+ else
14
+ org ||= ENV["AZURE_DEVOPS_ORG"] || "DevOpsMusco"
15
+ project ||= ENV["AZURE_DEVOPS_PROJECT"] || "Design"
16
+ end
17
+
18
+ # Pipeline ID can be set via environment variable, or we'll try to find it by name
19
+ pipeline_id ||= ENV["AZURE_PIPELINE_ID"]
20
+ pipeline_name ||= ENV["AZURE_PIPELINE_NAME"] || project_name
21
+
22
+ # Display values if show_value is available (from raykit)
23
+ if defined?(show_value)
24
+ show_value "Organization", org
25
+ show_value "Project", project
26
+ show_value "Pipeline", pipeline_name
27
+ end
28
+
29
+ # Try to get access token from parameter, environment variable, or Azure CLI
30
+ pat ||= ENV["AZURE_DEVOPS_PAT"]
31
+ if pat.nil? || pat.empty?
32
+ puts " AZURE_DEVOPS_PAT not set, attempting to use Azure CLI authentication..."
33
+ begin
34
+ # Get access token for Azure DevOps (resource ID: 499b84ac-1321-427f-aa5e-6d8b3c8c4123)
35
+ token_output = `az account get-access-token --resource 499b84ac-1321-427f-aa5e-6d8b3c8c4123 --query accessToken -o tsv 2>&1`
36
+ if $?.exitstatus == 0 && !token_output.strip.empty?
37
+ pat = token_output.strip
38
+ puts " Successfully obtained access token from Azure CLI"
39
+ else
40
+ raise "Azure CLI authentication failed"
41
+ end
42
+ rescue => e
43
+ puts " Error: Could not get access token from Azure CLI"
44
+ puts " Make sure you're logged in: az login"
45
+ puts " Or set AZURE_DEVOPS_PAT: export AZURE_DEVOPS_PAT=your_personal_access_token"
46
+ exit 1
47
+ end
48
+ end
49
+
50
+ # Helper lambda to set authorization header (Azure AD tokens can use Bearer, PAT uses Basic)
51
+ set_auth_header = lambda do |req, token|
52
+ # Azure AD tokens are typically longer and can use Bearer auth
53
+ # PAT tokens use Basic auth. Try Bearer first for longer tokens, Basic for shorter ones
54
+ if token.length > 100
55
+ req["Authorization"] = "Bearer #{token}"
56
+ else
57
+ req.basic_auth("", token)
58
+ end
59
+ end
60
+
61
+ # If pipeline ID is not set, try to find it by name
62
+ if pipeline_id.nil? || pipeline_id.empty?
63
+ puts " Looking up pipeline ID for '#{pipeline_name}'..."
64
+ uri = URI("https://dev.azure.com/#{org}/#{project}/_apis/pipelines?api-version=7.1")
65
+ req = Net::HTTP::Get.new(uri)
66
+ set_auth_header.call(req, pat)
67
+ req["Content-Type"] = "application/json"
68
+
69
+ res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
70
+ http.request(req)
71
+ end
72
+
73
+ if res.is_a?(Net::HTTPSuccess)
74
+ pipelines = JSON.parse(res.body)["value"]
75
+ pipeline = pipelines.find { |p| p["name"] == pipeline_name || p["name"].include?(pipeline_name) }
76
+ if pipeline
77
+ pipeline_id = pipeline["id"].to_s
78
+ puts " Found pipeline ID: #{pipeline_id}"
79
+ else
80
+ puts " Error: Could not find pipeline '#{pipeline_name}'"
81
+ puts " Available pipelines: #{pipelines.map { |p| p["name"] }.join(", ")}"
82
+ exit 1
83
+ end
84
+ else
85
+ puts " Error: Failed to list pipelines: #{res.code} #{res.message}"
86
+ exit 1
87
+ end
88
+ end
89
+
90
+ # Get the latest pipeline run
91
+ puts " Fetching latest pipeline run..."
92
+ uri = URI("https://dev.azure.com/#{org}/#{project}/_apis/pipelines/#{pipeline_id}/runs")
93
+ params = {
94
+ "$top" => 1,
95
+ "api-version" => "7.1",
96
+ }
97
+ uri.query = URI.encode_www_form(params)
98
+
99
+ req = Net::HTTP::Get.new(uri)
100
+ set_auth_header.call(req, pat)
101
+ req["Content-Type"] = "application/json"
102
+
103
+ res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
104
+ http.request(req)
105
+ end
106
+
107
+ if res.is_a?(Net::HTTPSuccess)
108
+ body = JSON.parse(res.body)
109
+ if body["value"] && body["value"].length > 0
110
+ run = body["value"].first
111
+ result = run["result"] || "unknown"
112
+ state = run["state"] || "unknown"
113
+ build_number = run["name"] || run["id"].to_s
114
+ finish_time = run["finishedDate"] || run["createdDate"] || "N/A"
115
+ url = run["_links"] && run["_links"]["web"] ? run["_links"]["web"]["href"] : "https://dev.azure.com/#{org}/#{project}/_build/results?buildId=#{run["id"]}"
116
+
117
+ puts " Latest Run:"
118
+ puts " Build Number: #{build_number}"
119
+ puts " State: #{state}"
120
+ puts " Result: #{result}"
121
+ puts " Finished: #{finish_time}"
122
+ puts " URL: #{url}"
123
+ else
124
+ puts " No pipeline runs found yet."
125
+ end
126
+ else
127
+ puts " Error: Failed to fetch pipeline runs: #{res.code} #{res.message}"
128
+ if res.body
129
+ error_body = JSON.parse(res.body) rescue nil
130
+ if error_body && error_body["message"]
131
+ puts " Message: #{error_body["message"]}"
132
+ end
133
+ end
134
+ exit 1
135
+ end
136
+ end
137
+ # Publishes a NuGet package to an Azure DevOps feed
138
+ #
139
+ # @param package_name [String] The name of the NuGet package
140
+ # @param package_version [String] The version of the package
141
+ # @param package_file [String] Path to the .nupkg file
142
+ # @param feed_source [String] The name of the Azure DevOps feed
143
+ # @param api_key [String, nil] Optional API key (defaults to "az" for Azure CLI)
144
+ # @raise [RuntimeError] If the push fails and it's not a duplicate package error
145
+ def self.publish(package_name:, package_version:, package_file:, feed_source:, api_key: "az")
146
+ puts " Checking if package #{package_name} version #{package_version} already exists in feed..."
147
+
148
+ # Check if package version already exists
149
+ list_command = "dotnet nuget list \"#{package_name}\" --source \"#{feed_source}\" --api-key #{api_key}"
150
+ list_output = `#{list_command} 2>&1`
151
+ list_exit_code = $?.exitstatus
152
+
153
+ if list_exit_code == 0 && list_output.include?(package_version)
154
+ puts " Package #{package_name} version #{package_version} already exists in feed. Skipping push."
155
+ elsif list_exit_code != 0 && list_output =~ /401|Unauthorized|credential/i
156
+ puts " Authentication failed when checking feed. Will attempt to push anyway."
157
+ puts " (To check manually, run: #{list_command} --interactive)"
158
+ push_package(package_file: package_file, feed_source: feed_source, api_key: api_key, package_name: package_name, package_version: package_version)
159
+ else
160
+ puts " Package #{package_name} version #{package_version} not found in feed (or unable to verify). Attempting to push..."
161
+ push_package(package_file: package_file, feed_source: feed_source, api_key: api_key, package_name: package_name, package_version: package_version)
162
+ end
163
+ end
164
+
165
+ private
166
+
167
+ def self.push_package(package_file:, feed_source:, api_key:, package_name:, package_version:)
168
+ push_command = "dotnet nuget push \"#{package_file}\" --source \"#{feed_source}\" --api-key #{api_key} --skip-duplicate"
169
+ push_output = `#{push_command} 2>&1`
170
+ push_exit_code = $?.exitstatus
171
+
172
+ if push_exit_code == 0
173
+ puts " Package pushed successfully to #{feed_source} feed."
174
+ elsif push_output =~ /already exists|conflict|409/i
175
+ puts " Package #{package_name} version #{package_version} already exists in feed. This is expected."
176
+ else
177
+ puts " Error pushing package to #{feed_source} feed:"
178
+ puts push_output
179
+ puts ""
180
+ puts " To retry manually, run:"
181
+ puts " #{push_command} --interactive"
182
+ puts ""
183
+ raise "Failed to push package to #{feed_source} feed"
184
+ end
185
+ end
186
+ end
187
+ end
188
188
 
@@ -1,17 +1,17 @@
1
- # frozen_string_literal: true
2
-
3
- require "clamp"
4
-
5
- module Makit
6
- module Cli
7
- # Base class for CLI commands
8
- class Base < Clamp::Command
9
- # Common functionality for CLI commands can be added here
10
-
11
- # Helper method to define command descriptions
12
- def self.desc(command_name, description)
13
- self.description = "#{command_name} - #{description}"
14
- end
15
- end
16
- end
17
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "clamp"
4
+
5
+ module Makit
6
+ module Cli
7
+ # Base class for CLI commands
8
+ class Base < Clamp::Command
9
+ # Common functionality for CLI commands can be added here
10
+
11
+ # Helper method to define command descriptions
12
+ def self.desc(command_name, description)
13
+ self.description = "#{command_name} - #{description}"
14
+ end
15
+ end
16
+ end
17
+ end