Skip to main content

GitHub repository setup

install.sh can create your project's GitHub repository and apply a fixed set of general settings, labels and a default branch ruleset to it. This page is for developers who publish a Scaffold project on GitHub. Follow it to set up the repository during an install, or later on a project that already exists.

The GitHub step changes only git and the repository on GitHub. It runs after Initialization complete., so the project files are ready even when a request fails.

Before you begin​

  • Install GitHub CLI. install.sh calls gh for every GitHub request.

  • Create a GitHub token and export it as SCAFFOLD_GITHUB_TOKEN:

    export SCAFFOLD_GITHUB_TOKEN=github_pat_xxx

    Replace github_pat_xxx with your token. install.sh sends only this token. It ignores the account gh is logged in with and any GITHUB_TOKEN in your shell.

  • To create a repository, install git and set your git email with git config --global user.email "[email protected]", replacing [email protected] with your address.

A fine-grained token needs these repository permissions:

PermissionNeeded for
Metadata: readReading the repository (always granted)
Administration: writeGeneral settings, the ruleset and creating the repository
Issues: writeLabels
Checks: readReading the checks of a CI run
Actions: readWaiting for CI and matching each check to its workflow file
Contents: readReading workflow triggers
Contents: write and Workflows: writePushing a new repository

For settings only, you can limit a fine-grained token to the repositories it manages. Creating a repository needs All repositories access, because a token limited to selected repositories can't include one that doesn't exist yet. A classic token needs the repo and workflow scopes.

When gh or the token is missing, install.sh prints what's missing and the command to run later. An install carries on without the GitHub step and exits 0. The github command stops with exit code 1.

Configure the repository during an install​

The last prompt of an interactive install depends on the directory:

  • In a directory with a .git directory, such as a clone of a repository made with Use this template, the prompt is Configure GitHub repository settings.
  • In a directory without one, such as a run piped from curl, the prompt is Create a GitHub repository. When git or your git email is missing, the install prints why and asks Configure GitHub repository settings instead.

Both prompts appear only when gh and the token are available, and both default to n. After a y, the install asks for the owner, the repository and each section. It reads the repository from GitHub before the section prompts, so the Description prompt shows the current description. Press Enter to keep it.

Without prompts, pass --github:

curl -fsSL https://getscaffold.dev/install.sh | \
bash -s -- --namespace=AcmeApp --name=acme-app --author="Jane Doe" --github

Create the repository​

When the repository doesn't exist on GitHub, install.sh can create it and push the project. The following recording shows an install that creates the repository:

In an interactive run, answer y to Create a GitHub repository, or to the does not exist. Create it prompt that follows a repository GitHub doesn't know. Then pick the visibility. Without prompts, pass --github-create, which also turns on --github:

curl -fsSL https://getscaffold.dev/install.sh | \
bash -s -- --github-owner=acme-org --github-repo=acme-app --author="Jane Doe" --github-create

install.sh creates the repository in this order:

  1. Without a .git directory, it runs git init on a main branch.
  2. Without commits, it commits every file in 1 initial commit. Unless you pass --keep, install.sh itself stays out of that commit.
  3. It creates the repository with gh repo create, as public unless you pass --github-visibility=private.
  4. It adds an origin remote when there is none. An existing origin stays as it is.
  5. It pushes the current branch with the token, so your local git credentials don't matter.
  6. It applies the general settings, the labels and the ruleset.
  7. It waits for the first CI run and adds that run's checks to the ruleset. For details, see Required status checks.
  8. It removes install.sh, unless you passed --keep.

A repository with commits keeps them, and install.sh warns about uncommitted changes because it pushes only what's committed. To create the repository without pushing, pass --no-github-push.

install.sh removes itself only as the very last step. A run that fails or is interrupted keeps the script, so you can run ./install.sh github again.

Configure an existing project​

To configure the repository of a project that already exists, run the github command in the project's root directory:

curl -fsSL https://getscaffold.dev/install.sh | bash -s -- github

The github command leaves the project files untouched and needs no template. With no other options, it prompts for the owner, the repository and each section. Any option turns off the prompts and applies every section that isn't turned off:

curl -fsSL https://getscaffold.dev/install.sh | \
bash -s -- github --github-owner=acme --github-repo=acme-app --no-github-ruleset

The command ends with GitHub repository settings complete. Each section prints 1 line with what it changed.

How the owner and repository are found​

Each value comes from the first source that has it:

ValueSources, in order
Owner--github-owner, the origin remote, the login of the token
Repository--github-repo, the origin remote, the project name

The github command takes the current directory's name in place of the project name. install.sh reads origin only in the project's root directory and skips a remote that points at the Scaffold template.

When origin names a different repository than the options, install.sh stops with an error. It never rewrites the remote.

The owner and repository also set the defaults for --namespace and --name. An owner of acme-org gives the namespace AcmeOrg, and a repository of Acme_App gives the name acme-app. With those defaults, a non-interactive install needs only --author. An explicit --namespace or --name wins over the default. In an interactive install, the defaults appear on the Namespace and Project prompts.

A derived value that fails validation names its source:

Error: Name derived from --github-repo is invalid: 'acme.app'. Pass --name explicitly.

What gets applied​

Each section reads the repository first and changes only what differs, so you can run it again safely. Each section has its own option to turn it off.

General settings​

General settings go to GitHub in 1 request:

  • Squash and rebase merges on, merge commits off. To change the methods, pass --github-merge with a comma-separated list of merge, squash and rebase.
  • Squash commits take the pull request title and an empty message.
  • Auto-merge, the update branch button and deleting the branch after a merge on.
  • Issues on. Wiki, projects and discussions off.
  • The description from --github-description. Without a value, the description stays as it is.

Labels​

install.sh creates or updates these labels:

LabelColorDescription
AUTOMERGE#934BF4Pull request has been approved and set to automerge
BLOCKED#D93F0BIssue or pull request is blocked
CONFLICT#BC143EPull request has a conflict that needs to be resolved before it can be merged
Dependencies#62E795Pull request was raised automatically by a dependency bot
DO NOT MERGE#D93F0BDo not merge this pull request
Do not review#D93F0BDo not review this pull request
Needs review#5319E7Pull request needs a review from assigned developers
Ready for test#0E8A16Pull request is ready for manual testing
Ready to be merged#C2E0C6Pull request is ready to be merged (assigned after testing is complete)
Requires more work#B60205Pull request was reviewed and reviewer(s) asked to work further on the pull request
UPSTREAM#FBCA04Issue or pull request is related to an upstream project
URGENT#D93F0BPull request needs to be urgently reviewed

Names match without regard to case, as they do on GitHub. Other labels stay in place. To delete them, pass --github-labels-prune.

Default branch ruleset​

The default-branch ruleset protects the repository's default branch:

  • It blocks deleting the branch and force-pushing to it.
  • It requires the checks of the latest CI run, as the next section describes.
  • The admin repository role bypasses it, so the owner can still push directly.

install.sh finds the ruleset by name. It updates an existing default-branch ruleset and creates one when none exists. An update keeps every other rule and bypass actor on the ruleset. A ruleset of another name stays as it is, so rename an existing ruleset to default-branch to have install.sh manage it.

Rulesets on a private repository of a personal account need GitHub Pro. On a free plan, install.sh skips the ruleset and applies the other sections.

Required status checks​

install.sh reads the checks from the latest commit on the default branch. It keeps a check only when all 3 of these hold:

  • GitHub Actions reported it.
  • Its workflow file has a pull_request trigger. A check from a workflow that runs only on push never reports on a pull request, so requiring it would block every pull request.
  • Its conclusion isn't skipped, cancelled or neutral.

install.sh reads each workflow file through the GitHub API, so the check works from a curl run with no checkout. The checks it finds replace the ruleset's required checks. When it finds none, the ruleset keeps the checks it already had, and install.sh prints the command to run again after CI. On an existing repository, --no-github-required-checks leaves the required checks as they are.

A repository that install.sh created in the same run has no CI run yet. The ruleset goes on without checks, and install.sh then waits for the first CI run of the pushed commit:

  • When no run starts within about 60 seconds, it stops waiting and prints the command to run again later.
  • It waits up to 1800 seconds for every run to finish. To change the limit, pass --github-wait-timeout.
  • When every run has finished, it adds the checks to the ruleset. A failed run still adds its checks, with a warning that pull requests stay blocked until CI passes.
  • When the wait times out or you press Ctrl-C, the ruleset stays without checks and install.sh prints the command to run again.

To skip the wait, pass --no-github-wait-checks.

Preview the changes​

To print the requests and git commands install.sh would run without running them, add --dry-run:

curl -fsSL https://getscaffold.dev/install.sh | bash -s -- github --dry-run

A dry run still reads the repository to work out what would change, so it needs gh and the token too. A dry run for a new repository creates nothing and doesn't wait for CI.

When a request fails​

A 403 skips only its section and names the missing permission:

Ruleset: skipped (token lacks Administration: write)

The other sections still run, and a skipped section doesn't change the exit code. Any other failure also lets the other sections run, then makes install.sh exit with code 1. A failure to create or push the repository stops the GitHub step, because the sections need the repository.

Options​

These options control the GitHub step. Each one also works with the github command, apart from --github:

OptionDefaultDescription
--github, --no-githubOffConfigures the repository after an install.
--github-owner=VALUESee How the owner and repository are foundSets the GitHub user or organization.
--github-repo=VALUESee How the owner and repository are foundSets the repository name.
--github-create, --no-github-createOffCreates the repository when it doesn't exist, and turns on --github.
--github-visibility=VALUEpublicSets the visibility of a created repository: public or private.
--github-push, --no-github-pushOnPushes a created repository.
--github-settings, --no-github-settingsOnApplies the general settings.
--github-description=VALUEUnchangedSets the repository description.
--github-merge=VALUEsquash,rebaseSets the allowed merge methods: merge, squash and rebase.
--github-labels, --no-github-labelsOnApplies the labels.
--github-labels-prune, --no-github-labels-pruneOffDeletes labels that aren't in the list.
--github-ruleset, --no-github-rulesetOnApplies the default branch ruleset.
--github-required-checks, --no-github-required-checksOnRequires the checks of the latest CI run on an existing repository.
--github-wait-checks, --no-github-wait-checksOnWaits for the first CI run of a created repository and requires its checks.
--github-wait-timeout=SECONDS1800Sets how long to wait for CI.
--dry-runOffPrints the requests and git commands without running them.

Every interactive install also prints the non-interactive command that repeats your answers, before the Proceed with project init prompt. The command leaves out the token.