]> git.ipfire.org Git - thirdparty/google/fonts.git/commitdiff
Check source state of fontc inputs 9669/head
authorSimon Cozens <simon@simon-cozens.org>
Mon, 14 Jul 2025 13:37:13 +0000 (14:37 +0100)
committerSimon Cozens <simon@simon-cozens.org>
Mon, 14 Jul 2025 13:37:13 +0000 (14:37 +0100)
.ci/dashboard/src/data/fontc_review.json.js [new file with mode: 0644]
.ci/dashboard/src/data/metadata.json.py
.ci/dashboard/src/source_check.md [new file with mode: 0644]

diff --git a/.ci/dashboard/src/data/fontc_review.json.js b/.ci/dashboard/src/data/fontc_review.json.js
new file mode 100644 (file)
index 0000000..e68c308
--- /dev/null
@@ -0,0 +1,14 @@
+const sheet = await fetch(
+  "https://docs.google.com/spreadsheets/d/1ao3k56FwQy6W0Ll5QbU_wpuKEvNPYcn8YyEU9_L8O4Q/gviz/tq?tqx=out:json&tq"
+);
+const text = await sheet.text();
+const json = JSON.parse(text.substr(47).slice(0, -2));
+var families = {};
+for (const row of json.table.rows) {
+  const family = row.c[0]?.v.split("/")?.pop();
+  const reviewed = row.c[3]?.v;
+  if (family && reviewed) {
+    families[family] = reviewed;
+  }
+}
+console.log(JSON.stringify(families));
index c73502b548744d48d3108cdc9ce6ffb22ca39331..ad6c4fb33902de7922a42324550de1e0bb866455 100644 (file)
@@ -10,7 +10,7 @@ from gftools.push.items import parse_html
 repo_path = os.environ["GF_REPO_PATH"]
 metadata = {}
 
-for directory in glob(os.path.join(repo_path, "ofl", "*")):
+for directory in list(glob(os.path.join(repo_path, "ofl", "*"))) + list(glob(os.path.join(repo_path, "apache", "*"))):
     if not os.path.isdir(directory):
         continue
 
diff --git a/.ci/dashboard/src/source_check.md b/.ci/dashboard/src/source_check.md
new file mode 100644 (file)
index 0000000..d3d855f
--- /dev/null
@@ -0,0 +1,170 @@
+---
+title: Fontc crater sources check
+toc: false
+---
+
+```js
+const fontc = await FileAttachment("./data/fontc.json").json();
+const metadata = await FileAttachment("./data/metadata.json").json();
+const servers = await FileAttachment("./data/servers.json").json();
+const github = await FileAttachment("./data/github.json").json();
+const reviewlist = await FileAttachment("./data/fontc_review.json").json();
+
+const family_to_directory = Object.fromEntries(
+  Object.entries(metadata).map(([k, v]) => [v.name, k])
+);
+const directory_to_family = Object.fromEntries(
+  Object.entries(metadata).map(([k, v]) => [k, v.name])
+);
+
+function fontcKeyToGithubAndSha(key, state) {
+  let match = key.match(
+    /^([^\/]+)\/([^\/]+)\/(\S+)\?([a-f0-9]+) \((\S+)\) (\S+)/
+  );
+  if (match) {
+    let [_, owner, repo, path, sha, config, mode] = match;
+    return { repo: `${owner}/${repo}`, sha, state };
+  }
+}
+
+let fontcResults = [];
+for (let successKey of Object.keys(fontc.lastRun.success)) {
+  let githubAndSha = fontcKeyToGithubAndSha(successKey, "success");
+  if (githubAndSha) {
+    fontcResults.push(githubAndSha);
+  }
+}
+for (let failureKey of Object.keys(fontc.lastRun.failure)) {
+  let githubAndSha = fontcKeyToGithubAndSha(failureKey, "failure");
+  if (githubAndSha) {
+    fontcResults.push(githubAndSha);
+  }
+}
+
+const summary = Object.keys(metadata).map((directory) => {
+  const md = metadata[directory];
+  const family = md.name;
+  let source_state = "Good";
+  if (!md.source) {
+    source_state = "No source information";
+  } else if (!md.source.repositoryUrl) {
+    source_state = "Missing repository URL";
+  } else if (!md.source.commit) {
+    source_state = "Missing SHA";
+  } else if (!md.source.configYaml) {
+    source_state = "Missing config.yaml";
+  } else if (!md.source.commit.match(/^[0-9a-f]{40}$/)) {
+    source_state = "Invalid commit hash";
+  }
+  let github =
+    md.source?.repositoryUrl &&
+    md.source.repositoryUrl.match(/github.com\/([^/]+\/[^/]+)/)?.[1];
+  let fontcResult = fontcResults.find((r) => r.repo === github);
+  let fontcState = "unknown";
+  if (fontcResult) {
+    fontcState = fontcResult.state;
+  }
+  if (source_state != "Good" && fontcState == "unknown") {
+    fontcState = "insufficient source data: " + source_state;
+  }
+  return {
+    directory,
+    family,
+    slug:
+      source_state == "Good"
+        ? github + "/" + md.source?.configYaml + "@" + md.source?.commit
+        : "",
+    github,
+    sha: md.source?.commit,
+    source_state,
+    fontc_state: fontcState,
+    reviewed: reviewlist[directory],
+  };
+});
+
+let successes = summary.filter((s) => s.fontc_state == "success");
+let failures = summary.filter((s) => s.fontc_state == "failure");
+let insufficient = summary.filter((s) =>
+  s.fontc_state.startsWith("insufficient source data")
+);
+let unknown = summary.filter((s) => s.fontc_state == "unknown");
+let reviewed = summary.filter((s) => s.reviewed == "yes");
+```
+
+<div class="hero">
+  <h2> Total families: <span class="huge ">${ summary.length }</h2>
+    <h2> Ran: <span class="pass">${ successes.length }</span> + <span class="fail">${ failures.length}</span> = <span class="huge">${ successes.length + failures.length }</span></h2>
+    <h2> Insufficient source data: <span class="">${ insufficient.length }<br/>
+    Unaccounted: <span class="">${ unknown.length }</h2>
+    <h2>Reviewed: <span class="">${ reviewed.length } (${ Math.floor(reviewed.length / summary.length * 100) }%)</span></h2>
+</div>
+
+```js
+const domain = ["success", "failure", "insufficient source data", "unknown"];
+display(
+  Plot.plot({
+    y: { percent: true },
+    color: { legend: true },
+    marks: [
+      Plot.waffleY(
+        summary,
+        Plot.groupX(
+          { y: "count" },
+          {
+            x: 0,
+            fill: (d) =>
+              d.fontc_state.replace(
+                /insufficient source data: (.+)/,
+                "insufficient source data"
+              ),
+            offset: "normalize",
+            order: domain,
+          }
+        )
+      ),
+    ],
+    width: 500,
+    height: 400,
+    color: {
+      domain,
+      range: ["#1a821aff", "#8d2929ff", "#4ee5f9ff", "#aaaaaa"],
+      legend: true,
+    },
+  })
+);
+```
+
+## Details
+
+```js
+display(
+  Inputs.table(summary, {
+    rows: 200,
+    columns: ["directory", "family", "slug", "fontc_state", "reviewed"],
+    sort: "fontc_state",
+    reverse: true,
+    header: {
+      directory: "Directory",
+      family: "Family name",
+      slug: "Source",
+      fontc_state: "Fontc state",
+      reviewed: "Reviewed",
+    },
+    format: {
+      fontc_state: (d) => {
+        if (d == "success") {
+          return html`<span class="pass">${d}</span>`;
+        } else if (d == "failure") {
+          return html`<span class="fail">${d}</span>`;
+        } else if (d.startsWith("insufficient source data")) {
+          return html`<span class="insufficient"
+            >${d.replace("insufficient source data:", "")}</span
+          >`;
+        } else {
+          return html`<b>${d}</b>`;
+        }
+      },
+    },
+  })
+);
+```