Skip to content

Commit

Permalink
feat: allow conditional rendering of files (#36)
Browse files Browse the repository at this point in the history
  • Loading branch information
btkostner authored Mar 29, 2024
1 parent c39925d commit 4aa31cc
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 9 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ echo $MY_KEY

All files in your `templates/` directory will be rendered with [Handlebars](https://handlebarsjs.com/) and placed in your repository. Handlebars will have access to any template key that was saved in the scripts step above.

### Conditional Rendering

In some instances you may want to allow only certain files to be rendered. This can be achieved by calling the `denyRender` handlebars function. This helper will prevent the file from being rendered and can be called from anywhere in the file (though we recommend up top.)

```handlebars
{{denyRender}}
```

```handlebars
{{~#if DO_NOT_RENDER_THIS_FILE}}{{denyRender}}{{/if~}}
```

## Alternatives

There are many other git sync type actions currently on GitHub, however most of them only handle static files. This action was created where some files are dynamic and should be templated or scripted before synced.
26 changes: 20 additions & 6 deletions src/handlebars.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { readFile, mkdtemp, rm } from "fs/promises";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import Handlebars from "./handlebars";
import Handlebars, { DenyRenderError } from "./handlebars";

describe.concurrent("handlebars", () => {
describe.concurrent("handlebars or", () => {
it("can use an or helper function", async (ctx) => {
const template = Handlebars.compile(
"{{#or KEY_ONE KEY_TWO KEY_THREE}}helpers: true{{else}}helpers: false{{/or}}",
Expand Down Expand Up @@ -31,23 +31,37 @@ describe.concurrent("handlebars", () => {

it("can use an or helper without an else statement", async (ctx) => {
const template = Handlebars.compile(
"{{#or POSTGRES_VERSION KAFKA_USAGE}} services:{{/or}}"
"{{#or POSTGRES_VERSION KAFKA_USAGE}} services:{{/or}}",
);
const result = template({
POSTGRES_VERSION: "14"
POSTGRES_VERSION: "14",
});

expect(result).toEqual(" services:");
});

it("allows statements in block", async (ctx) => {
const template = Handlebars.compile(
"{{#or POSTGRES_VERSION KAFKA_USAGE}}{{#if POSTGRES_VERSION}}POSTGRES{{/if}}{{#if KAFKA_USAGE}}KAFKA{{/if}}{{/or}}"
"{{#or POSTGRES_VERSION KAFKA_USAGE}}{{#if POSTGRES_VERSION}}POSTGRES{{/if}}{{#if KAFKA_USAGE}}KAFKA{{/if}}{{/or}}",
);
const result = template({
POSTGRES_VERSION: "14"
POSTGRES_VERSION: "14",
});

expect(result).toEqual("POSTGRES");
});
});

describe.concurrent("handlebars denyRender", () => {
it("raises an error when called", async (_ctx) => {
const template = Handlebars.compile("{{denyRender}}");

expect(() => template({})).toThrowError(DenyRenderError);
});

it("does not raise an error in conditional block", async (_ctx) => {
const template = Handlebars.compile("{{#if false}}{{denyRender}}{{/if}}");

expect(() => template({})).not.toThrowError(DenyRenderError);
});
});
7 changes: 6 additions & 1 deletion src/handlebars.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Handlebars from "handlebars";
import isObject from "lodash/isObject";

export class DenyRenderError extends Error {}

Handlebars.registerHelper("or", function (...params) {
const options = params[params.length - 1];
Expand All @@ -14,4 +15,8 @@ Handlebars.registerHelper("or", function (...params) {
return options.inverse(this);
});

Handlebars.registerHelper("denyRender", function () {
throw new DenyRenderError();
});

export default Handlebars;
24 changes: 24 additions & 0 deletions src/templates.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { existsSync } from "fs";
import { readFile, mkdtemp, rm } from "fs/promises";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { join, resolve } from "path";
Expand Down Expand Up @@ -62,4 +63,27 @@ describe.concurrent("templates", () => {
`{\n "keyOne": true,\n "keyTwo": "valueTwo",\n "keyThree": "valueThree"\n}\n`,
);
});

it<LocalTestContext>("will render a regular markdown file", async (ctx) => {
await templateFiles(ctx.config);
const path = join(ctx.config.fullPath, "conditional.md");
const data = await readFile(path, "utf8");

expect(data).toEqual(
`# Conditional Markdown File
This file will only be templated if the \`NO_MARKDOWN\` environment variable is not set. Otherwise, it will be rendered as a normal markdown file.
`,
);
});

it<LocalTestContext>("will not template files if the denyRender helper is called", async (ctx) => {
await templateFiles({
...ctx.config,
templateVariables: { NO_MARKDOWN: "true" },
});
const path = join(ctx.config.fullPath, "conditional.md");
const fileExists = existsSync(path);
expect(fileExists).toBe(false);
});
});
8 changes: 6 additions & 2 deletions src/templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { dirname, join, relative } from "path";
import { mkdirP } from "@actions/io";

import { Config } from "./config";
import Handlebars from "./handlebars";
import Handlebars, { DenyRenderError } from "./handlebars";

export async function templateFiles(config: Config): Promise<void> {
const templateGlob = await glob.create(`${config.syncPath}/templates/*`, {
Expand Down Expand Up @@ -36,7 +36,11 @@ export async function templateFiles(config: Config): Promise<void> {

core.debug("File written.");
} catch (err) {
core.error(`Error templating ${relativePath}: ${err}`);
if (err instanceof DenyRenderError) {
core.debug(`denyRender was called for ${relativePath}`);
} else {
core.error(`Error templating ${relativePath}: ${err}`);
}
}
}
}
7 changes: 7 additions & 0 deletions test/fixtures/templates/conditional.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{{~#if NO_MARKDOWN}}
{{ denyRender }}
{{/if~}}

# Conditional Markdown File

This file will only be templated if the `NO_MARKDOWN` environment variable is not set. Otherwise, it will be rendered as a normal markdown file.

0 comments on commit 4aa31cc

Please sign in to comment.