Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

release: trigger release processes when release workflow succeeded #47

Merged
merged 39 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
939b99e
release: trigger release processes when release workflow succeeded
otegami Dec 12, 2024
61d9a1b
skip executing release tasks
otegami Dec 19, 2024
999fb07
Simplify
komainu8 Dec 19, 2024
2171649
Fix wrong condition
komainu8 Dec 19, 2024
562c585
Fix wrong condition
komainu8 Dec 19, 2024
6884ce5
Revert "Simplify"
komainu8 Dec 20, 2024
5e8fa4a
Use excption
komainu8 Dec 20, 2024
be6e11d
Remove needless require
komainu8 Dec 20, 2024
99af4b6
Remove needless return value
komainu8 Dec 20, 2024
c9a8823
Use more suitable name
komainu8 Dec 20, 2024
3c1b253
Use exception
komainu8 Dec 20, 2024
1a83b0a
Return payload
komainu8 Dec 20, 2024
f4f916f
Use exception
komainu8 Dec 20, 2024
7273386
Add a new line
komainu8 Dec 20, 2024
752a436
Set proc
komainu8 Dec 20, 2024
7e7728f
Remove needless return
komainu8 Dec 20, 2024
d052250
Use more suitable name
komainu8 Dec 20, 2024
9657fee
Fix wrong method name
komainu8 Dec 20, 2024
9224946
call asynchronous release tasks
otegami Dec 20, 2024
31fd835
Remove unnecessary arguments because we don't use them anymore
otegami Dec 20, 2024
2bb1a88
Remove a needless argument
komainu8 Dec 20, 2024
07b433e
Add a necessary argument
komainu8 Dec 20, 2024
bc59737
Use more suitable name
komainu8 Dec 20, 2024
4a6812a
Use more suitable name
komainu8 Dec 20, 2024
a548d2e
Fix wrong name
komainu8 Dec 20, 2024
469ad67
Fix wrong name
komainu8 Dec 20, 2024
764ce39
Raise error status
komainu8 Dec 20, 2024
be34927
Remove unnecessary freeze
otegami Dec 23, 2024
15cd16d
refactor Deploy::Payload#[] using Hash#dig
otegami Dec 23, 2024
f3eecfd
Simplify the logic using dig method
otegami Dec 23, 2024
a39c792
Fix the condition of checking the tag because Mroonga's tag is like vX.Y
otegami Dec 23, 2024
1481c70
add Deploer::RequestError class to handle the webhook errors
otegami Dec 23, 2024
b48457a
add `!` because it might raise exceptions
otegami Dec 23, 2024
0be9ff2
call asynchronous release tasks
otegami Dec 23, 2024
2f40dc8
add todo comments which we will deal with in the following PRs
otegami Dec 23, 2024
89dc83f
Remove unnecessary Deployer::Response#set_finish_proc
otegami Dec 23, 2024
e0b7514
add CMake workflow to the release targets for Windows packages
otegami Dec 23, 2024
d94d95d
fix formats
otegami Dec 23, 2024
bceac4f
fix regular expressions because we will just use the string without line
otegami Dec 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 59 additions & 10 deletions ansible/files/home/deployer/webhook/lib/deployer/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

require "json"
require "openssl"
require_relative "payload"
require_relative "response"

module Deployer
Expand All @@ -29,23 +31,70 @@ def call(env)
private

def process(request, response)
unless request.post?
response.set(:method_not_allowed, "must POST")
return
end

unless valid_signature?(request)
response.set(:unauthorized, "Authorization failed")
return
begin
unless request.post?
raise RequestError.new(:method_not_allowed, "must POST")
end
verify_signature!(request)
payload = parse_body!(request)
process_payload!(payload)
rescue RequestError => request_error
response.set(request_error.status, request_error.message)
rescue => e
response.set(:internal_server_error, e.message)
end
end

def valid_signature?(request)
def verify_signature!(request)
hmac_sha256 = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"),
ENV["SECRET_TOKEN"],
request.body.read)
signature = "sha256=#{hmac_sha256}"
Rack::Utils.secure_compare(signature, request.env["HTTP_X_HUB_SIGNATURE_256"])
unless Rack::Utils.secure_compare(signature, request.env["HTTP_X_HUB_SIGNATURE_256"])
raise RequestError.new(:unauthorized, "Authorization failed")
end
end

def parse_body!(request)
unless request.media_type == "application/json"
raise RequestError.new(:bad_request, "invalid payload format")
end

body = request.body.read
if body.nil?
raise RequestError.new(:bad_request, "request body is missing")
end

begin
raw_payload = JSON.parse(body)
rescue JSON::ParserError
raise RequestError.new(:bad_request, "invalid JSON format: <#{$!.message}>")
end

metadata = {
"x-github-event" => request.env["HTTP_X_GITHUB_EVENT"]
}
Payload.new(raw_payload, metadata)
end

def process_payload!(payload)
case payload.event_name
when "ping"
# Do nothing because this is a kind of healthcheck.
nil
otegami marked this conversation as resolved.
Show resolved Hide resolved
when "workflow_run"
return unless payload.released?
deploy(payload)
else
raise RequestError.new(:bad_request, "Unsupported event: <#{payload.event_name}>")
end
end

def deploy(payload)
Thread.new do
# TODO: call rake tasks for sign packages.
# TODO: write down the errors into log files.
end
end
end
end
29 changes: 29 additions & 0 deletions ansible/files/home/deployer/webhook/lib/deployer/error.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright (C) 2024 Horimoto Yasuhiro <[email protected]>
# Copyright (C) 2024 Takuya Kodama <[email protected]>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

module Deployer
class Error < StandardError
end

class RequestError < Error
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

よくわかってなくて初歩的な質問ですみません。
Error をはさむときと RequestError < StandardError するときとどういう違いがあるのですか?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rubyは継承できるクラスが一つなので、今後拡張しやすいようにErrorのベースクラスは別で置いて置きたくて、このようにしてみました。(ただ、今回はまだ拡張予定が直近ではないのでなくても問題ないです。)

attr_reader :status, :message

def initialize(status, message)
@status = status
@message = message
end
end
end
73 changes: 73 additions & 0 deletions ansible/files/home/deployer/webhook/lib/deployer/payload.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Copyright (C) 2010-2019 Sutou Kouhei <[email protected]>
# Copyright (C) 2015 Kenji Okimoto <[email protected]>
# Copyright (C) 2024 Takuya Kodama <[email protected]>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

module Deployer
class Payload
RELEASE_WORKFLOWS = ["Package", "CMake"].freeze

def initialize(data, metadata={})
@data = data
@metadata = metadata
end

def [](key)
@data.dig(*key.split("."))
end

def event_name
@metadata["x-github-event"]
end

def workflow_name
self["workflow_run.name"]
end

def workflow_succeeded?
self["workflow_run.conclusion"] == "success"
end

def branch
self["workflow_run.head_branch"]
end

def version
return unless workflow_tag?
branch.delete_prefix("v")
end

def released?
RELEASE_WORKFLOWS.include?(workflow_name) &&
workflow_tag? &&
workflow_succeeded?
end

def repository_owner
self["repository.owner.login"]
end

def repository_name
self["repository.name"]
end

private

def workflow_tag?
return false unless branch
branch.match?(/\Av\d+(\.\d+){1,2}\z/)
end
end
end