module sources import x.json2 as json pub fn transform_gitea(raw string, source GiteaSource) ?Event { doc := json.decode[json.Any](raw, json.DecoderOptions{}) or { return none } obj := doc.as_map() event_type := detect_gitea_event(obj) priority := source.priority_map[event_type] or { 0 } repo := get_string(obj, 'repository.full_name') mut user := get_string(obj, 'pusher.username') action := get_string(obj, 'action') mut title := get_string(obj, 'commits.0.message') mut sha := get_string(obj, 'commits.0.id') if event_type == 'pull_request' { pr := obj['pull_request'] or { json.Any(map[string]json.Any{}) }.as_map() title = get_string(pr, 'title') sha = get_string(pr, 'merge_commit_sha') if user == '' { user = get_string(pr, 'user.login') } } else if event_type == 'issue' { issue := obj['issue'] or { json.Any(map[string]json.Any{}) }.as_map() title = get_string(issue, 'title') sha = '' if user == '' { user = get_string(issue, 'user.login') } } template := source.template mut message := '' if template != '' { vars := { 'repo': repo 'user': user 'action': action 'title': title 'sha': sha } message = render_source_template(template, vars) } else { mut parts := []string{} if repo != '' { parts << '[${repo}]' } if user != '' { parts << '${user}' } if action != '' { parts << '${action}:' } if title != '' { parts << '"${title}"' } if sha != '' { short := if sha.len >= 7 { sha[..7] } else { sha } parts << '(${short})' } emoji := match event_type { 'pull_request' { '🔀' } 'issue' { '📝' } 'release' { '🚀' } else { '🔨' } } message = '${emoji} ' + parts.join(' ') } return Event{ source: 'gitea' name: source.name topic: source.topic priority: priority tags: source.tags.clone() message: message raw: raw } } fn detect_gitea_event(obj map[string]json.Any) string { if 'commits' in obj { return 'push' } if 'pull_request' in obj { return 'pull_request' } if 'issue' in obj { return 'issue' } if 'release' in obj { return 'release' } return 'unknown' } fn get_string(obj map[string]json.Any, path string) string { parts := path.split('.') mut current := obj.clone() for i, part in parts { if i == parts.len - 1 { val := current[part] or { return '' } return val.str() } next := current[part] or { return '' } current = next.as_map().clone() } return '' }