///|
fn push_event_json_error(message : String) -> PushEventJsonParseResult {
{ event: None, errors: [message] }
}
///|
fn push_event_json_field(obj : Json, key : String) -> Json? {
if obj is Object(fields) {
fields.get(key)
} else {
None
}
}
///|
fn push_event_json_string(obj : Json, key : String) -> String? {
match push_event_json_field(obj, key) {
Some(String(value)) => Some(value)
_ => None
}
}
///|
fn push_event_json_object(obj : Json, key : String) -> Json? {
match push_event_json_field(obj, key) {
Some(value) => if value is Object(_) { Some(value) } else { None }
_ => None
}
}
///|
fn push_event_json_string_array(obj : Json, key : String) -> Array[String] {
let values : Array[String] = []
match push_event_json_field(obj, key) {
Some(Array(items)) =>
for item in items {
if item is String(value) {
values.push(value)
}
}
_ => ()
}
values
}
///|
fn push_event_strip_ref(ref_name : String) -> String {
if ref_name.has_prefix("refs/heads/") {
return String::unsafe_substring(ref_name, start=11, end=ref_name.length())
}
if ref_name.has_prefix("refs/tags/") {
return String::unsafe_substring(ref_name, start=10, end=ref_name.length())
}
ref_name
}
///|
fn push_event_append_unique(
paths : Array[String],
extra : Array[String],
) -> Unit {
for path in extra {
if path.length() == 0 {
continue
}
if !paths.contains(path) {
paths.push(path)
}
}
}
///|
fn push_event_collect_changed_paths(payload : Json) -> Array[String] {
let paths : Array[String] = []
match push_event_json_field(payload, "commits") {
Some(Array(commits)) =>
for commit in commits {
push_event_append_unique(
paths,
push_event_json_string_array(commit, "added"),
)
push_event_append_unique(
paths,
push_event_json_string_array(commit, "modified"),
)
push_event_append_unique(
paths,
push_event_json_string_array(commit, "removed"),
)
}
_ => ()
}
match push_event_json_object(payload, "head_commit") {
Some(head_commit) if paths.length() == 0 => {
push_event_append_unique(
paths,
push_event_json_string_array(head_commit, "added"),
)
push_event_append_unique(
paths,
push_event_json_string_array(head_commit, "modified"),
)
push_event_append_unique(
paths,
push_event_json_string_array(head_commit, "removed"),
)
}
_ => ()
}
paths.sort_by(String::lexical_compare)
paths
}
///|
pub fn parse_github_push_event_json(text : String) -> PushEventJsonParseResult {
let payload = @json.parse(text) catch {
err =>
return push_event_json_error(
"failed to parse push event JSON: " + err.to_string(),
)
}
guard payload is Object(_) else {
return push_event_json_error("push event payload must be a JSON object")
}
let errors : Array[String] = []
let ref_value = push_event_json_string(payload, "ref").unwrap_or("")
let before_sha = push_event_json_string(payload, "before").unwrap_or("")
let after_sha = push_event_json_string(payload, "after").unwrap_or("")
if ref_value.length() == 0 {
errors.push("push event JSON is missing string field `ref`")
}
if before_sha.length() == 0 {
errors.push("push event JSON is missing string field `before`")
}
if after_sha.length() == 0 {
errors.push("push event JSON is missing string field `after`")
}
if errors.length() > 0 {
return { event: None, errors }
}
let repository = match push_event_json_object(payload, "repository") {
Some(repo) => push_event_json_string(repo, "full_name").unwrap_or("")
None => ""
}
let actor = match push_event_json_object(payload, "sender") {
Some(sender) => push_event_json_string(sender, "login").unwrap_or("")
None => ""
}
let changed_paths = push_event_collect_changed_paths(payload)
{
event: Some(
new_push_event(
push_event_strip_ref(ref_value),
changed_paths,
before_sha~,
after_sha~,
repository~,
actor~,
),
),
errors: [],
}
}