Skip to content

Commit 1dba744

Browse files
committed
monitor: add support for Forgejo Actions
1 parent 6c26b88 commit 1dba744

File tree

4 files changed

+68
-24
lines changed

4 files changed

+68
-24
lines changed

.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
GITHUB_TOKEN=gho_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1+
GITHUB_OR_FORGEJO_TOKEN=gho_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
22
LIBVIRT_DEFAULT_URI=qemu:///system
33

44
# Accept requests with this API token only.

monitor.toml.example

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,14 @@ listen_on = ["::1", "192.168.100.1"]
44
# Prepend this to any internal URL in our own responses. Must end with trailing slash.
55
external_base_url = "http://[::1]:8000/"
66

7-
# GitHub Actions runner scope (`/repos/<owner>/<repo>` or `/orgs/<owner>`).
8-
github_api_scope = "/repos/delan/servo"
7+
# GitHub Actions runner scope, as a full URL including the domain of the forge. For example:
8+
# - `https://api.github.com/repos/<owner>/<repo>`
9+
# - `https://api.github.com/orgs/<org>`
10+
# - `https://codeberg.org/api/v1/repos/<owner>/<repo>`
11+
# - `https://codeberg.org/api/v1/orgs/<org>`
12+
# - `https://codeberg.org/api/v1/user`
13+
github_api_scope_url = "https://api.github.com/repos/delan/servo"
14+
github_api_is_forgejo = false
915

1016
# For tokenless runner select, qualified repos must start with this prefix.
1117
allowed_qualified_repo_prefix = "delan/"

monitor/settings/src/lib.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub static TOML: LazyLock<Toml> = LazyLock::new(|| {
5353

5454
#[derive(Default)]
5555
pub struct Dotenv {
56-
// GITHUB_TOKEN not used
56+
pub github_or_forgejo_token: String,
5757
// LIBVIRT_DEFAULT_URI not used
5858
pub monitor_api_token_raw_value: String,
5959
pub monitor_api_token_authorization_value: String,
@@ -64,7 +64,8 @@ pub struct Dotenv {
6464
pub struct Toml {
6565
pub listen_on: Vec<String>,
6666
pub external_base_url: String,
67-
pub github_api_scope: String,
67+
pub github_api_scope_url: String,
68+
pub github_api_is_forgejo: bool,
6869
pub allowed_qualified_repo_prefix: String,
6970
pub github_api_suffix: String,
7071
monitor_poll_interval: u64,
@@ -94,6 +95,7 @@ impl Dotenv {
9495
pub fn load() -> Self {
9596
let monitor_api_token = env_string("SERVO_CI_MONITOR_API_TOKEN");
9697
let result = Self {
98+
github_or_forgejo_token: env_string("GITHUB_OR_FORGEJO_TOKEN"),
9799
monitor_api_token_raw_value: monitor_api_token.clone(),
98100
monitor_api_token_authorization_value: Self::monitor_api_token_authorization_value(
99101
&monitor_api_token,
@@ -106,6 +108,7 @@ impl Dotenv {
106108

107109
#[cfg(any(test, feature = "test"))]
108110
fn load_for_tests() -> Self {
111+
let mut github_or_forgejo_token = None;
109112
let mut monitor_data_path = None;
110113

111114
// TODO: find a way to do this without a temporary file
@@ -122,6 +125,7 @@ impl Dotenv {
122125
for entry in dotenv::from_path_iter(env_path).expect("Failed to load temporary env file") {
123126
let (key, value) = entry.expect("Failed to load entry");
124127
match &*key {
128+
"GITHUB_OR_FORGEJO_TOKEN" => github_or_forgejo_token = Some(value),
125129
"SERVO_CI_MONITOR_API_TOKEN" => { /* do nothing (see below) */ }
126130
"SERVO_CI_MONITOR_DATA_PATH" => monitor_data_path = Some(value),
127131
_ => { /* do nothing */ }
@@ -132,6 +136,8 @@ impl Dotenv {
132136
let monitor_api_token = "ChangedMe";
133137

134138
let result = Self {
139+
github_or_forgejo_token: github_or_forgejo_token
140+
.expect("Bad contents of monitor.toml.example"),
135141
monitor_api_token_raw_value: monitor_api_token.to_owned(),
136142
monitor_api_token_authorization_value: Self::monitor_api_token_authorization_value(
137143
monitor_api_token,

monitor/src/github.rs

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use chrono::{DateTime, FixedOffset};
77
use cmd_lib::{run_cmd, run_fun};
88
use jane_eyre::eyre::{self, Context};
99
use serde::{Deserialize, Serialize};
10-
use settings::TOML;
10+
use settings::{DOTENV, TOML};
1111
use tracing::trace;
1212

1313
#[derive(Clone, Debug, Deserialize, Serialize)]
@@ -107,10 +107,19 @@ impl<Response: Clone + Debug> Cache<Response> {
107107
}
108108

109109
fn list_registered_runners() -> eyre::Result<Vec<ApiRunner>> {
110-
let github_api_scope = &TOML.github_api_scope;
111-
let result = run_fun!(gh api -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28"
112-
"$github_api_scope/actions/runners" --paginate -q ".runners[]"
113-
| jq -s .)?;
110+
let github_or_forgejo_token = &DOTENV.github_or_forgejo_token;
111+
let github_api_scope_url = &TOML.github_api_scope_url;
112+
let result = if TOML.github_api_is_forgejo {
113+
// FIXME: this leaks the token in logs when the command fails
114+
run_fun!(curl -fsSH "Authorization: token $github_or_forgejo_token"
115+
"$github_api_scope_url/actions/runners" // TODO: pagination?
116+
| jq -er ".runners")?
117+
} else {
118+
run_fun!(GITHUB_TOKEN=$github_or_forgejo_token gh api
119+
-H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28"
120+
"$github_api_scope_url/actions/runners" --paginate -q ".runners[]"
121+
| jq -s .)?
122+
};
114123

115124
Ok(serde_json::from_str(&result).wrap_err("Failed to parse JSON")?)
116125
}
@@ -127,20 +136,37 @@ pub fn list_registered_runners_for_host() -> eyre::Result<Vec<ApiRunner>> {
127136
}
128137

129138
pub fn register_runner(runner_name: &str, label: &str, work_folder: &str) -> eyre::Result<String> {
139+
let github_or_forgejo_token = &DOTENV.github_or_forgejo_token;
140+
let github_api_scope_url = &TOML.github_api_scope_url;
130141
let github_api_suffix = &TOML.github_api_suffix;
131-
let github_api_scope = &TOML.github_api_scope;
132-
let result = run_fun!(gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28"
133-
"$github_api_scope/actions/runners/generate-jitconfig"
134-
-f "name=$runner_name@$github_api_suffix" -F "runner_group_id=1" -f "work_folder=$work_folder"
135-
-f "labels[]=self-hosted" -f "labels[]=X64" -f "labels[]=$label")?;
142+
let result = if TOML.github_api_is_forgejo {
143+
// FIXME: this leaks the token in logs when the command fails
144+
// TODO: this doesn’t actually register a runner, it just gets a registration token
145+
run_fun!(curl -fsSH "Authorization: token $github_or_forgejo_token"
146+
-X POST "$github_api_scope_url/actions/runners/registration-token/TODO")?
147+
} else {
148+
run_fun!(GITHUB_TOKEN=$github_or_forgejo_token gh api
149+
-H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28"
150+
--method POST "$github_api_scope_url/actions/runners/generate-jitconfig"
151+
-f "name=$runner_name@$github_api_suffix" -F "runner_group_id=1" -f "work_folder=$work_folder"
152+
-f "labels[]=self-hosted" -f "labels[]=X64" -f "labels[]=$label")?
153+
};
136154

137155
Ok(result)
138156
}
139157

140158
pub fn unregister_runner(id: usize) -> eyre::Result<()> {
141-
let github_api_scope = &TOML.github_api_scope;
142-
run_cmd!(gh api --method DELETE -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28"
143-
"$github_api_scope/actions/runners/$id")?;
159+
let github_or_forgejo_token = &DOTENV.github_or_forgejo_token;
160+
let github_api_scope_url = &TOML.github_api_scope_url;
161+
if TOML.github_api_is_forgejo {
162+
// FIXME: this leaks the token in logs when the command fails
163+
run_cmd!(curl -fsSH "Authorization: token $github_or_forgejo_token"
164+
-X DELETE "$github_api_scope_url/actions/runners/$id")?;
165+
} else {
166+
run_cmd!(GITHUB_TOKEN=$github_or_forgejo_token gh api
167+
-H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28"
168+
--method DELETE "$github_api_scope_url/actions/runners/$id")?;
169+
}
144170

145171
Ok(())
146172
}
@@ -151,13 +177,19 @@ pub fn reserve_runner(
151177
reserved_since: SystemTime,
152178
reserved_by: &str,
153179
) -> eyre::Result<()> {
154-
let github_api_scope = &TOML.github_api_scope;
180+
let github_or_forgejo_token = &DOTENV.github_or_forgejo_token;
181+
let github_api_scope_url = &TOML.github_api_scope_url;
155182
let reserved_since = reserved_since.duration_since(UNIX_EPOCH)?.as_secs();
156-
run_cmd!(gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28"
157-
"$github_api_scope/actions/runners/$id/labels"
158-
-f "labels[]=reserved-for:$unique_id"
159-
-f "labels[]=reserved-since:$reserved_since"
160-
-f "labels[]=reserved-by:$reserved_by")?;
183+
if TOML.github_api_is_forgejo {
184+
todo!()
185+
} else {
186+
run_cmd!(GITHUB_TOKEN=$github_or_forgejo_token gh api
187+
-H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28"
188+
--method POST "$github_api_scope_url/actions/runners/$id/labels"
189+
-f "labels[]=reserved-for:$unique_id"
190+
-f "labels[]=reserved-since:$reserved_since"
191+
-f "labels[]=reserved-by:$reserved_by")?;
192+
}
161193

162194
Ok(())
163195
}

0 commit comments

Comments
 (0)