From 16ed4e75704efdf7d45d5991728bf2df5209175c Mon Sep 17 00:00:00 2001 From: Blake Kostner Date: Wed, 17 Apr 2024 15:05:17 -0600 Subject: [PATCH] feat: allow templates to be executable files (#41) Allows you to `chmod +x` a template file, making it executable. Then when templating the file, the resulting file will also be executable. --- src/templates.test.ts | 11 +++++++++-- src/templates.ts | 7 ++++++- test/fixtures/templates/executable.sh | 3 +++ 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100755 test/fixtures/templates/executable.sh diff --git a/src/templates.test.ts b/src/templates.test.ts index 9dac3d5..56c2a46 100644 --- a/src/templates.test.ts +++ b/src/templates.test.ts @@ -1,9 +1,8 @@ import { existsSync } from "fs"; -import { readFile, mkdtemp, rm } from "fs/promises"; +import { readFile, mkdtemp, rm, stat } from "fs/promises"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { join, resolve } from "path"; import { tmpdir } from "os"; -import { v4 as uuid } from "uuid"; import { Config } from "./config"; import { templateFiles } from "./templates"; @@ -86,4 +85,12 @@ This file will only be templated if the \`NO_MARKDOWN\` environment variable is const fileExists = existsSync(path); expect(fileExists).toBe(false); }); + + it("will use the same file permissions as the template", async (ctx) => { + await templateFiles(ctx.config); + const path = join(ctx.config.fullPath, "executable.sh"); + const stats = await stat(path); + + expect(stats.mode.toString(8)).toBe("100755"); + }); }); diff --git a/src/templates.ts b/src/templates.ts index 6841d67..b9f8301 100644 --- a/src/templates.ts +++ b/src/templates.ts @@ -1,6 +1,6 @@ import * as core from "@actions/core"; import * as glob from "@actions/glob"; -import { open, readFile, writeFile } from "fs/promises"; +import { chmod, open, readFile, stat, writeFile } from "fs/promises"; import { dirname, join, relative } from "path"; import { mkdirP } from "@actions/io"; @@ -20,6 +20,7 @@ export async function templateFiles(config: Config): Promise { core.info(`Template ${relativePath}`); try { + const templateStats = await stat(templatePath); const templateData = await readFile(templatePath, "utf8"); const templateHandlebar = Handlebars.compile(templateData); const fileData = templateHandlebar(config.templateVariables); @@ -33,6 +34,10 @@ export async function templateFiles(config: Config): Promise { const io = await open(writePath, "a"); await io.close(); await writeFile(writePath, fileData); + await chmod( + writePath, + "0" + (templateStats.mode & parseInt("777", 8)).toString(8), + ); core.debug("File written."); } catch (err) { diff --git a/test/fixtures/templates/executable.sh b/test/fixtures/templates/executable.sh new file mode 100755 index 0000000..c5f6810 --- /dev/null +++ b/test/fixtures/templates/executable.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env + +echo "This is an executable script."