<|start_filename|>lib/create-pull-request.js<|end_filename|>
export default async function createPullRequest(
  octokit,
  { owner, repo, ownerId, repositoryId }
) {
  let body = `Your new script is ready to be implemented :tada:

You can run it locally on your machine with

\`\`\`
node cli.js
\`\`\`

Once you are happy with it, push your changes to this pull request

\`\`\`
git commit -a -m "feat: initial version"
git push
\`\`\`

Before merging:

- [ ] [Install the Octoherd GitHub App](https://github.com/apps/octoherd/installations/new/permissions?suggested_target_id=${ownerId}&repository_ids[]=${repositoryId})
`;

  if (owner !== "octoherd") {
    body += `- [ ] Add \`NPM_TOKEN\` to the [repository secrets](https://github.com/${owner}/${repo}/settings/secrets). Set it to an [npm automation token](https://docs.npmjs.com/creating-and-viewing-access-tokens#creating-access-tokens)`;
  }

  const options = {
    owner,
    repo,
    head: "initial-version",
    base: "main",
    title:
      owner === "octoherd"
        ? "🚧 feat: Initial version"
        : "feat: Initial version",
    body,
  };
  await octokit.request("POST /repos/{owner}/{repo}/pulls", options);
}


<|start_filename|>lib/create-github-action.js<|end_filename|>
import writePrettyFile from "./write-pretty-file.js";
import getTemplateFileContent from "./get-template-file-content.js";

export default async function createGitHubAction(actionFileName, options = {}) {
  let fileContent = getTemplateFileContent(`github-actions/${actionFileName}`);

  if (options.replace) {
    fileContent = fileContent.replace(
      options.replace.searchValue,
      options.replace.replaceValue
    );
  }

  await writePrettyFile(`.github/workflows/${actionFileName}`, fileContent);
}


<|start_filename|>cli.js<|end_filename|>
#!/usr/bin/env node

import { inspect } from "util";
import { mkdir, writeFile } from "fs/promises";

import inquirer from "inquirer";
import { Octokit } from "@octokit/core";
import { createOAuthDeviceAuth } from "@octokit/auth-oauth-device";
import clipboardy from "clipboardy";

import command from "./lib/command.js";
import createBranchProtection from "./lib/create-branch-protection.js";
import createCoc from "./lib/create-coc.js";
import createContributing from "./lib/create-contributing.js";
import createIssueTemplates from "./lib/create-issue-templates.js";
import createLicense from "./lib/create-license.js";
import createPackageJson from "./lib/create-package-json.js";
import createPullRequest from "./lib/create-pull-request.js";
import createReadme from "./lib/create-readme.js";
import createReleaseAction from "./lib/create-release-action.js";
import createTestAction from "./lib/create-test-action.js";
import createRepository from "./lib/create-repository.js";
import createScript from "./lib/create-script.js";
import prompts from "./lib/prompts.js";
import writePrettyFile from "./lib/write-pretty-file.js";

main();

async function main() {
  const { repoIsPrivate } = await inquirer.prompt({
    name: "repoIsPrivate",
    type: "list",
    message: "Do you want to create a public or private repository?",
    choices: ["public", "private"],
    filter: (input) => input === "private",
  });

  const auth = createOAuthDeviceAuth({
    clientId: "<KEY>", // Create Octoherd Script OAuth app by @octoherd
    scopes: repoIsPrivate ? ["repo"] : ["public_repo"],
    async onVerification({ verification_uri, user_code }) {
      console.log("Open %s", verification_uri);

      await clipboardy.write(user_code);
      console.log("Paste code: %s (copied to your clipboard)", user_code);

      await inquirer.prompt({
        name: "grant_access",
        type: "confirm",
        message: "Press <enter> when ready",
      });
    },
  });

  const { token } = await auth({ type: "oauth" });
  const octokit = new Octokit({ auth: token });
  octokit.hook.before("request", async (options) => {
    const { method, url, ...parameters } = octokit.request.endpoint.parse(
      options
    );
    console.log(`> ${method} ${url.replace("https://api.github.com", "")}`);
    for (const [name, value] of Object.entries(parameters.headers)) {
      console.log(`  ${name}: ${value}`);
    }
    if (parameters.body) {
      console.log(``);
      for (const [name, value] of Object.entries(parameters.body)) {
        console.log(`  ${name}: ${inspect(value)}`);
      }
    }
  });

  // get user information
  const {
    data: { id: userId, login, name, email, blog: website, twitter_username },
  } = await octokit.request("GET /user");

  try {
    const answers = await prompts({
      login,
      name,
      email,
      website,
      twitter_username,
    });

    const [owner, repo] = answers.repository.split("/");
    const isUserRepo = answers.repository.startsWith(login);

    // create project folder and chdir into it
    console.log(`Creating ${answers.path}`);
    await mkdir(answers.path, { recursive: true });
    process.chdir(answers.path);

    await command("git init");
    await command("git checkout -b main");

    createLicense(answers.licenseName);
    console.log(`LICENSE created`);

    createCoc(answers.cocEmail);
    console.log(`CODE_OF_CONDUCT.md created`);

    createContributing({ owner, repo, packageName: answers.packageName });
    console.log(`CONTRIBUTING.md created`);

    await createReadme({
      addWip: true,
      repository: answers.repository,
      repo,
      description: answers.description,
    });
    console.log(`README.md created`);

    await command("git add LICENSE.md");
    await command("git commit -m 'docs(LICENSE): ISC'");

    await command("git add CODE_OF_CONDUCT.md");
    await command(
      "git commit -m 'docs(CODE_OF_CONDUCT): Contributor Covenant'"
    );

    await command("git add CONTRIBUTING.md");
    await command("git commit -m 'docs(CONTRIBUTING): initial version'");

    await command("git add README.md");
    await command("git commit -m 'docs(README): initial version'");

    await createIssueTemplates(answers.packageName);
    await command("git add .github/ISSUE_TEMPLATE");
    await command("git commit -m 'docs(ISSUE_TEMPLATES): initial version'");

    const {
      data: { id: repositoryId },
    } = await createRepository(octokit, {
      isUserRepo,
      owner,
      repo,
      description: answers.description,
      repoIsPrivate,
    });

    await command(
      `git remote add origin <EMAIL>:${answers.repository}.git`
    );
    await command(`git push -u origin HEAD`);
    await command(`git checkout -b initial-version`);

    createReadme({
      repo,
      description: answers.description,
    });

    await command(`git commit README.md -m 'docs(README): remove WIP note'`);
    await command(`git push -u origin HEAD`);

    let ownerId = userId;
    if (!isUserRepo) {
      const { data } = await octokit.request("GET /orgs/{org}", {
        org: owner,
      });
      ownerId = data.id;
    }

    await createPullRequest(octokit, {
      owner,
      repo,
      ownerId,
      repositoryId,
    });

    await createPackageJson(owner, repo, answers);
    console.log("Install dependencies");
    const dependencies = ["@octoherd/cli"];

    await command(`npm install ${dependencies.join(" ")}`);

    await command(`git add package.json`);
    await command(`git commit -m 'build(package): initial version'`);
    await command(`git add package-lock.json`);
    await command(`git commit -m 'build(package): lock file'`);

    console.log("Create branch protection for main");
    try {
      await createBranchProtection(octokit, { owner, repo });
    } catch (error) {
      if (error.status !== 403) throw error;

      console.log(
        "Branch protection could not be enabled, because the repository is private and belongs to an organization using the free plan"
      );
    }

    const ignorePaths = ["node_modules"];
    await writePrettyFile(".gitignore", ignorePaths.join("\n"));
    await command(`git add .gitignore`);
    await command(
      `git commit -m 'build(gitignore): ${ignorePaths.join(", ")}'`
    );

    console.log("create script.js and cli.js");
    await createScript(answers);
    await writeFile(
      // we cannot use writePrettyFile, it blows because of the #! in the first line
      "cli.js",
      `#!/usr/bin/env node

import { script } from "./script.js";
import { run } from "@octoherd/cli/run";

run(script);
`
    );

    await command(`git add script.js cli.js`);
    await command(`git commit -m 'feat: initial version'`);

    await createReadme({
      addBadges: true,
      repo,
      description: answers.description,
      packageName: answers.packageName,
      repository: answers.repository,
    });
    await command(`git commit README.md -m 'docs(README): badges'`);

    await createReadme({
      addBadges: true,
      addUsage: true,
      owner,
      repo,
      description: answers.description,
      packageName: answers.packageName,
      repository: answers.repository,
      scriptOptions: answers.scriptOptions,
    });
    await command(`git commit README.md -m 'docs(README): usage'`);

    console.log("Create actions");
    await createReleaseAction({ owner });
    await command(`git add .github/workflows/release.yml`);
    await command(`git commit -m 'ci(release): initial version'`);

    await createTestAction();
    await command(`git add .github/workflows/test.yml`);
    await command(`git commit -m 'ci(test): initial version'`);

    await command(`git push`);

    console.log(`Your new repository is here:
https://github.com/${answers.repository}

To change into the new directory, do 
$ cd ${answers.path}`);
  } catch (error) {
    console.log(error);
  }

  console.log("All done.");
}


<|start_filename|>lib/create-contributing.js<|end_filename|>
import writePrettyFile from "./write-pretty-file.js";

export default async function createContributing({ owner, repo, packageName }) {
  await writePrettyFile(
    "CONTRIBUTING.md",
    `
# How to contribute

Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md).
By participating in this project you agree to abide by its terms.

We appreciate you taking the time to contribute to \`${packageName}\`. Especially as a new contributor, you have a valuable perspective that we lost a long time ago: you will find things confusing and run into problems that no longer occur to us. Please share them with us, so we can make the experience for future contributors the best it could be.

Thank you 💖

## Creating an Issue

Before you create a new Issue:

1. Please make sure there is no [open issue](https://github.com/${owner}/${repo}/issues?utf8=%E2%9C%93&q=is%3Aissue) yet.
2. If it is a bug report, include the steps to reproduce the issue
3. If it is a feature request, please share the motivation for the new feature, what alternatives you tried, and how you would implement it.

## Setup the repository locally

First, fork the repository.

Setup the repository locally. Replace \`<your account name>\` with the name of the account you forked to.

\`\`\`shell
git clone https://github.com/<your account name>/${repo}.git
cd ${repo}
npm install
\`\`\`

Run the tests before making changes to make sure the local setup is working as expected

\`\`\`shell
npm test
\`\`\`

## Submitting the Pull Request

- Create a new branch locally.
- Make your changes in that branch and push them to your fork
- Submit a pull request from your topic branch to the main branch on the \`${owner}/${repo}\` repository.
- Be sure to tag any issues your pull request is taking care of / contributing to. Adding "Closes #123" to a pull request description will automatically close the issue once the pull request is merged in.

## Maintainers only

### Merging the Pull Request & releasing a new version

Releases are automated using [semantic-release](https://github.com/semantic-release/semantic-release).
The following commit message conventions determine which version is released:

1. \`fix: ...\` or \`fix(scope name): ...\` prefix in subject: bumps fix version, e.g. \`1.2.3\` → \`1.2.4\`
2. \`feat: ...\` or \`feat(scope name): ...\` prefix in subject: bumps feature version, e.g. \`1.2.3\` → \`1.3.0\`
3. \`BREAKING CHANGE:\` in body (**Important**: commit body, not subject!): bumps breaking version, e.g. \`1.2.3\` → \`2.0.0\`

Only one version number is bumped at a time, the highest version change trumps the others.
Besides publishing a new version to npm, semantic-release also creates a git tag and release
on GitHub, generates changelogs from the commit messages and puts them into the release notes.

If the pull request looks good but does not follow the commit conventions, use the <kbd>Squash & merge</kbd> button.
`
  );
}


<|start_filename|>lib/write-pretty-file.js<|end_filename|>
import { mkdir, writeFile } from "fs/promises";
import { extname, dirname } from "path";

import pretier from "prettier";

export default async function writePrettyFile(path, content) {
  const ext = extname(path);

  // make sure the path exists
  await mkdir(dirname(path), { recursive: true });

  if (!ext) {
    return writeFile(path, content + "\n");
  }

  const parser = {
    ".js": "babel",
    ".json": "json",
    ".md": "markdown",
    ".ts": "typescript",
    ".yml": "yaml",
  }[ext];

  if (!parser) throw new Error(`Define parser for ${path}`);

  await writeFile(
    path,
    pretier.format(content, {
      parser,
    })
  );
}


<|start_filename|>lib/create-coc.js<|end_filename|>
import getTemplateFileContent from "./get-template-file-content.js";
import writePrettyFile from "./write-pretty-file.js";

export default async function createCoc(email) {
  const contributorCovenantText = getTemplateFileContent(
    "CODE_OF_CONDUCT.md"
  ).replace("{{EMAIL}}", email);
  await writePrettyFile("CODE_OF_CONDUCT.md", contributorCovenantText);
}


<|start_filename|>lib/create-script.js<|end_filename|>
import writePrettyFile from "./write-pretty-file.js";

export default async function createScript({ description, scriptOptions }) {
  let optionsParam = "";

  const args = ["octokit", "repository"];

  if (Object.keys(scriptOptions).length) {
    optionsParam += "* @param {object} options\n";

    const optionsArgs = [];
    Object.entries(scriptOptions).forEach(([name, option]) => {
      const objName = option.required ? `options.${name}` : `[options.${name}]`;
      optionsParam += `* @param {${option.type}} ${objName} ${option.description}\n`;

      if (!option.default) {
        optionsArgs.push(name);
        return;
      }

      if (option.type === "number") {
        optionsArgs.push(`${name} = ${option.default}`);
        return;
      }

      optionsArgs.push(`${name} = "${option.default}"`);
    });

    args.push(`{${Object.keys(scriptOptions).join(", ")}}`);
  }

  const content = [
    `
      // @ts-check
      
      /**
       * ${description}
       *
       * @param {import('@octoherd/cli').Octokit} octokit
       * @param {import('@octoherd/cli').Repository} repository`,
    optionsParam.trim(),
    `  */
      export async function script(${args.join(", ")}) {
    
      }
    `,
  ].filter(Boolean);

  await writePrettyFile("script.js", content.join("\n"));
}


<|start_filename|>lib/create-repository.js<|end_filename|>
export default async function createRepository(
  octokit,
  { isUserRepo, owner, repo, description, repoIsPrivate }
) {
  const createRepoOptions = {
    name: repo,
    description,
    private: repoIsPrivate,
    has_wiki: false,
    has_projects: false,
    allow_merge_commit: false,
    allow_rebase_merge: false,
    delete_branch_on_merge: true,
  };

  let repositoryResponse;
  if (isUserRepo) {
    repositoryResponse = octokit.request("POST /user/repos", createRepoOptions);
  } else {
    repositoryResponse = octokit.request("POST /orgs/{org}/repos", {
      org: owner,
      ...createRepoOptions,
    });
  }

  // waiting 3s until #6 is resolved
  await new Promise((resolve) => setTimeout(resolve, 3000));

  // add topic
  await octokit.request("PUT /repos/{owner}/{repo}/topics", {
    mediaType: {
      previews: ["mercy"],
    },
    owner,
    repo,
    names: ["octoherd-script"],
  });

  return repositoryResponse;
}


<|start_filename|>lib/create-license.js<|end_filename|>
import getTemplateFileContent from "./get-template-file-content.js";
import writePrettyFile from "./write-pretty-file.js";

export default async function createLicense(name) {
  await writePrettyFile(
    "LICENSE.md",
    getTemplateFileContent("LICENSE.md")
      .replace("{{YEAR}}", new Date().getFullYear())
      .replace("{{OWNER}}", name)
  );
}


<|start_filename|>lib/prompts.js<|end_filename|>
import inquirer from "inquirer";
import camelcase from "camelcase";

export default async function prompts({
  login,
  name,
  email,
  website,
  twitter_username,
}) {
  const answers1 = await inquirer.prompt([
    {
      type: "input",
      name: "packageName",
      message:
        "What npm package name should the project have? (Example: octoherd-script-hello-world)",
    },
    {
      type: "confirm",
      name: "publicAccess",
      message: (answers) =>
        `Should the package ${answers.packageName} be publicly accessible?`,
      default: true,
      when: (answers) => answers.packageName.startsWith("@"),
    },
    {
      type: "input",
      name: "description",
      message: "Description for npm package and the GitHub repository",
    },
    {
      type: "input",
      name: "repository",
      message:
        "Full name of the repository. Name must start with 'octoherd-script-' (Example: octocat/octoherd-script-hello-world)",
      default: (answers) => {
        if (answers.packageName.startsWith("@octoherd")) {
          return answers.packageName.substr(1);
        }

        return answers.packageName.startsWith("@")
          ? answers.packageName.substr(1)
          : [login, answers.packageName].join("/");
      },
      validate: (input) =>
        /^[^/]+\/octoherd-script-/.test(input) ||
        /^octoherd\/script-/.test(input),
    },
  ]);

  const { scriptOptionNames } = await inquirer.prompt({
    type: "input",
    name: "scriptOptionNames",
    message:
      "Comma-separated list of script options (camelCase). Leave empty if there are none",
    filter: (input) =>
      input
        .split(/,/)
        .map((name) => camelcase(name.trim()))
        .filter(Boolean),
  });

  const scriptOptions = {};
  for (const name of scriptOptionNames) {
    scriptOptions[name] = await inquirer.prompt([
      {
        type: "list",
        name: "type",
        message: `What type is ${name}?`,
        choices: ["string", "number", "boolean"],
      },
      {
        type: "list",
        name: "required",
        message: `Is the ${name} option optional or required?`,
        choices: ["optional", "required"],
        filter: (input) => input === "required",
        when: (answers) => answers.type !== "boolean",
      },
      {
        type: "input",
        name: "default",
        message: `Default value (if any)`,
        when: (answers) => !answers.required && answers.type !== "boolean",
      },
      {
        type: "input",
        name: "example",
        message: `Example value`,
        when: (answers) => answers.type !== "boolean",
      },
      {
        type: "input",
        name: "description",
        message: `Description for ${name} option (optional)`,
      },
    ]);
  }

  const answers2 = await inquirer.prompt([
    {
      type: "input",
      name: "packageAuthor",
      message: 'Value for "author" key in package.json',
      default: () => {
        if (!name) return;
        let author = name;

        if (email) {
          author += ` <${email}>`;
        }

        if (website) {
          author += ` (${website})`;
        } else if (twitter_username) {
          author += ` (https://twitter.com/${twitter_username})`;
        } else {
          author += ` (https://github.com/${login})`;
        }

        return author;
      },
    },
    {
      type: "input",
      name: "cocEmail",
      message:
        "What email can folks reach out to for Code of Conduct inquiries?",
      default: () =>
        answers1.packageName.startsWith("@octoherd")
          ? "<EMAIL>"
          : email,
    },
    {
      type: "input",
      name: "licenseName",
      message: "Name for license",
      default: () =>
        answers1.packageName.startsWith("@octoherd")
          ? "Octoherd contributors"
          : name,
    },
    {
      type: "input",
      name: "path",
      message: `Folder path to initialize the project in, relative to current path. If the path does not yet exist it will be created. Current path is ${process.cwd()})`,
      default: () => answers1.repository.split("/")[1],
    },
  ]);

  return {
    ...answers1,
    ...answers2,
    scriptOptions,
  };
}


<|start_filename|>lib/create-issue-templates.js<|end_filename|>
import writePrettyFile from "./write-pretty-file.js";

export default async function createIssueTemplates(packageName) {
  await writePrettyFile(
    ".github/ISSUE_TEMPLATE/01_bug.md",
    `---
name: "🐛 Bug Report"
about: "If something isn't working as expected 🤔"
labels: bug
---

<!-- Please replace all placeholders such as this below -->

**What happened?**

<!-- Describe the problem and how to reproduce it. Add screenshots or a link to your repository if possible and helpful -->

**What did you expect to happen?**

<!-- Describe what you expected to happen instead -->

**What the problem might be**

<!-- If you have an idea where the bug might lie, please share here. Otherwise remove the whole section -->
`
  );
  await writePrettyFile(
    ".github/ISSUE_TEMPLATE/02_feature_request.md",
    `---
name: "🧚‍♂️ Feature Request"
about: "Wouldn’t it be nice if 💭"
labels: feature
---

<!-- Please replace all placeholders such as this below -->

**What’s missing?**

<!-- Describe your feature idea  -->

**Why?**

<!-- Describe the problem you are facing -->

**Alternatives you tried**

<!-- Describe the workarounds you tried so far and how they worked for you -->
`
  );
}


<|start_filename|>lib/create-package-json.js<|end_filename|>
import writePrettyFile from "./write-pretty-file.js";

export default async function createPackageJson(owner, repo, answers) {
  const binName = owner === "octoherd" ? `octoherd-${repo}` : repo;
  const pkg = {
    name: answers.packageName,
    version: "0.0.0-development",
    type: "module",
    exports: "./script.js",
    bin: {
      [binName]: "./cli.js",
    },
    description: answers.description,
    scripts: {
      start: "node cli.js",
      test: "node script.js",
    },
    repository: `https://github.com/${answers.repository}`,
    keywords: ["octoherd-script"],
    author: answers.packageAuthor,
    license: "ISC",
    dependencies: {},
    devDependencies: {},
    release: {
      branches: ["main"],
    },
  };

  if (answers.publicAccess) {
    pkg.publishConfig = {
      access: "public",
    };
  }

  await writePrettyFile("package.json", JSON.stringify(pkg));
}


<|start_filename|>lib/get-template-file-content.js<|end_filename|>
import { readFileSync } from "fs";
import { join as pathJoin, dirname } from "path";
import { fileURLToPath } from "url";

export default function getTemplateFileContent(filename) {
  // https://stackoverflow.com/a/50052194/206879
  const __dirname = dirname(fileURLToPath(import.meta.url));

  return readFileSync(pathJoin(__dirname, "..", "templates", filename), "utf8");
}


<|start_filename|>lib/create-release-action.js<|end_filename|>
import createGitHubAction from "./create-github-action.js";

export default async function createReleaseAction({ owner }) {
  const npmTokenSecretName =
    owner === "octoherd" ? "NPM_AUTOMATION_TOKEN" : "NPM_TOKEN";

  await createGitHubAction("release.yml", {
    replace: {
      searchValue: "__npmTokenSecretName__",
      replaceValue: npmTokenSecretName,
    },
  });
}


<|start_filename|>lib/create-readme.js<|end_filename|>
import decamelize from "decamelize";

import writePrettyFile from "./write-pretty-file.js";

export default async function createReadme({
  repository,
  owner,
  repo,
  description,
  packageName,
  addWip,
  addBadges,
  addUsage,
  scriptOptions,
}) {
  let content = "";

  if (addWip) {
    // WIP banner
    content += `# 🚧 WORK IN PROGRESS. See [#1](https://github.com/${repository}/pull/1) | [Preview](https://github.com/${repository}/tree/initial-version)

`;
  }

  // header
  content += `# ${repo}\n\n`;

  if (description) {
    content += `> ${description}\n\n`;
  }

  if (addBadges) {
    content += `[![@latest](https://img.shields.io/npm/v/${packageName}.svg)](https://www.npmjs.com/package/${packageName})
[![Build Status](https://github.com/${repository}/workflows/Test/badge.svg)](https://github.com/${repository}/actions?query=workflow%3ATest+branch%3Amain)

`;
  }

  if (addUsage) {
    let minimalUsage = `npx ${packageName}`;
    let fullUsage = `npx ${packageName} \\
  -T ghp_0123456789abcdefghjklmnopqrstuvwxyzA \\
  -R "${owner}/*"`;

    Object.entries(scriptOptions).forEach(([name, { required, example }]) => {
      if (!required) return;
      minimalUsage += ` \\
  --${name} ${example}`;
    });
    Object.entries(scriptOptions).forEach(([name, { required, example }]) => {
      fullUsage += ` \\
  --${name} ${example}`;
    });

    content += `## Usage

Minimal usage

\`\`\`js
${minimalUsage}
\`\`\`

Pass all options as CLI flags to avoid user prompts

\`\`\`js
${fullUsage}
\`\`\`


`;

    content += `## Options
      
| option | type | description |
| --- | --- | --- |
`;

    Object.entries(scriptOptions).forEach(
      ([name, { type, required, description, default: defaultValue }]) => {
        const CliOption = decamelize(name, {
          separator: "-",
        });
        let optionNames = `\`--${CliOption}\``;
        if (type === "boolean") {
          optionNames += ` or \`--no-${CliOption}\``;
        }

        content += `| ${optionNames} | ${type} | ${
          required ? `**Required.**` : ""
        } ${description}${
          defaultValue
            ? `. Defaults to ${
                type === "string" ? `"${defaultValue}"` : defaultValue
              }`
            : ""
        } |
`;
      }
    );

    content += `| \`--octoherd-token\`, \`-T\` | string | A personal access token ([create](https://github.com/settings/tokens/new?scopes=repo)). Script will create one if option is not set |\n`;
    content += `| \`--octoherd-repos\`, \`-R\` | array of strings | One or multiple space-separated repositories in the form of \`repo-owner/repo-name\`. \`repo-owner/*\` will find all repositories for one owner. \`*\` will find all repositories the user has access to. Will prompt for repositories if not set |\n`;
    content += `| \`--octoherd-bypass-confirms\` | boolean | Bypass prompts to confirm mutating requests |\n\n`;
  }

  // footer
  content += `## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md)

## About Octoherd

[@octoherd](https://github.com/octoherd/) is project to help you keep your GitHub repositories in line.
  
## License

[ISC](LICENSE.md)
`;

  await writePrettyFile(`README.md`, content);
}


<|start_filename|>lib/create-test-action.js<|end_filename|>
import createGitHubAction from "./create-github-action.js";

export default async function createTestAction() {
  await createGitHubAction("test.yml");
}


<|start_filename|>lib/create-branch-protection.js<|end_filename|>
export default async function createBranchProtection(octokit, { owner, repo }) {
  await octokit.request(
    "PUT /repos/{owner}/{repo}/branches/{branch}/protection",
    {
      owner,
      repo,
      branch: "main",
      enforce_admins: null,
      required_pull_request_reviews: {
        dismiss_stale_reviews: true,
      },
      required_status_checks: {
        strict: false,
        contexts: owner === "octoherd" ? ["WIP", "test"] : ["test"],
      },
      restrictions: null,
    }
  );
}
