Skip to content

Instantly share code, notes, and snippets.

@taras
Last active July 7, 2022 20:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save taras/dbe58cf0d1c5f5feadaaee63d9a2a0d5 to your computer and use it in GitHub Desktop.
Save taras/dbe58cf0d1c5f5feadaaee63d9a2a0d5 to your computer and use it in GitHub Desktop.

Create a pull request to each repository in an organization with a catalog-info.yaml file

To run this script, download this script to a folder on your computer and run npx zx create-prs.md.

Requirements

You must install the following utilities to run this script.

GitHub CLI

Follow instructions on GitHub CLI. Once you installed, you must run gh auth login to authenticate your local environment.

git-xargs

Follow instructions on git-xargs. You have to make sure to configure GITHUB_OAUTH_TOKEN environment variable with a personal access token.

Node.js 16+

zx which runs this script requires Node.js 16+.

How do we verify dependencies?

Here is the code that verifies that all of the utilities are available for this script to run.

const { ok } = await import('assert')

ok(await which('gh'), 'gh utility is missing')
ok(await which('git-xargs'), 'git-xargs is missing')

const m = process.version.match(/(\d+)\.(\d+)\.(\d+)/);
const [major] = m.slice(1).map(_ => parseInt(_));

ok(major >= 16, `Node 16+ required, using ${process.version}`)

Arguments

You can pass name of the organization as the first argument. The script will prompt you otherwise.

For example: npx zx create-prs.md thefrontside

let {_: [org]} = argv;

if (!org) {
  org = await question('What GitHub organization do you want to create pull requests in?')
}

What does the script do?

Gets a list of repositories using GitHub CLI

let repoes = await $`gh repo list ${org} --limit=1000 --json=description,url,name,owner,nameWithOwner,languages`;

Creates a directory where we'll store generated files

await $`mkdir -p components`

Defines the template

You can modify the following template to customize how

function template(repo) {
  return {
    apiVersion: "backstage.io/v1alpha1",
    kind: 'Component',
    metadata: {
      name: slugify(repo.name),
      description: repo.description,
    },
    annotations: {
      "github.com/project-slug": repo.nameWithOwner,
    },
    tags: [...repo.languages.map(language => language.node.name)],
    spec: {
      type: "service",
      owner: repo.owner.login,
      lifecycle: "experimental"
    }
  }
}

Iterates over retrieved repositories and create a file for each repository

for (let repo of JSON.parse(repoes)) {
  let content = YAML.stringify(template(repo));

  await $`mkdir -p components/${repo.name}`;
  let file = $`cat > components/${repo.name}/app-config.yaml`
  file.stdin.write(content)
  file.stdin.end()
}

Utilities

These are the utilities used by the template.

/**
 * @source: https://gist.github.com/hagemann/382adfc57adbd5af078dc93feef01fe1
 **/
function slugify(string) {
  const a = 'àáâäæãåāăąçćčđďèéêëēėęěğǵḧîïíīįìıİłḿñńǹňôöòóœøōõőṕŕřßśšşșťțûüùúūǘůűųẃẍÿýžźż·/_,:;'
  const b = 'aaaaaaaaaacccddeeeeeeeegghiiiiiiiilmnnnnoooooooooprrsssssttuuuuuuuuuwxyyzzz------'
  const p = new RegExp(a.split('').join('|'), 'g')

  return string.toString().toLowerCase()
    .replace(/\s+/g, '-') // Replace spaces with -
    .replace(p, c => b.charAt(a.indexOf(c))) // Replace special characters
    .replace(/&/g, '-and-') // Replace & with 'and'
    .replace(/[^\w\-]+/g, '') // Remove all non-word characters
    .replace(/\-\-+/g, '-') // Replace multiple - with single -
    .replace(/^-+/, '') // Trim - from start of text
    .replace(/-+$/, '') // Trim - from end of text
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment