Dry run by default: the script reads from both hosts (tokens, owners,
names, license, SSH) and prints a plan; --apply creates the repositories
and the Gitea -> GitHub push mirror after a final yes. Choosing GitHub
applies the AGPL-3.0 license to the Gitea repository. A failed step is
reported with what exists and how to continue; nothing is ever deleted.
create-project.sh is now the entry point; the work lives in src/lib/, one
responsibility per file. .gitignore gets !src/lib (the Python template
ignores any lib/ folder). Tests grow to 599 checks, with a stub curl and
ssh, and guards for the file structure.
Task: MIL-002#1
Task: MIL-002#2
Task: MIL-002#3
Task: MIL-002#4
Task: MIL-002#5
Task: MIL-002#6
Refs #9
Refs #10
Refs #11
Refs #12
Refs #13
Refs #14
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
create-project.sh validates config.env and .env (parsed, never sourced),
checks the required tools, asks for the project details and prints a
summary. It makes no network call and no change on disk yet.
- config.env.example and .env.example hold placeholders only
- tokens go through a private curl config file, never the command line
- tests run in private directories with a stub curl; shellcheck and shfmt
are part of tests/run-tests.sh
Task: MIL-001#1
Task: MIL-001#2
Task: MIL-001#3
Task: MIL-001#4
Task: MIL-001#5
Task: MIL-001#6
Closes#3Closes#4Closes#5Closes#6Closes#7Closes#8
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>