Skip to content

Commit

Permalink
release: trigger release processes when release workflow succeeded
Browse files Browse the repository at this point in the history
GitHub: GH-43

In this PR, we set up how release flow is triggered from webhook
requests.
  • Loading branch information
otegami committed Dec 19, 2024
1 parent 2a87072 commit e4f8727
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 2 deletions.
65 changes: 63 additions & 2 deletions ansible/files/home/deployer/webhook/lib/deployer/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,18 @@
# 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"
require_relative "source-archive"

module Deployer
class App
def call(env)
request = Rack::Request.new(env)
response = Response.new
process(request, response)
response.finish
process(request, response) || response.finish
end

private
Expand All @@ -38,6 +40,10 @@ def process(request, response)
response.set(:unauthorized, "Authorization failed")
return
end

payload = parse_payload(request, response)
return if payload.nil?
process_payload(request, response, payload)
end

def valid_signature?(request)
Expand All @@ -47,5 +53,60 @@ def valid_signature?(request)
signature = "sha256=#{hmac_sha256}"
Rack::Utils.secure_compare(signature, request.env["HTTP_X_HUB_SIGNATURE_256"])
end

def parse_payload(request, response)
unless request.media_type == "application/json"
response.set(:bad_request, "invalid payload format")
return
end

payload = request.body.read
if payload.nil?
response.set(:bad_request, "payload is missing")
return
end

begin
JSON.parse(payload)
rescue JSON::ParserError
response.set(:bad_request, "invalid JSON format: <#{$!.message}>")
nil
end
end

def process_payload(request, response, raw_payload)
metadata = {
"x-github-event" => request.env["HTTP_X_GITHUB_EVENT"]
}

payload = Payload.new(raw_payload, metadata)

case payload.event_name
when "ping"
# Do nothing because this is a kind of healthcheck.
nil
when "workflow_run"
return unless payload.released?
process_release(request, response, payload)
else
response.set(:bad_request,
"Unsupported event: <#{payload.event_name}>")
nil
end
end

def process_release(request, response, payload)
response.finish do
Thread.new do
gpg_key_id = "TODO: handle a GPG key"
archive = Deployer::SourceArchive.new(payload.repository_owner,
payload.repository_name,
payload.repository_name,
payload.version,
payload.branch)
archive.process(gpg_key_id)
end
end
end
end
end
80 changes: 80 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,80 @@
# 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"].map(&:freeze).freeze

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

def [](key)
key.split(".").inject(@data) do |current_data, current_key|
if current_data
current_data[current_key]
else
nil
end
end
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 if workflow_tag?
branch.delete_prefix("v")
end

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

def repository_owner
owner = self["repository.owner"] || {}
owner["login"]
end

def repository_name
self["repository.name"]
end

private

def workflow_tag?
return if branch
branch.match?(/^v\d+(\.\d+){2}$/)
end
end
end

0 comments on commit e4f8727

Please sign in to comment.