Skip to content

Commit f65df76

Browse files
authored
Merge pull request #5 from code4rena-dev/feat/template-ci
feat: add mustache generator and use it for ci
2 parents 6589085 + 38d8190 commit f65df76

File tree

6 files changed

+106
-5
lines changed

6 files changed

+106
-5
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
!/.github/
1010
!/.gitignore
1111
!/.npmrc
12+
!/Dockerfile
1213
!/bin/
1314
!/CHANGELOG*
1415
!/docs/
@@ -23,7 +24,6 @@
2324
!/tap-snapshots/
2425
!/test/
2526
!/tsconfig*.json
26-
!Dockerfile
2727

2828
# re-ignore typescript output artifacts
2929
/knexfile.js

lib/content/ci.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,22 @@ jobs:
3838
defaults:
3939
run:
4040
shell: bash
41+
<%#postgres%>
42+
services:
43+
postgres:
44+
image: "postgres:14"
45+
env:
46+
POSTGRES_USER: ${{ vars.POSTGRES_USER }}
47+
POSTGRES_PASSWORD: ${{ vars.POSTGRES_PASSWORD }}
48+
POSTGRES_DB: ${{ vars.POSTGRES_DB }}
49+
options: >-
50+
--health-cmd pg_isready
51+
--health-interval 10s
52+
--health-timeout 5s
53+
--health-retries 5
54+
ports:
55+
- "${{ vars.POSTGRES_PORT }}:5432"
56+
<%/postgres%>
4157
steps:
4258
- name: Checkout
4359
uses: actions/checkout@v3
@@ -52,4 +68,8 @@ jobs:
5268
- name: Add tap problem matcher
5369
run: echo "::add-matcher::.github/matchers/tap.json"
5470
- name: Test
71+
<%#env_vault%>
72+
env:
73+
DOTENV_KEY: ${{ secrets.DOTENV_KEY }}
74+
<%/env_vault%>
5575
run: npm test --ignore-scripts

lib/content/gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44

55
# keep these
66
!**/.gitignore
7+
!/.devcontainer/
78
!/.eslintrc.js
89
!/.github/
910
!/.gitignore
1011
!/.npmrc
12+
!/Dockerfile
1113
!/bin/
1214
!/CHANGELOG*
1315
!/docs/

lib/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { dirname, join } from "node:path";
22
import { readFileSync } from "node:fs";
33
import { readFile, rm } from "node:fs/promises";
44
import { copy, json, pkg, type Skeleton } from "code-skeleton";
5+
import { mustache } from "./mustache";
56

67
const ownPkg = JSON.parse(
78
readFileSync(join(dirname(__dirname), "package.json"), { encoding: "utf8" })
@@ -10,6 +11,7 @@ const ownPkg = JSON.parse(
1011
interface Variables {
1112
dogfood?: boolean;
1213
library?: boolean;
14+
ci?: object;
1315
}
1416

1517
export default async function (root: string, variables: Variables) {
@@ -51,12 +53,14 @@ export default async function (root: string, variables: Variables) {
5153
},
5254
types: "lib/index.d.ts",
5355
devDependencies: {
54-
"@tsconfig/node18": "^2.0.0",
56+
"@tsconfig/node18": "^18.0.0",
57+
"@types/mustache": "^4.0.0",
5558
"@types/node": "^18.0.0",
5659
"@types/tap": "^15.0.0",
5760
"@typescript-eslint/eslint-plugin": "^5.0.0",
5861
"@typescript-eslint/parser": "^5.0.0",
5962
"eslint": "^8.0.0",
63+
"mustache": "^4.0.0",
6064
"tap": "^16.0.0",
6165
"ts-node": "^10.0.0",
6266
"typescript": "^5.0.0"
@@ -94,7 +98,7 @@ export default async function (root: string, variables: Variables) {
9498
".eslintrc.js": copy(join(__dirname, "content", "eslintrc.js")),
9599
".gitignore": copy(join(__dirname, "content", "gitignore")),
96100
"scripts/clean.ts": copy(join(__dirname, "content", "clean.ts")),
97-
".github/workflows/ci.yml": copy(join(__dirname, "content", "ci.yml")),
101+
".github/workflows/ci.yml": mustache(join(__dirname, "content", "ci.yml"), variables.ci),
98102
".github/matchers/tap.json": copy(join(__dirname, "content", "tap.json")),
99103
};
100104

lib/mustache.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import {
2+
Generator,
3+
GeneratorResults,
4+
GeneratorOptions
5+
} from "code-skeleton/lib/generators/abstract";
6+
import { dirname } from "node:path";
7+
import { writeFile, mkdir, readFile } from "node:fs/promises";
8+
import Mustache from "mustache";
9+
Mustache.tags = [ "<%", "%>" ];
10+
11+
interface MustacheGeneratorOptions extends GeneratorOptions {
12+
sourcePath: string;
13+
}
14+
15+
class MustacheGenerator extends Generator {
16+
declare options: MustacheGeneratorOptions;
17+
18+
constructor (options: MustacheGeneratorOptions) {
19+
super(options);
20+
21+
if (!this.options.sourcePath) {
22+
throw new Error("Must specify a source path");
23+
}
24+
}
25+
26+
async apply(targetPath: string): Promise<GeneratorResults> {
27+
await mkdir(dirname(targetPath), { recursive: true });
28+
try {
29+
const source = await readFile(this.options.sourcePath);
30+
31+
const rendered = Mustache.render(source.toString(), this.options);
32+
await writeFile(targetPath, rendered);
33+
return this.pass();
34+
} catch (err) {
35+
const { code, message } = err as { code?: string; message: string };
36+
// istanbul ignore next - no need to test message fallback
37+
return this.fail(code ?? message);
38+
}
39+
}
40+
async verify(targetPath: string): Promise<GeneratorResults> {
41+
let actual;
42+
try {
43+
actual = await readFile(targetPath);
44+
} catch (err) {
45+
const { code, message } = err as { code?: string; message: string };
46+
// istanbul ignore next - no need to test passthrough throws
47+
if (code !== "ENOENT") {
48+
return this.fail(code ?? message);
49+
}
50+
51+
return this.fail("file missing");
52+
}
53+
54+
const source = await readFile(this.options.sourcePath);
55+
const expected = Buffer.from(Mustache.render(source.toString(), this.options));
56+
if (actual.compare(expected) === 0) {
57+
return this.pass();
58+
}
59+
60+
return this.fail("contents do not match");
61+
}
62+
}
63+
64+
export function mustache (sourcePath: string, options: GeneratorOptions = {}) {
65+
return new MustacheGenerator({
66+
...options,
67+
sourcePath
68+
});
69+
}

package.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818
"author": "Nathan LaFreniere <[email protected]>",
1919
"license": "ISC",
2020
"devDependencies": {
21-
"@tsconfig/node18": "^2.0.0",
21+
"@tsconfig/node18": "^18.0.0",
22+
"@types/mustache": "^4.0.0",
2223
"@types/node": "^18.0.0",
2324
"@types/tap": "^15.0.0",
2425
"@typescript-eslint/eslint-plugin": "^5.0.0",
2526
"@typescript-eslint/parser": "^5.0.0",
2627
"eslint": "^8.0.0",
28+
"mustache": "^4.0.0",
2729
"tap": "^16.0.0",
2830
"ts-node": "^10.0.0",
2931
"typescript": "^5.0.0"
@@ -34,7 +36,11 @@
3436
"skeleton": {
3537
"module": ".",
3638
"variables": {
37-
"library": true
39+
"library": true,
40+
"ci": {
41+
"postgres": false,
42+
"env_vault": false
43+
}
3844
}
3945
},
4046
"files": [

0 commit comments

Comments
 (0)