From 170803c11472ea83431aaf21822d334c662313d9 Mon Sep 17 00:00:00 2001 From: xmppftw Date: Tue, 23 Jun 2026 17:40:48 +0200 Subject: [PATCH 1/2] meta: example systemd service --- cusku.service | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 cusku.service diff --git a/cusku.service b/cusku.service new file mode 100644 index 0000000..0824c84 --- /dev/null +++ b/cusku.service @@ -0,0 +1,14 @@ +[Unit] +Description=Forgejo webhooks (cusku) +Wants=network-online.target +After=network-online.target nss-lookup.target prosody.service forgejo.service + +[Service] +Type=exec +User=cusku +ExecStart=/opt/cusku/cusku -c /opt/cusku/cusku.toml +WorkingDirectory=/opt/cusku +Environment=RUST_LOG=debug + +[Install] +WantedBy=multi-user.target From 3c09b40a43a2dcb60224bf0e3705a2644cc9be63 Mon Sep 17 00:00:00 2001 From: xmppftw Date: Wed, 1 Jul 2026 15:48:55 +0200 Subject: [PATCH 2/2] feat: Support assets (uploaded images) --- forgejo-hooks/src/lib.rs | 17 +- .../src/tests/issue-opened-with-image.json | 198 ++++++++++++++++++ forgejo-hooks/src/tests/mod.rs | 6 + 3 files changed, 219 insertions(+), 2 deletions(-) create mode 100644 forgejo-hooks/src/tests/issue-opened-with-image.json diff --git a/forgejo-hooks/src/lib.rs b/forgejo-hooks/src/lib.rs index 4af7628..bbceb9e 100644 --- a/forgejo-hooks/src/lib.rs +++ b/forgejo-hooks/src/lib.rs @@ -251,7 +251,7 @@ pub struct IssueAttrs { pub body: String, #[serde(rename(deserialize = "ref"))] pub ref_: String, - pub assets: Vec, + pub assets: Vec, pub labels: Option>, pub milestone: Option, pub assignee: Option, @@ -277,7 +277,7 @@ pub struct Comment { pub original_author: String, pub original_author_id: u64, pub body: String, - pub assets: Vec, + pub assets: Vec, pub created_at: DateTime, pub updated_at: DateTime, } @@ -348,3 +348,16 @@ impl Hook { }?) } } + +#[derive(Deserialize, Debug, PartialEq)] +pub struct Asset { + pub id: u32, + pub name: String, + pub size: u64, + pub download_count: u64, + pub created_at: DateTime, + pub uuid: String, + pub browser_download_url: String, + #[serde(rename = "type")] + pub asset_type: String, +} diff --git a/forgejo-hooks/src/tests/issue-opened-with-image.json b/forgejo-hooks/src/tests/issue-opened-with-image.json new file mode 100644 index 0000000..c6416c4 --- /dev/null +++ b/forgejo-hooks/src/tests/issue-opened-with-image.json @@ -0,0 +1,198 @@ +{ + "action": "opened", + "number": 14, + "issue": { + "id": 51, + "url": "https://git.example.com/api/v1/repos/myorga/todo/issues/14", + "html_url": "https://git.example.com/myorga/todo/issues/14", + "number": 14, + "user": { + "id": 2, + "login": "myuser", + "login_name": "myuser", + "source_id": 1, + "full_name": "myuser", + "email": "myuser@git.example.com", + "avatar_url": "https://secure.gravatar.com/avatar/a2b9fffa242ce41115a6cbb65785f777?d=identicon", + "html_url": "https://git.example.com/myuser", + "language": "en-US", + "is_admin": true, + "last_login": "2026-07-01T14:14:44+02:00", + "created": "2026-06-22T17:10:26+02:00", + "restricted": false, + "active": true, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "myuser" + }, + "original_author": "", + "original_author_id": 0, + "title": "Nouveau ticket", + "body": "Test \r\n\r\n![image](/attachments/5f57bc21-c2bb-4c3b-8f09-68492f885853)\r\n\r\n", + "ref": "", + "assets": [ + { + "id": 1, + "name": "image.png", + "size": 258465, + "download_count": 0, + "created_at": "2026-07-01T14:20:49+02:00", + "uuid": "5f57bc21-c2bb-4c3b-8f09-68492f885853", + "browser_download_url": "https://git.example.com/attachments/5f57bc21-c2bb-4c3b-8f09-68492f885853", + "type": "attachment" + } + ], + "labels": [], + "milestone": null, + "assignee": null, + "assignees": null, + "state": "open", + "is_locked": false, + "comments": 0, + "created_at": "2026-07-01T14:21:53+02:00", + "updated_at": "2026-07-01T14:21:53+02:00", + "closed_at": null, + "due_date": null, + "pull_request": null, + "repository": { + "id": 15, + "name": "todo", + "owner": "myorga", + "full_name": "myorga/todo" + }, + "pin_order": 0 + }, + "repository": { + "id": 15, + "owner": { + "id": 288, + "login": "myorga", + "login_name": "", + "source_id": 0, + "full_name": "", + "email": "", + "avatar_url": "https://git.example.com/avatars/7052cad6b415f4272c1986aa9a50a7c3", + "html_url": "https://git.example.com/myorga", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2026-06-22T22:44:01+02:00", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "private", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "myorga" + }, + "name": "todo", + "full_name": "myorga/todo", + "description": "", + "empty": true, + "private": false, + "fork": false, + "template": false, + "parent": null, + "mirror": false, + "size": 25, + "language": "", + "languages_url": "https://git.example.com/api/v1/repos/myorga/todo/languages", + "html_url": "https://git.example.com/myorga/todo", + "url": "https://git.example.com/api/v1/repos/myorga/todo", + "link": "", + "ssh_url": "ssh://forgejo@kl.netlib.re/myorga/todo.git", + "clone_url": "https://git.example.com/myorga/todo.git", + "original_url": "", + "website": "", + "stars_count": 0, + "forks_count": 0, + "watchers_count": 4, + "open_issues_count": 13, + "open_pr_counter": 0, + "release_counter": 0, + "default_branch": "main", + "archived": false, + "created_at": "2026-06-22T22:45:01+02:00", + "updated_at": "2026-06-22T22:45:01+02:00", + "archived_at": "1970-01-01T01:00:00+01:00", + "permissions": { + "admin": true, + "push": true, + "pull": true + }, + "has_issues": true, + "internal_tracker": { + "enable_time_tracker": true, + "allow_only_contributors_to_track_time": true, + "enable_issue_dependencies": true + }, + "has_wiki": true, + "has_wiki_contents": false, + "wiki_branch": "main", + "wiki_ssh_url": "ssh://forgejo@kl.netlib.re/myorga/todo.wiki.git", + "wiki_clone_url": "https://git.example.com/myorga/todo.wiki.git", + "globally_editable_wiki": false, + "has_pull_requests": true, + "has_projects": true, + "has_releases": true, + "has_packages": true, + "has_actions": false, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": true, + "allow_rebase": true, + "allow_rebase_explicit": true, + "allow_squash_merge": true, + "allow_fast_forward_only_merge": true, + "allow_rebase_update": true, + "default_delete_branch_after_merge": false, + "default_merge_style": "merge", + "default_allow_maintainer_edit": false, + "default_update_style": "merge", + "avatar_url": "", + "internal": true, + "mirror_interval": "", + "object_format_name": "sha1", + "mirror_updated": "0001-01-01T00:00:00Z", + "repo_transfer": null, + "topics": [] + }, + "sender": { + "id": 2, + "login": "myuser", + "login_name": "", + "source_id": 0, + "full_name": "myuser", + "email": "myuser@noreply.git.example.com", + "avatar_url": "https://secure.gravatar.com/avatar/a2b9fffa242ce41115a6cbb65785f777?d=identicon", + "html_url": "https://git.example.com/myuser", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2026-06-22T17:10:26+02:00", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "myuser" + }, + "commit_id": "" +} diff --git a/forgejo-hooks/src/tests/mod.rs b/forgejo-hooks/src/tests/mod.rs index cc089aa..0f74681 100644 --- a/forgejo-hooks/src/tests/mod.rs +++ b/forgejo-hooks/src/tests/mod.rs @@ -59,6 +59,12 @@ fn issue_opened() { let _ = parse_roundtrip::(&payload); } +#[test] +fn issue_opened_with_image() { + let payload = std::fs::read_to_string("src/tests/issue-opened-with-image.json").unwrap(); + let _ = parse_roundtrip::(&payload); +} + #[test] fn issue_with_assignee() { let payload = std::fs::read_to_string("src/tests/issue-with-assignee.json").unwrap();