Skip to content

Commit d5f935f

Browse files
committed
ci: reduce workflow failures on forks (denoland#3176)
Publishing packages workflow and deploying to Deno Deploy step runs even for forks. This is annoying, since it creates some spam every push for any open PR's. This PR tries to address this, by skipping certain steps or workflows unless the current GitHub org is `denoland`, which should be pretty safe long term. ## Failed workflow spam <img width="1396" height="635" alt="image" src="https://github.com/user-attachments/assets/d939d1f5-e736-42a4-9355-f946b3d6ddf2" /> <img width="1577" height="905" alt="image" src="https://github.com/user-attachments/assets/fbf7ffe3-2759-430a-a33e-c8de0d7e113c" />
1 parent b120245 commit d5f935f

File tree

3 files changed

+114
-0
lines changed

3 files changed

+114
-0
lines changed

.github/workflows/deploy.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ jobs:
2929

3030
- name: Upload to Deno Deploy
3131
uses: denoland/deployctl@v1
32+
# Skip publishing for forks
33+
if: github.repository_owner == 'denoland'
3234
with:
3335
project: "fresh"
3436
entrypoint: "./www/_fresh/server.js"

.github/workflows/publish.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ jobs:
1212
contents: read
1313
id-token: write
1414

15+
# Skip publishing for forks
16+
if: github.repository_owner == 'denoland'
17+
1518
steps:
1619
- uses: actions/checkout@v4
1720

tests/doc_examples_test.tsx

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import twDenoJson from "../plugin-tailwindcss/deno.json" with { type: "json" };
2+
import * as Marked from "marked";
3+
import { ensureDir, walk } from "@std/fs";
4+
import { dirname, join, relative } from "@std/path";
5+
// import { expect } from "@std/expect/expect";
6+
import { withTmpDir } from "../src/test_utils.ts";
7+
import { FRESH_VERSION, PREACT_VERSION } from "../update/src/update.ts";
8+
9+
Deno.test("Docs Code example checks", async () => {
10+
await using tmp = await withTmpDir();
11+
12+
for await (const { path, code } of docsMarkdownFiles()) {
13+
const codePath = join(tmp.dir, path);
14+
await ensureDir(dirname(codePath));
15+
await Deno.writeTextFile(codePath, code);
16+
}
17+
18+
const denoJson = {
19+
lock: false,
20+
imports: {
21+
fresh: `jsr:@fresh/core@${FRESH_VERSION}`,
22+
"@fresh/plugin-tailwind-v3":
23+
`jsr:@fresh/plugin-tailwind@^${twDenoJson.version}`,
24+
"@fresh/plugin-tailwind":
25+
`jsr:@fresh/plugin-tailwind@^${twDenoJson.version}`,
26+
preact: `npm:preact@^${PREACT_VERSION}`,
27+
"@deno/gfm": "jsr:@deno/gfm@^0.11.0",
28+
"@std/expect": "jsr:@std/expect@^1.0.16",
29+
},
30+
compilerOptions: {
31+
lib: ["dom", "dom.asynciterable", "deno.ns", "deno.unstable"],
32+
jsx: "precompile",
33+
jsxImportSource: "preact",
34+
jsxPrecompileSkipElements: ["a", "img", "source", "body", "html", "head"],
35+
},
36+
};
37+
await Deno.writeTextFile(
38+
join(tmp.dir, "deno.json"),
39+
JSON.stringify(denoJson, undefined, 2),
40+
);
41+
42+
// Download and cache all dependencies (reduces `stdout` noise)
43+
await new Deno.Command(Deno.execPath(), {
44+
args: ["cache", "**/*"],
45+
cwd: tmp.dir,
46+
}).output();
47+
48+
const { stdout, stderr } = await new Deno.Command(Deno.execPath(), {
49+
args: ["check", "**/*"],
50+
cwd: tmp.dir,
51+
}).output();
52+
53+
const decoder = new TextDecoder();
54+
const output = `${decoder.decode(stdout)}\n${decoder.decode(stderr)}`;
55+
// Log `deno check` output (can be removed if expects below are enabled)
56+
// deno-lint-ignore no-console
57+
console.log(output);
58+
59+
// TODO: Enable after fixing docs check issues
60+
// expect(code).toBe(0);
61+
// expect(output).toBe("");
62+
});
63+
64+
async function* docsMarkdownFiles() {
65+
// Limit to checking Fresh v2 (canary) docs for now
66+
const docsDir = join(import.meta.dirname!, "..", "docs", "canary");
67+
const docsIter = walk(docsDir, { exts: [".md"], includeDirs: false });
68+
69+
for await (const entry of docsIter) {
70+
for (const { file, code } of await extractTsCode(entry.path)) {
71+
const path = join(relative(docsDir, entry.path), file);
72+
yield { path, code };
73+
}
74+
}
75+
}
76+
77+
async function extractTsCode(path: string) {
78+
const code: { file: string; code: string }[] = [];
79+
const input = await Deno.readTextFile(path);
80+
let index = 0;
81+
82+
const tokens = await Marked.lexer(input, { gfm: true, async: true });
83+
84+
Marked.walkTokens(tokens, (token) => {
85+
// Get rid of `Marked.Tokens.Generic`
86+
const t = token as Marked.MarkedToken;
87+
if (t.type !== "code") return;
88+
89+
const result = /^([tj]sx?)\s*/.exec(t.lang ?? "");
90+
if (!result) return;
91+
92+
// Codeblock must be TS/JS
93+
index += 1;
94+
95+
// Probably a filename, but perhaps a title,
96+
// so get rid of non-file safe characters
97+
const [match, ext] = result;
98+
let file = t.lang!.slice(match.length)
99+
.toLocaleLowerCase()
100+
.replaceAll(/[^a-z0-9._\-\/\\]/g, "_")
101+
.replaceAll(/_{2,}/g, "_") || String(index);
102+
103+
if (!file.endsWith(ext)) file += `.${ext}`;
104+
105+
code.push({ file, code: t.text });
106+
});
107+
108+
return code;
109+
}

0 commit comments

Comments
 (0)