Skip to content

Commit 939b99e

Browse files
committed
release: trigger release processes when release workflow succeeded
GitHub: groongaGH-43 In this PR, we set up how release flow is triggered from webhook requests.
1 parent d809eca commit 939b99e

File tree

2 files changed

+143
-2
lines changed

2 files changed

+143
-2
lines changed

ansible/files/home/deployer/webhook/lib/deployer/app.rb

+63-2
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,18 @@
1414
# You should have received a copy of the GNU General Public License
1515
# along with this program. If not, see <https://www.gnu.org/licenses/>.
1616

17+
require "json"
1718
require "openssl"
19+
require_relative "payload"
1820
require_relative "response"
21+
require_relative "source-archive"
1922

2023
module Deployer
2124
class App
2225
def call(env)
2326
request = Rack::Request.new(env)
2427
response = Response.new
25-
process(request, response)
26-
response.finish
28+
process(request, response) || response.finish
2729
end
2830

2931
private
@@ -38,6 +40,10 @@ def process(request, response)
3840
response.set(:unauthorized, "Authorization failed")
3941
return
4042
end
43+
44+
payload = parse_payload(request, response)
45+
return if payload.nil?
46+
process_payload(request, response, payload)
4147
end
4248

4349
def valid_signature?(request)
@@ -47,5 +53,60 @@ def valid_signature?(request)
4753
signature = "sha256=#{hmac_sha256}"
4854
Rack::Utils.secure_compare(signature, request.env["HTTP_X_HUB_SIGNATURE_256"])
4955
end
56+
57+
def parse_payload(request, response)
58+
unless request.media_type == "application/json"
59+
response.set(:bad_request, "invalid payload format")
60+
return
61+
end
62+
63+
payload = request.body.read
64+
if payload.nil?
65+
response.set(:bad_request, "payload is missing")
66+
return
67+
end
68+
69+
begin
70+
JSON.parse(payload)
71+
rescue JSON::ParserError
72+
response.set(:bad_request, "invalid JSON format: <#{$!.message}>")
73+
nil
74+
end
75+
end
76+
77+
def process_payload(request, response, raw_payload)
78+
metadata = {
79+
"x-github-event" => request.env["HTTP_X_GITHUB_EVENT"]
80+
}
81+
82+
payload = Payload.new(raw_payload, metadata)
83+
84+
case payload.event_name
85+
when "ping"
86+
# Do nothing because this is a kind of healthcheck.
87+
nil
88+
when "workflow_run"
89+
return unless payload.released?
90+
process_release(request, response, payload)
91+
else
92+
response.set(:bad_request,
93+
"Unsupported event: <#{payload.event_name}>")
94+
nil
95+
end
96+
end
97+
98+
def process_release(request, response, payload)
99+
response.finish do
100+
Thread.new do
101+
gpg_key_id = "TODO: handle a GPG key"
102+
archive = Deployer::SourceArchive.new(payload.repository_owner,
103+
payload.repository_name,
104+
payload.repository_name,
105+
payload.version,
106+
payload.branch)
107+
archive.process(gpg_key_id)
108+
end
109+
end
110+
end
50111
end
51112
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Copyright (C) 2010-2019 Sutou Kouhei <[email protected]>
2+
# Copyright (C) 2015 Kenji Okimoto <[email protected]>
3+
# Copyright (C) 2024 Takuya Kodama <[email protected]>
4+
#
5+
# This program is free software: you can redistribute it and/or modify
6+
# it under the terms of the GNU General Public License as published by
7+
# the Free Software Foundation, either version 3 of the License, or
8+
# (at your option) any later version.
9+
#
10+
# This program is distributed in the hope that it will be useful,
11+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
# GNU General Public License for more details.
14+
#
15+
# You should have received a copy of the GNU General Public License
16+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
18+
module Deployer
19+
class Payload
20+
RELEASE_WORKFLOWS= ["Package"].map(&:freeze).freeze
21+
22+
def initialize(data, metadata={})
23+
@data = data
24+
@metadata = metadata
25+
end
26+
27+
def [](key)
28+
key.split(".").inject(@data) do |current_data, current_key|
29+
if current_data
30+
current_data[current_key]
31+
else
32+
nil
33+
end
34+
end
35+
end
36+
37+
def event_name
38+
@metadata["x-github-event"]
39+
end
40+
41+
def workflow_name
42+
self["workflow_run.name"]
43+
end
44+
45+
def workflow_succeeded?
46+
self["workflow_run.conclusion"] == "success"
47+
end
48+
49+
def branch
50+
self["workflow_run.head_branch"]
51+
end
52+
53+
def version
54+
return if workflow_tag?
55+
branch.delete_prefix("v")
56+
end
57+
58+
def released?
59+
RELEASE_WORKFLOWS.include?(workflow_name) &&
60+
workflow_tag? &&
61+
workflow_succeeded?
62+
end
63+
64+
def repository_owner
65+
owner = self["repository.owner"] || {}
66+
owner["login"]
67+
end
68+
69+
def repository_name
70+
self["repository.name"]
71+
end
72+
73+
private
74+
75+
def workflow_tag?
76+
return if branch
77+
branch.match?(/^v\d+(\.\d+){2}$/)
78+
end
79+
end
80+
end

0 commit comments

Comments
 (0)