Creations
A Creation is what’s returned by a template’s produce()
function.
It may contain any of the following properties:
- “Direct” creations that always cause changes to the repository:
- “Indirect” creations to hint to the Bingo CLI:
suggestions
: Printed tips for the next steps the user should take
For example, this template both creates a Prettier config and runs Prettier:
import { createTemplate } from "bingo";
export default createTemplate({ produce() { return { files: { ".prettierrc.json": `{ useTabs: true }`, }, scripts: ["npx prettier . --write"], }; },});
Direct Creations
These Creation properties always cause changes to the output repository.
files
Files to create or modify on disk.
This is the primary, most common output from templates.
Each object under files
describes a folder of files.
Properties whose values are strings are written as files on disk.
Properties whose values are objects represent a directory.
For example, this template generates a .github/CODE_OF_CONDUCT.md
file:
import { createTemplate } from "bingo";
export default createTemplate({ produce() { return { files: { ".github": { "CODE_OF_CONDUCT.md": `# Contributor Covenant Code of Conduct \n ...`, }, }, }; },});
That would instruct the Bingo engine to create a .github/
directory if it doesn’t exist yet, then create a .github/CODE_OF_CONDUCT.md
file.
See Packages > bingo-fs
> Files for more information on the files
format.
requests
Network requests to send after files are created.
This can be useful when repository settings or other APIs are necessary to align the created repository to what templates have produced.
Each request may be specified as an object with:
id
(string
): Unique ID to know how to deduplicate previous creations during mergingsend
(function): Asynchronous method that sends the request, which receives an object parameter containing:fetch
: Equivalent to the globalfetch
octokit
: GitHub Octokit that uses thefetch
internally
For example, this template a GitHub repository’s default branch to main
:
import { createTemplate } from "bingo";
export default createTemplate({ produce({ options }) { return { requests: [ { id: "default-branch", async send({ octokit }) { await octokit.rest.repos.update({ default_branch: "main", owner: options.owner, repo: options.repository, }); }, }, ], }; },});
scripts
Terminal commands to run after files are created.
This can be useful when shell scripts are necessary to apply changes to the repository to align the created repository to what templates have produced.
Each script may be specified as either a string or an object with:
commands
(string[]
): Shell scripts to run within the phase, in orderphase
(number
) (optional): What order, relative to any other command groups, to run insilent
(boolean
) (optional): Whether to skip logging errors if the script fails
Commands provided as strings are assumed to not be order-dependent. They are run all at the same time.
For example, this template runs pnpm package installation:
import { createTemplate } from "bingo";
export default createTemplate({ produce() { return { scripts: "pnpm install", }; },});
phase
Adding a phase
to a script indicates when it should run relative to other scripts.
Scripts with phase
start in ascending order of their phase
.
Each script with the same phase
will start running its commands at the same time.
For example, this template runs pnpm package installation and duplication in series within a first phase, then Prettier formatting in a subsequent phase after dependencies are done resolving:
import { createTemplate } from "bingo";
export default createTemplate({ produce() { return { scripts: [ { commands: ["pnpm install", "pnpm dedupe"], phase: 0, }, { commands: ["pnpx prettier . --write"], phase: 1, }, ], }; },});
Those phase-dependent scripts together would run the following commands in order:
pnpm install
pnpm dedupe
pnpm format --write
If multiple command groups specify the same phase
, then they will start executing their scripts at the same time.
The next phase will not be started until all scripts in that phase complete.
For example, given the following production of scripts:
[ { commands: ["a", "b"], phase: 0 }, { commands: ["c", "d"], phase: 1 }, { commands: ["e", "f"], phase: 1 }, { commands: ["g"], phase: 2 },];
Those commands would be run in the following order:
a
b
c
ande
d
(afterc
completes)f
(aftere
completes)
g
(afterd
andf
complete)
silent
Scripts may optionally include a silent: true
option to prevent an error being logged to the console if they fail.
Silent scripts are particularly useful for migration scripts that clean up existing files. Some native commands throw an error if a file doesn’t yet exist, which might not be a problem for common deletions.
For example, this template a .github/CONTRIBUTING.md
and deletes a root-level CONTRIBUTING.md
during transition if it exists:
import { createTemplate } from "bingo";
export default createTemplate({ produce() { return { files: { ".github": { "CONTRIBUTING.md": "...", }, }, }; }, transition() { return { scripts: [ { commands: ["rm CONTRIBUTING.md"], silent: true, }, ], }; },});
Indirect Creations
These Creation properties produce information purely for the Bingo CLI, not for the new repository.
suggestions
Tips for next steps the running user should take.
Some templates require additional setup that users will have to take action on. These will be logged to users after running the template’s CLI.
For example, this template directs the user to create an automation token:
import { base } from "./base";
export default createTemplate({ produce() { return { suggestions: [ "Set an NPM_TOKEN secret to an npm access token with automation permissions", ], }; },});