2026-10-05 09:33:06 +02:00
2026-10-05 06:00:35 +02:00

RepoFoundry

RepoFoundry (src/create-project.sh) sets up a new project: a Gitea repository, optionally an empty GitHub repository with a push mirror from Gitea to GitHub, and (in a later phase) a local project with the SQA-QC-Framework.

Status: work in progress. The script can validate its configuration, check both hosts and create the repositories and the mirror. Creating the local project, and the full installation guide, come in a later phase (MIL-003). This file so far documents what is needed to run the host steps safely.

Quick start

cp config.env.example config.env     # service addresses, not secret
cp .env.example .env                 # credentials: keep private
chmod 600 .env                       # Linux and macOS

src/create-project.sh                # dry run: reads from the hosts, creates nothing
src/create-project.sh --apply        # creates the repositories and the mirror

Without --apply the script only reads from GitHub and Gitea (it checks the tokens, the owners, the name, the license and SSH) and prints a plan. With --apply it prints the plan again and asks a final question before it creates anything. Nothing is ever deleted by the script.

Choosing GitHub also applies the AGPL-3.0 license to the Gitea repository, so that repository is not empty. Without GitHub the Gitea repository is created empty and has no license.

Token permissions

Both tokens go in .env (never in config.env, never in a remote URL). The script sends them only in a request header, through a private temporary file, and never prints them.

GitHub token (GITHUB_PAT, only when you choose GitHub)

The same token has two jobs: it creates the repository, and it is the password Gitea uses to push the mirror. It therefore needs to create repositories for the chosen owner and to push to the new one.

Need Token Source
Create a private repository classic token with the repo scope GitHub REST documentation, "Create a repository"
Create a public repository only classic token with public_repo is enough same
Push from the Gitea mirror covered by repo
Check that you belong to the organization owner probably read:org Not confirmed: the GitHub documentation names no scope for this call. If the script says you do not belong to an organization that you do belong to, add read:org.
  • Organization owners: you must be an active member who is allowed to create repositories in the organization. Organizations that require SSO or approval of tokens need the token authorised first.
  • Fine-grained tokens: the GitHub documentation lists no fine-grained permission for creating a repository, and this has not been tested. Use a classic token until it has been.
  • GITHUB_USER: names the account the token belongs to. It is only a default for the owner prompt; the repository may belong to an organization. If it differs from the account the token belongs to, the script warns and uses the account the token belongs to.

Gitea token (GITEA_TOKEN)

Need Scope Source
Read the account the token belongs to read:user Gitea documentation
Create repositories, manage the push mirror write:repository Gitea documentation
Look up an organization and your permissions in it read:organization Gitea documentation
Create a repository in an organization probably write:organization as well Not confirmed: expected from how the Gitea API groups organization calls; the end-to-end test in MIL-003 will confirm it.

A missing scope shows up as an HTTP 403 with the server's own message. The script stops before it creates anything when a preflight check is refused.

Known limitations

  • The mirror password is stored on the Gitea server. Gitea needs the GitHub token to push, so it keeps it. How it is protected depends on the Gitea version and its administrators. Use a token that is only meant for this, and revoke it if the Gitea server is ever in doubt.
  • sync_on_commit may be ignored. When a push mirror is created through the API, some Gitea versions ignore sync_on_commit (upstream issue go-gitea/gitea#22990). The script reads the mirror back and warns if the setting was not applied; the mirror then syncs on its interval (MIRROR_INTERVAL, default 10 minutes). The first sync is requested right after the mirror is created.
  • The server decides the shortest interval and whether push mirrors are allowed at all. A refused mirror stops the run with the server's message; the repositories created so far are kept.
  • The license commit. Gitea adds the license file when the repository is created with auto_init. The script sends no README, so the repository should hold only LICENSE; this is checked in the MIL-003 end-to-end test.
  • No rollback. If a step fails, the script reports what exists and how to continue. A repeated run offers to reuse a repository it created earlier (empty, or in Gitea's case holding only the license). Delete what you do not want in the web interface.
  • Mirror direction is Gitea to GitHub only. Push to Gitea; GitHub is a copy.
  • Requirements: bash 4.4 or later, git, curl and mktemp; jq and ssh are optional. Without jq the script reads the few JSON fields it needs with a simple built-in reader.

Code layout

src/create-project.sh is the entry point: the header, strict mode, loading and main. The work is split by responsibility into src/lib/, one job per file. The files are loaded from that directory only, by a fixed path.

File Responsibility
constants.sh constants and the shared state of a run
output.sh messages for the user and redaction of secrets
temp.sh private temporary files and their cleanup
util.sh small string and list helpers
validate.sh validators for names, URLs, tokens, ports, intervals
config.sh reading and checking config.env and .env (never sourced)
tools.sh checking the required tools
json.sh the little JSON the script reads and writes
http.sh the one place that runs curl; tokens stay off the command line
api.sh GitHub and Gitea API calls and reporting a refused call
prompts.sh interactive questions with validation
project.sh the project details: asking for them and showing them
hosts.sh names and links of the repositories on each host
preflight.sh read-only checks of both hosts
steps.sh the outcome of each step and the final report
plan.sh printing what the script is about to do
repositories.sh creating the GitHub and Gitea repositories
mirror.sh the Gitea to GitHub push mirror
apply.sh confirmations and the apply flow; the only code that changes anything
cli.sh usage text and option parsing

Each file names its responsibility and lists the functions it provides in its first lines. tests/test-structure.sh keeps it that way: every file in src/lib/ is loaded, no function is defined twice, and a file does nothing when it is loaded.

Development

bash tests/run-tests.sh           # shellcheck, shfmt and all tests, no network
S
Description
No description provided
Readme AGPL-3.0
271 KiB
Languages
Shell 100%