makit 0.0.166 → 0.0.168
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/lib/makit/azure-pipelines.rb +49 -0
- data/lib/makit/github_actions.rb +202 -0
- data/lib/makit/nuget.rb +4 -0
- data/lib/makit/version.rb +1 -1
- data/lib/makit.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6be9a6673223fda1b260a75ffa168c9026b68772629f2ef8b81af2bb715cfecc
|
|
4
|
+
data.tar.gz: ef19ab60e4dca86f30846a46845c3eda58f5942b6c60392bb042aa87299201ab
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5eb9e71e09ed6b633b21c9563377c6e58ae62265be8c4404f8b3c7513c4783f7f5f85abc56f7aeaff0d794cfafb86acbddda79b669be45d4e0fd19a234f00b54
|
|
7
|
+
data.tar.gz: 4db9d4220b6a300a7f86d5bd9d3ad962400777a6f5adf1d73cbed93c5b62f8bb49c606c54889bd45806a572ebeea64f2048b9142f1864e91035f7e4ba2336cb2
|
|
@@ -134,6 +134,55 @@ module Makit
|
|
|
134
134
|
exit 1
|
|
135
135
|
end
|
|
136
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
|
|
137
186
|
end
|
|
138
187
|
end
|
|
139
188
|
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
require "net/http"
|
|
2
|
+
require "json"
|
|
3
|
+
require "uri"
|
|
4
|
+
|
|
5
|
+
module Makit
|
|
6
|
+
module GitHubActions
|
|
7
|
+
# Gets the current git branch, defaulting to "main" if not available
|
|
8
|
+
#
|
|
9
|
+
# @return [String] Current branch name
|
|
10
|
+
def self.get_current_branch
|
|
11
|
+
branch = `git rev-parse --abbrev-ref HEAD`.strip
|
|
12
|
+
branch.empty? ? "main" : branch
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Gets GitHub token from secrets or environment variable
|
|
16
|
+
#
|
|
17
|
+
# @return [String, nil] GitHub token if available
|
|
18
|
+
def self.get_token
|
|
19
|
+
if defined?(Makit::Secrets) && Makit::Secrets.has_key?("github_token")
|
|
20
|
+
Makit::Secrets.get("github_token")
|
|
21
|
+
else
|
|
22
|
+
ENV["GITHUB_TOKEN"]
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Formats and displays workflow status information
|
|
27
|
+
#
|
|
28
|
+
# @param result [Hash] Workflow status result from workflow_status
|
|
29
|
+
# @param owner [String] Repository owner (for display)
|
|
30
|
+
# @param repo [String] Repository name (for display)
|
|
31
|
+
# @param branch [String] Branch name (for display)
|
|
32
|
+
def self.display_status(result, owner, repo, branch)
|
|
33
|
+
if result[:status] == "not_found"
|
|
34
|
+
puts "⚠️ #{result[:message]}"
|
|
35
|
+
else
|
|
36
|
+
status_emoji = case result[:conclusion]
|
|
37
|
+
when "success"
|
|
38
|
+
"✅"
|
|
39
|
+
when "failure"
|
|
40
|
+
"❌"
|
|
41
|
+
when "cancelled"
|
|
42
|
+
"🚫"
|
|
43
|
+
when nil
|
|
44
|
+
result[:status] == "completed" ? "⏸️" : "🔄"
|
|
45
|
+
else
|
|
46
|
+
"❓"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
puts "\n#{status_emoji} Workflow Status: #{result[:workflow_name] || "Unknown"}"
|
|
50
|
+
puts " Status: #{result[:status]}"
|
|
51
|
+
puts " Conclusion: #{result[:conclusion] || "N/A"}" if result[:conclusion]
|
|
52
|
+
puts " Run Number: ##{result[:run_number]}" if result[:run_number]
|
|
53
|
+
puts " Created: #{result[:created_at]}" if result[:created_at]
|
|
54
|
+
puts " Updated: #{result[:updated_at]}" if result[:updated_at]
|
|
55
|
+
puts " URL: #{result[:html_url]}" if result[:html_url]
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Queries and displays GitHub Actions workflow status
|
|
60
|
+
# Handles all logic including branch detection, token retrieval, and output formatting
|
|
61
|
+
#
|
|
62
|
+
# @param branch [String, nil] Branch name to query (default: auto-detect from git)
|
|
63
|
+
# @param workflow_id [String, nil] Specific workflow ID to query (optional)
|
|
64
|
+
# @param token [String, nil] GitHub Personal Access Token (optional, will try secrets/env if not provided)
|
|
65
|
+
# @raise [RuntimeError] If authentication fails or API error occurs
|
|
66
|
+
def self.query_and_display_status(branch: nil, workflow_id: nil, token: nil)
|
|
67
|
+
branch ||= get_current_branch
|
|
68
|
+
owner, repo = get_repo_from_git
|
|
69
|
+
|
|
70
|
+
puts "Querying GitHub Actions status for #{owner}/#{repo} (branch: #{branch})..."
|
|
71
|
+
|
|
72
|
+
token ||= get_token
|
|
73
|
+
if token.nil? || token.empty?
|
|
74
|
+
puts "github_token SECRET not available"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
result = workflow_status(branch: branch, workflow_id: workflow_id, token: token)
|
|
78
|
+
display_status(result, owner, repo, branch)
|
|
79
|
+
rescue => e
|
|
80
|
+
puts "❌ Error: #{e.message}"
|
|
81
|
+
raise
|
|
82
|
+
end
|
|
83
|
+
# Extracts GitHub repository owner and name from a URL or git remote URL
|
|
84
|
+
#
|
|
85
|
+
# @param url [String] GitHub repository URL (https://github.com/owner/repo or git@github.com:owner/repo)
|
|
86
|
+
# @return [Array<String>] Array containing [owner, repo_name]
|
|
87
|
+
# @raise [ArgumentError] If URL cannot be parsed
|
|
88
|
+
#
|
|
89
|
+
# @example HTTPS URL format
|
|
90
|
+
# parse_repo_url("https://github.com/node-net/Node.Net.git")
|
|
91
|
+
# # => ["node-net", "Node.Net"]
|
|
92
|
+
#
|
|
93
|
+
# @example SSH URL format
|
|
94
|
+
# parse_repo_url("git@github.com:node-net/Node.Net.git")
|
|
95
|
+
# # => ["node-net", "Node.Net"]
|
|
96
|
+
#
|
|
97
|
+
# @example URL without .git extension
|
|
98
|
+
# parse_repo_url("https://github.com/microsoft/dotnet")
|
|
99
|
+
# # => ["microsoft", "dotnet"]
|
|
100
|
+
def self.parse_repo_url(url)
|
|
101
|
+
match = url.match(%r{github\.com[:/]([^/]+)/([^/]+)(?:\.git)?$})
|
|
102
|
+
if match
|
|
103
|
+
owner = match[1]
|
|
104
|
+
repo = match[2].gsub(/\.git$/, "")
|
|
105
|
+
return [owner, repo]
|
|
106
|
+
else
|
|
107
|
+
raise ArgumentError, "Could not parse GitHub repository from URL: #{url}"
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Gets GitHub repository info from git remote origin
|
|
112
|
+
#
|
|
113
|
+
# @return [Array<String>] Array containing [owner, repo_name]
|
|
114
|
+
# @raise [RuntimeError] If git remote URL cannot be determined or parsed
|
|
115
|
+
def self.get_repo_from_git
|
|
116
|
+
remote_url = `git config --get remote.origin.url`.strip
|
|
117
|
+
if remote_url.empty?
|
|
118
|
+
raise "Could not determine git remote URL. Make sure you're in a git repository with a remote configured."
|
|
119
|
+
end
|
|
120
|
+
parse_repo_url(remote_url)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Queries GitHub Actions API for workflow run status
|
|
124
|
+
#
|
|
125
|
+
# @param owner [String, nil] Repository owner (required if repo_url is nil)
|
|
126
|
+
# @param repo [String, nil] Repository name (required if repo_url is nil)
|
|
127
|
+
# @param repo_url [String, nil] GitHub repository URL or git remote URL (alternative to owner/repo)
|
|
128
|
+
# @param workflow_id [String, nil] Specific workflow ID to query (optional)
|
|
129
|
+
# @param branch [String] Branch name to query (default: "main")
|
|
130
|
+
# @param token [String, nil] GitHub Personal Access Token (optional, will use GITHUB_TOKEN env var if not provided)
|
|
131
|
+
# @return [Hash] Workflow status information
|
|
132
|
+
# @raise [RuntimeError] If authentication fails or API error occurs
|
|
133
|
+
def self.workflow_status(owner: nil, repo: nil, repo_url: nil, workflow_id: nil, branch: "main", token: nil)
|
|
134
|
+
# Determine owner and repo from URL if provided
|
|
135
|
+
if repo_url
|
|
136
|
+
owner, repo = parse_repo_url(repo_url)
|
|
137
|
+
elsif owner.nil? || repo.nil?
|
|
138
|
+
# Try to get from git if not provided
|
|
139
|
+
owner, repo = get_repo_from_git
|
|
140
|
+
end
|
|
141
|
+
# Token should be provided by caller, but fallback to environment variable if not provided
|
|
142
|
+
token ||= ENV["GITHUB_TOKEN"]
|
|
143
|
+
|
|
144
|
+
if token.nil? || token.empty?
|
|
145
|
+
raise "GitHub token not found. Set GITHUB_TOKEN environment variable or configure github_token secret."
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
base_url = "https://api.github.com/repos/#{owner}/#{repo}"
|
|
149
|
+
|
|
150
|
+
if workflow_id
|
|
151
|
+
# Get status for a specific workflow
|
|
152
|
+
url = "#{base_url}/actions/workflows/#{workflow_id}/runs?branch=#{branch}&per_page=1"
|
|
153
|
+
else
|
|
154
|
+
# Get status for all workflows (latest run)
|
|
155
|
+
url = "#{base_url}/actions/runs?branch=#{branch}&per_page=1"
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
uri = URI(url)
|
|
159
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
160
|
+
http.use_ssl = true
|
|
161
|
+
|
|
162
|
+
request = Net::HTTP::Get.new(uri)
|
|
163
|
+
request["Accept"] = "application/vnd.github.v3+json"
|
|
164
|
+
request["Authorization"] = "Bearer #{token}"
|
|
165
|
+
request["User-Agent"] = "Node.Net-Rake-Task"
|
|
166
|
+
|
|
167
|
+
response = http.request(request)
|
|
168
|
+
|
|
169
|
+
case response.code.to_i
|
|
170
|
+
when 200
|
|
171
|
+
data = JSON.parse(response.body)
|
|
172
|
+
runs = data["workflow_runs"] || []
|
|
173
|
+
|
|
174
|
+
if runs.empty?
|
|
175
|
+
return {
|
|
176
|
+
status: "not_found",
|
|
177
|
+
message: "No workflow runs found for branch '#{branch}'",
|
|
178
|
+
}
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
latest_run = runs.first
|
|
182
|
+
workflow_name = latest_run["name"] || latest_run.dig("workflow", "name") || "Unknown"
|
|
183
|
+
|
|
184
|
+
{
|
|
185
|
+
status: latest_run["status"], # queued, in_progress, completed
|
|
186
|
+
conclusion: latest_run["conclusion"], # success, failure, cancelled, etc.
|
|
187
|
+
workflow_name: workflow_name,
|
|
188
|
+
run_number: latest_run["run_number"],
|
|
189
|
+
html_url: latest_run["html_url"],
|
|
190
|
+
created_at: latest_run["created_at"],
|
|
191
|
+
updated_at: latest_run["updated_at"],
|
|
192
|
+
}
|
|
193
|
+
when 401
|
|
194
|
+
raise "GitHub API authentication failed. Check your token."
|
|
195
|
+
when 404
|
|
196
|
+
raise "Repository #{owner}/#{repo} not found or access denied."
|
|
197
|
+
else
|
|
198
|
+
raise "GitHub API error: #{response.code} - #{response.message}"
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
data/lib/makit/nuget.rb
CHANGED
|
@@ -64,6 +64,10 @@ module Makit
|
|
|
64
64
|
system("dotnet nuget push #{path} --source #{path}")
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
+
def self.publish(package, api_key, source)
|
|
68
|
+
"dotnet nuget push #{package} --skip-duplicate --api-key #{api_key} --source #{source}".run
|
|
69
|
+
end
|
|
70
|
+
|
|
67
71
|
def self.publish_to_directory(nuget_package_path, directory, package_name, version)
|
|
68
72
|
target_package_path = "#{directory}/#{package_name}/#{version}/#{package_name}.#{version}.nupkg".downcase
|
|
69
73
|
if File.exist?(target_package_path)
|
data/lib/makit/version.rb
CHANGED
data/lib/makit.rb
CHANGED
|
@@ -24,6 +24,7 @@ require_relative "makit/rubygems"
|
|
|
24
24
|
require_relative "makit/azure/cli"
|
|
25
25
|
require_relative "makit/azure/blob_storage"
|
|
26
26
|
require_relative "makit/azure-pipelines"
|
|
27
|
+
require_relative "makit/github_actions"
|
|
27
28
|
require_relative "makit/humanize"
|
|
28
29
|
require_relative "makit/directories"
|
|
29
30
|
require_relative "makit/exceptions"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: makit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.168
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Lou Parslow
|
|
@@ -312,6 +312,7 @@ files:
|
|
|
312
312
|
- lib/makit/git.rb
|
|
313
313
|
- lib/makit/git/cli.rb
|
|
314
314
|
- lib/makit/git/repository.rb
|
|
315
|
+
- lib/makit/github_actions.rb
|
|
315
316
|
- lib/makit/gitlab/pipeline.rb
|
|
316
317
|
- lib/makit/gitlab/pipeline_service_impl.rb
|
|
317
318
|
- lib/makit/gitlab_runner.rb
|