wip: pull request view & md rendering
This commit is contained in:
166
build.rs
166
build.rs
@@ -9,6 +9,12 @@ struct AssetFile {
|
||||
disk_path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TimelineFixturePage {
|
||||
json: String,
|
||||
end_cursor: Option<String>,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let manifest_dir =
|
||||
PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("missing CARGO_MANIFEST_DIR"));
|
||||
@@ -129,6 +135,9 @@ fn render_github_fixtures(fixture_root: &Path) -> String {
|
||||
let repo_list = read_json_fixture(&fixture_root.join("repo.list.json"));
|
||||
|
||||
let mut issue_fixtures = BTreeMap::<(String, u32), String>::new();
|
||||
let mut pull_request_fixtures = BTreeMap::<String, String>::new();
|
||||
let mut pull_request_timeline_fixtures =
|
||||
BTreeMap::<String, BTreeMap<u32, TimelineFixturePage>>::new();
|
||||
let mut entries = fs::read_dir(fixture_root)
|
||||
.unwrap_or_else(|err| panic!("failed to read {}: {err}", fixture_root.display()))
|
||||
.map(|entry| entry.expect("failed to read github fixture entry"))
|
||||
@@ -141,11 +150,24 @@ fn render_github_fixtures(fixture_root: &Path) -> String {
|
||||
.into_string()
|
||||
.unwrap_or_else(|_| panic!("non-utf8 fixture name in {}", fixture_root.display()));
|
||||
|
||||
let Some((filter, page)) = parse_issue_fixture_name(&file_name) else {
|
||||
if let Some((filter, page)) = parse_issue_fixture_name(&file_name) {
|
||||
let value = read_fixture_value(&entry.path());
|
||||
issue_fixtures.insert((filter, page), read_issue_fixture(&value, &entry.path()));
|
||||
continue;
|
||||
};
|
||||
}
|
||||
|
||||
issue_fixtures.insert((filter, page), read_issue_fixture(&entry.path()));
|
||||
if let Some(id) = parse_pull_request_fixture_name(&file_name) {
|
||||
pull_request_fixtures.insert(id, read_json_fixture(&entry.path()));
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some((id, page)) = parse_pull_request_timeline_fixture_name(&file_name) {
|
||||
let value = read_fixture_value(&entry.path());
|
||||
pull_request_timeline_fixtures
|
||||
.entry(id)
|
||||
.or_default()
|
||||
.insert(page, read_timeline_fixture(&value, &entry.path()));
|
||||
}
|
||||
}
|
||||
|
||||
let mut output = String::new();
|
||||
@@ -177,23 +199,68 @@ fn render_github_fixtures(fixture_root: &Path) -> String {
|
||||
output.push_str(" }\n");
|
||||
output.push_str("}\n");
|
||||
|
||||
output.push_str("\n");
|
||||
output.push_str("pub fn issues_pull_request(id: &str) -> Option<&'static str> {\n");
|
||||
output.push_str(" match id {\n");
|
||||
for (id, json) in pull_request_fixtures {
|
||||
output.push_str(" ");
|
||||
output.push_str(&string_literal(&id));
|
||||
output.push_str(" => Some(");
|
||||
output.push_str(&string_literal(&json));
|
||||
output.push_str("),\n");
|
||||
}
|
||||
output.push_str(" _ => None,\n");
|
||||
output.push_str(" }\n");
|
||||
output.push_str("}\n");
|
||||
|
||||
output.push_str("\n");
|
||||
output.push_str("pub fn issues_pull_request_timeline(id: &str, after: Option<&str>) -> Option<&'static str> {\n");
|
||||
output.push_str(" match (id, after) {\n");
|
||||
for (id, pages) in pull_request_timeline_fixtures {
|
||||
let mut previous_page = 0;
|
||||
let mut previous_end_cursor = None;
|
||||
|
||||
for (page, fixture) in pages {
|
||||
if page != previous_page + 1 {
|
||||
panic!("missing pull request timeline fixture page {page} for {id}");
|
||||
}
|
||||
|
||||
output.push_str(" (");
|
||||
output.push_str(&string_literal(&id));
|
||||
output.push_str(", ");
|
||||
match previous_end_cursor.as_deref() {
|
||||
Some(after) => output.push_str(&format!("Some({})", string_literal(after))),
|
||||
None => output.push_str("None"),
|
||||
}
|
||||
output.push_str(") => Some(");
|
||||
output.push_str(&string_literal(&fixture.json));
|
||||
output.push_str("),\n");
|
||||
|
||||
previous_page = page;
|
||||
previous_end_cursor = fixture.end_cursor.clone();
|
||||
}
|
||||
}
|
||||
output.push_str(" _ => None,\n");
|
||||
output.push_str(" }\n");
|
||||
output.push_str("}\n");
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
fn read_json_fixture(path: &Path) -> String {
|
||||
fn read_fixture_value(path: &Path) -> serde_json::Value {
|
||||
let raw = fs::read_to_string(path)
|
||||
.unwrap_or_else(|err| panic!("failed to read fixture {}: {err}", path.display()));
|
||||
let value: serde_json::Value = serde_json::from_str(&raw)
|
||||
.unwrap_or_else(|err| panic!("invalid json fixture {}: {err}", path.display()));
|
||||
serde_json::from_str(&raw)
|
||||
.unwrap_or_else(|err| panic!("invalid json fixture {}: {err}", path.display()))
|
||||
}
|
||||
|
||||
fn read_json_fixture(path: &Path) -> String {
|
||||
let value = read_fixture_value(path);
|
||||
serde_json::to_string(&value)
|
||||
.unwrap_or_else(|err| panic!("failed to serialize fixture {}: {err}", path.display()))
|
||||
}
|
||||
|
||||
fn read_issue_fixture(path: &Path) -> String {
|
||||
let raw = fs::read_to_string(path)
|
||||
.unwrap_or_else(|err| panic!("failed to read fixture {}: {err}", path.display()));
|
||||
let value: serde_json::Value = serde_json::from_str(&raw)
|
||||
.unwrap_or_else(|err| panic!("invalid json fixture {}: {err}", path.display()));
|
||||
fn read_issue_fixture(value: &serde_json::Value, path: &Path) -> String {
|
||||
let issues = value
|
||||
.as_array()
|
||||
.unwrap_or_else(|| panic!("issue fixture {} must be a json array", path.display()));
|
||||
@@ -215,8 +282,49 @@ fn read_issue_fixture(path: &Path) -> String {
|
||||
})
|
||||
}
|
||||
|
||||
fn read_timeline_fixture(value: &serde_json::Value, path: &Path) -> TimelineFixturePage {
|
||||
let page_info = value
|
||||
.get("node")
|
||||
.and_then(|node| node.get("timelineItems"))
|
||||
.and_then(|timeline| timeline.get("pageInfo"))
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"timeline fixture {} must include node.timelineItems.pageInfo",
|
||||
path.display()
|
||||
)
|
||||
});
|
||||
|
||||
if !matches!(
|
||||
value
|
||||
.get("node")
|
||||
.and_then(|node| node.get("timelineItems"))
|
||||
.and_then(|timeline| timeline.get("nodes")),
|
||||
Some(serde_json::Value::Array(_))
|
||||
) {
|
||||
panic!(
|
||||
"timeline fixture {} must include node.timelineItems.nodes",
|
||||
path.display()
|
||||
);
|
||||
}
|
||||
|
||||
let end_cursor = page_info
|
||||
.get("endCursor")
|
||||
.and_then(serde_json::Value::as_str)
|
||||
.map(str::to_owned);
|
||||
|
||||
let json = serde_json::to_string(value).unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"failed to serialize mapped timeline fixture {}: {err}",
|
||||
path.display()
|
||||
)
|
||||
});
|
||||
|
||||
TimelineFixturePage { json, end_cursor }
|
||||
}
|
||||
|
||||
fn map_issue_fixture(issue: &serde_json::Value) -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"id": issue_fixture_graphql_id(issue),
|
||||
"title": required_string(issue, &["title"]),
|
||||
"state": issue_fixture_state(issue),
|
||||
"is_draft": issue.get("draft").and_then(serde_json::Value::as_bool).unwrap_or(false),
|
||||
@@ -231,27 +339,22 @@ fn issue_fixture_state(issue: &serde_json::Value) -> &'static str {
|
||||
.and_then(serde_json::Value::as_str)
|
||||
.is_some()
|
||||
{
|
||||
return "Merged";
|
||||
return "MERGED";
|
||||
}
|
||||
|
||||
match required_string(issue, &["state"]) {
|
||||
"open" => "Open",
|
||||
"closed" => "Closed",
|
||||
_ => "Unknown",
|
||||
"open" => "OPEN",
|
||||
"closed" => "CLOSED",
|
||||
state => panic!("unsupported pull request state in fixture: {state}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn issue_fixture_graphql_id<'a>(issue: &'a serde_json::Value) -> &'a str {
|
||||
required_string(issue, &["node_id"])
|
||||
}
|
||||
|
||||
fn issue_fixture_cursor(issue: &serde_json::Value) -> Option<String> {
|
||||
issue
|
||||
.get("node_id")
|
||||
.and_then(serde_json::Value::as_str)
|
||||
.map(str::to_owned)
|
||||
.or_else(|| {
|
||||
issue
|
||||
.get("id")
|
||||
.and_then(serde_json::Value::as_u64)
|
||||
.map(|id| id.to_string())
|
||||
})
|
||||
Some(issue_fixture_graphql_id(issue).to_owned())
|
||||
}
|
||||
|
||||
fn required_string<'a>(value: &'a serde_json::Value, path: &[&str]) -> &'a str {
|
||||
@@ -276,6 +379,19 @@ fn parse_issue_fixture_name(file_name: &str) -> Option<(String, u32)> {
|
||||
Some((filter.to_owned(), page))
|
||||
}
|
||||
|
||||
fn parse_pull_request_fixture_name(file_name: &str) -> Option<String> {
|
||||
let name = file_name.strip_suffix(".json")?;
|
||||
name.strip_prefix("issues.pull_request.").map(str::to_owned)
|
||||
}
|
||||
|
||||
fn parse_pull_request_timeline_fixture_name(file_name: &str) -> Option<(String, u32)> {
|
||||
let name = file_name.strip_suffix(".json")?;
|
||||
let rest = name.strip_prefix("issues.pull_request_timeline.")?;
|
||||
let (id, page) = rest.rsplit_once(".page")?;
|
||||
let page = page.parse::<u32>().ok()?;
|
||||
Some((id.to_owned(), page))
|
||||
}
|
||||
|
||||
fn string_literal(value: &str) -> String {
|
||||
format!("{value:?}")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user