Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b66eff809 | ||
|
|
d773fa91df |
+2
-5
@@ -1,9 +1,6 @@
|
|||||||
# RepoFoundry credentials. Placeholders only: never put a real value in this
|
# RepoFoundry credentials. Placeholders only: never put a real value in this
|
||||||
# file or commit one.
|
# file or commit one.
|
||||||
#
|
#
|
||||||
# Everything in this file is optional: a credential that is missing here is
|
|
||||||
# asked for when the script runs (the token is not echoed).
|
|
||||||
#
|
|
||||||
# Copy this file to .env, fill in the values and keep it private
|
# Copy this file to .env, fill in the values and keep it private
|
||||||
# (chmod 600 .env on Linux and macOS). .env is ignored by git. The file is
|
# (chmod 600 .env on Linux and macOS). .env is ignored by git. The file is
|
||||||
# read as plain KEY=VALUE lines and never executed. Values may be wrapped in
|
# read as plain KEY=VALUE lines and never executed. Values may be wrapped in
|
||||||
@@ -16,7 +13,7 @@
|
|||||||
GITHUB_PAT=
|
GITHUB_PAT=
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
# Secrets for framework
|
# Secrets for workframe
|
||||||
########################################
|
########################################
|
||||||
|
|
||||||
# GitHub account the token belongs to. It identifies who authenticates; it is
|
# GitHub account the token belongs to. It identifies who authenticates; it is
|
||||||
@@ -24,6 +21,6 @@ GITHUB_PAT=
|
|||||||
# belong to an organization.
|
# belong to an organization.
|
||||||
GITHUB_USER=
|
GITHUB_USER=
|
||||||
|
|
||||||
# Gitea access token. It needs permission to create repositories
|
# Gitea access token (required). It needs permission to create repositories
|
||||||
# for the chosen owner and to manage the repository's push mirror.
|
# for the chosen owner and to manage the repository's push mirror.
|
||||||
GITEA_TOKEN=
|
GITEA_TOKEN=
|
||||||
|
|||||||
@@ -129,40 +129,14 @@ src/create-project.sh --apply # asks only "Create these now (y/n) [n]"
|
|||||||
|
|
||||||
| Key | Meaning |
|
| Key | Meaning |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `GITEA_TOKEN` | Gitea access token |
|
| `GITEA_TOKEN` | Gitea access token (required) |
|
||||||
| `GITHUB_PAT` | GitHub personal access token (only when you choose GitHub) |
|
| `GITHUB_PAT` | GitHub personal access token (only when you choose GitHub) |
|
||||||
| `GITHUB_USER` | the GitHub account the token belongs to (only when you choose GitHub) |
|
| `GITHUB_USER` | the GitHub account the token belongs to; only a default for the owner prompt |
|
||||||
|
|
||||||
`.env` is ignored by git. The script warns if it is readable by other users or
|
`.env` is ignored by git. The script warns if it is readable by other users or
|
||||||
not ignored by git. See [Token permissions](#token-permissions) for what each
|
not ignored by git. See [Token permissions](#token-permissions) for what each
|
||||||
token needs.
|
token needs.
|
||||||
|
|
||||||
`.env` is optional, and so is each key in it. A credential that is not
|
|
||||||
provided (the file is missing, the key is absent or its value is empty) is
|
|
||||||
asked for: the Gitea token at the start, the GitHub token and account name once
|
|
||||||
you choose GitHub. A token is read without echo and checked like one read from
|
|
||||||
`.env`; a refused value is asked again and never shown. If input ends before a
|
|
||||||
valid value is entered, the run stops before any request to a host.
|
|
||||||
|
|
||||||
### The project's own `.env`
|
|
||||||
|
|
||||||
When the project exists, the script asks whether to create a `.env` in it
|
|
||||||
(default no). On a yes the file holds only the credentials the project needs:
|
|
||||||
`GITEA_TOKEN`, and `GITHUB_PAT` and `GITHUB_USER` when you chose GitHub, as read
|
|
||||||
from your `.env` or typed.
|
|
||||||
|
|
||||||
- The file is created readable by you only (mode 600), never readable by
|
|
||||||
others even for a moment, and is never written by anything else.
|
|
||||||
- Git ignores it: the script adds `.env` to `.git/info/exclude` of the new
|
|
||||||
project. No tracked file changes and nothing is committed.
|
|
||||||
- An existing `.env` in the project is never replaced without a second yes, and
|
|
||||||
a `.env` that git already tracks is never written.
|
|
||||||
- The summary names the keys, never the values.
|
|
||||||
|
|
||||||
This is the one place the script writes a token to disk. It is plain text: keep
|
|
||||||
the project directory private, do not copy the file around, and say no if you
|
|
||||||
do not need it. Tokens are written nowhere else.
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -290,9 +264,7 @@ script stops before it creates anything when a preflight check is refused.
|
|||||||
## Security decisions
|
## Security decisions
|
||||||
|
|
||||||
- **Tokens never appear** in output, logs, remote URLs, `.git/config`,
|
- **Tokens never appear** in output, logs, remote URLs, `.git/config`,
|
||||||
`.gitmodules`, command lines or leftover files, and are written to disk only
|
`.gitmodules`, command lines or leftover files. They go to `curl` through a
|
||||||
in the new project's own `.env`, after a yes (see
|
|
||||||
[The project's own `.env`](#the-projects-own-env)). They go to `curl` through a
|
|
||||||
private configuration file that is removed right after the request, and to
|
private configuration file that is removed right after the request, and to
|
||||||
`git` (HTTPS fetch only) through a `GIT_ASKPASS` helper and the environment
|
`git` (HTTPS fetch only) through a `GIT_ASKPASS` helper and the environment
|
||||||
of that one command. Output is filtered, so even a server message that echoes
|
of that one command. Output is filtered, so even a server message that echoes
|
||||||
@@ -396,13 +368,11 @@ file. The files are loaded from that directory only, by a fixed path.
|
|||||||
| `json.sh` | the little JSON the script reads and writes |
|
| `json.sh` | the little JSON the script reads and writes |
|
||||||
| `http.sh` | the one place that runs `curl`; tokens stay off the command line |
|
| `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 |
|
| `api.sh` | GitHub and Gitea API calls and reporting a refused call |
|
||||||
| `prompts.sh` | interactive questions with validation (secrets are read without echo) |
|
| `prompts.sh` | interactive questions with validation |
|
||||||
| `credentials.sh` | asking for a credential that `.env` does not provide |
|
|
||||||
| `project.sh` | the project details: asking for them and showing them |
|
| `project.sh` | the project details: asking for them and showing them |
|
||||||
| `hosts.sh` | names, links and remote addresses of the repositories |
|
| `hosts.sh` | names, links and remote addresses of the repositories |
|
||||||
| `preflight.sh` | read-only checks of both hosts |
|
| `preflight.sh` | read-only checks of both hosts |
|
||||||
| `steps.sh` | the outcome of each step and the final report |
|
| `steps.sh` | the outcome of each step and the final report |
|
||||||
| `envfile.sh` | the new project's own `.env`: created private, ignored by git, never replaced without a yes |
|
|
||||||
| `plan.sh` | printing what the script is about to do |
|
| `plan.sh` | printing what the script is about to do |
|
||||||
| `repositories.sh` | creating the GitHub and Gitea repositories |
|
| `repositories.sh` | creating the GitHub and Gitea repositories |
|
||||||
| `mirror.sh` | the Gitea to GitHub push mirror |
|
| `mirror.sh` | the Gitea to GitHub push mirror |
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ document of a type. `Primary File` may contain a glob (e.g.
|
|||||||
| BC | Business Case | docs/business-case.md | 002 |
|
| BC | Business Case | docs/business-case.md | 002 |
|
||||||
| SA | Stakeholder Analysis | docs/stakeholder-analysis.md | 002 |
|
| SA | Stakeholder Analysis | docs/stakeholder-analysis.md | 002 |
|
||||||
| PP | Project Plan | docs/project-plan.md | 002 |
|
| PP | Project Plan | docs/project-plan.md | 002 |
|
||||||
| MIL | Milestone / Gateway | docs/milestones/*.md | 006 |
|
| MIL | Milestone / Gateway | docs/milestones/*.md | 007 |
|
||||||
| US | User Story | docs/user-stories.md | 002 |
|
| US | User Story | docs/user-stories.md | 002 |
|
||||||
| UC | Use Case | docs/uc-*/uc.md | 002 |
|
| UC | Use Case | docs/uc-*/uc.md | 002 |
|
||||||
| SSD | System Sequence Diagram | docs/uc-*/ssd.md | 002 |
|
| SSD | System Sequence Diagram | docs/uc-*/ssd.md | 002 |
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-05 | Deprecated | Jens Tirsvad Nielsen | S02 | Added objective 8 (project details preset in config.env), the matching scope item and success criterion 8 | [2a6bb8e] |
|
|
||||||
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Added objective 9 (credentials asked, project .env created), scope items, success criterion 9 and a risk<br>Objective 6 and success criterion 1 now allow a token only in the new project's .env | [ded26a6] |
|
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Added objective 9 (credentials asked, project .env created), scope items, success criterion 9 and a risk<br>Objective 6 and success criterion 1 now allow a token only in the new project's .env | [ded26a6] |
|
||||||
|
| 2026-10-06 | Proposed | Jens Tirsvad Nielsen | S02 | Added objective 10 (PROJECT_LICENSE in config.env), a scope item and success criterion 10; objective 2 now names the configured license | [d773fa9] |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ One repeatable, reviewed procedure gives every new project the same secure basel
|
|||||||
## Objectives
|
## Objectives
|
||||||
|
|
||||||
1. Optionally create an empty GitHub repository under a chosen user or organization.
|
1. Optionally create an empty GitHub repository under a chosen user or organization.
|
||||||
2. Create a Gitea repository under a chosen user or organization, empty, or with the AGPL license when GitHub is chosen.
|
2. Create a Gitea repository under a chosen user or organization, empty, or with a license: the one set in `config.env` (`PROJECT_LICENSE`), or AGPL-3.0 when GitHub is chosen and none is set.
|
||||||
3. When GitHub was chosen, configure the Gitea repository as a push mirror to GitHub (direction Gitea to GitHub).
|
3. When GitHub was chosen, configure the Gitea repository as a push mirror to GitHub (direction Gitea to GitHub).
|
||||||
4. Create the local project directory with an `origin` (Gitea) remote and, when GitHub was chosen, a `github` remote, neither containing credentials.
|
4. Create the local project directory with an `origin` (Gitea) remote and, when GitHub was chosen, a `github` remote, neither containing credentials.
|
||||||
5. Add the SQA-QC-Framework as the `framework` submodule, install its skills and git hooks, and copy its templates, optionally enabling the plan gate.
|
5. Add the SQA-QC-Framework as the `framework` submodule, install its skills and git hooks, and copy its templates, optionally enabling the plan gate.
|
||||||
@@ -43,6 +43,7 @@ One repeatable, reviewed procedure gives every new project the same secure basel
|
|||||||
7. Document installation, configuration, usage, security decisions and error handling in clear English for GitHub readers.
|
7. Document installation, configuration, usage, security decisions and error handling in clear English for GitHub readers.
|
||||||
8. Let the Maintainer preset the project details in `config.env`, so that a detail that is set there is not asked again.
|
8. Let the Maintainer preset the project details in `config.env`, so that a detail that is set there is not asked again.
|
||||||
9. Ask for a credential that is not provided in `.env` (`GITEA_TOKEN`, `GITHUB_PAT`, `GITHUB_USER`) and, when the Maintainer agrees, create a `.env` file with the credentials the new project needs.
|
9. Ask for a credential that is not provided in `.env` (`GITEA_TOKEN`, `GITHUB_PAT`, `GITHUB_USER`) and, when the Maintainer agrees, create a `.env` file with the credentials the new project needs.
|
||||||
|
10. Let the Maintainer set the project's license in `config.env` (`PROJECT_LICENSE`), independent of the GitHub choice, or set `none` for no license.
|
||||||
|
|
||||||
## Scope
|
## Scope
|
||||||
|
|
||||||
@@ -54,6 +55,7 @@ One repeatable, reviewed procedure gives every new project the same secure basel
|
|||||||
- Checks for required tools (`git`, `curl`, optional `jq`) before any change.
|
- Checks for required tools (`git`, `curl`, optional `jq`) before any change.
|
||||||
- A check that the project name is not already taken on GitHub.
|
- A check that the project name is not already taken on GitHub.
|
||||||
- Asking for a credential that `.env` does not provide, and creating the new project's own `.env` (owner-only, ignored by git, never overwritten without a yes).
|
- Asking for a credential that `.env` does not provide, and creating the new project's own `.env` (owner-only, ignored by git, never overwritten without a yes).
|
||||||
|
- A project license set in `config.env` (`PROJECT_LICENSE`, optional, never asked), checked against the licenses the Gitea server offers.
|
||||||
- Partial-failure reporting with a documented way to continue.
|
- Partial-failure reporting with a documented way to continue.
|
||||||
- Documentation of the SSH prerequisite for the submodule (Gitea SSH on port `10022`).
|
- Documentation of the SSH prerequisite for the submodule (Gitea SSH on port `10022`).
|
||||||
|
|
||||||
@@ -95,6 +97,7 @@ Supports developing on self-hosted Gitea while publishing to GitHub, and adoptin
|
|||||||
| 7 | Documentation | `README.md` covers installation, configuration, usage, security decisions, error handling and stakeholders | Review by S02 against MIL-003 Go/No-Go criterion 6 |
|
| 7 | Documentation | `README.md` covers installation, configuration, usage, security decisions, error handling and stakeholders | Review by S02 against MIL-003 Go/No-Go criterion 6 |
|
||||||
| 8 | Preset details | A project detail set in `config.env` is never asked; an invalid one stops the run before any request and names the key | Tests with each key set, absent, empty and invalid |
|
| 8 | Preset details | A project detail set in `config.env` is never asked; an invalid one stops the run before any request and names the key | Tests with each key set, absent, empty and invalid |
|
||||||
| 9 | Credentials asked and kept | A credential missing from `.env` is asked (not echoed) instead of stopping the run; the new project's `.env` is created only after a yes, owner-only, ignored by git, holding only the keys the project needs, and an existing `.env` is never replaced without a yes | Tests: each credential present and missing, `.env` written, declined, existing, file mode, git exclusion, no token in output |
|
| 9 | Credentials asked and kept | A credential missing from `.env` is asked (not echoed) instead of stopping the run; the new project's `.env` is created only after a yes, owner-only, ignored by git, holding only the keys the project needs, and an existing `.env` is never replaced without a yes | Tests: each credential present and missing, `.env` written, declined, existing, file mode, git exclusion, no token in output |
|
||||||
|
| 10 | Project license | `PROJECT_LICENSE` set: that license is on the Gitea repository with and without GitHub; `none`: no license; absent: AGPL-3.0 only when GitHub is chosen; a license the server does not offer stops the run before anything is created | Tests with a license set, `none`, absent and not offered |
|
||||||
|
|
||||||
## Risks
|
## Risks
|
||||||
|
|
||||||
@@ -146,5 +149,5 @@ Proceed — the procedure is small, well bounded and removes a repeated, securit
|
|||||||
|
|
||||||
[SA-001]: ./stakeholder-analysis.md
|
[SA-001]: ./stakeholder-analysis.md
|
||||||
[UCD-001]: ./use-case-diagram.md
|
[UCD-001]: ./use-case-diagram.md
|
||||||
[2a6bb8e]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/2a6bb8e8afadfe6ca4a621da30e44a372898ca62
|
|
||||||
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
||||||
|
[d773fa9]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/d773fa91df5a54090254e12e074880fb6526a9ff
|
||||||
|
|||||||
+6
-5
@@ -9,8 +9,8 @@
|
|||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-06 | Deprecated | Jens Tirsvad Nielsen | S02 | Initial version, from DCD-001 (UC-001) | [f4d611b] |
|
|
||||||
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Added CredentialCollector, EnvFileWriter and EnvFile (from DCD-001) | [ded26a6] |
|
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Added CredentialCollector, EnvFileWriter and EnvFile (from DCD-001) | [ded26a6] |
|
||||||
|
| 2026-10-06 | Proposed | Jens Tirsvad Nielsen | S02 | ProjectRequest carries the license that applies (from DCD-001) | [d773fa9] |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -111,6 +111,7 @@ class ProjectRequest {
|
|||||||
-visibility : Visibility
|
-visibility : Visibility
|
||||||
-directory : Path
|
-directory : Path
|
||||||
-enablePlanGate : Boolean
|
-enablePlanGate : Boolean
|
||||||
|
-license : String [0..1]
|
||||||
}
|
}
|
||||||
class Owner {
|
class Owner {
|
||||||
-name : String
|
-name : String
|
||||||
@@ -247,13 +248,13 @@ Repository "0..*" --> "1" Visibility
|
|||||||
| `Credential` | Access Token | Holds a secret in memory only; it never becomes part of an address or a message. | `kind`, `value` | none |
|
| `Credential` | Access Token | Holds a secret in memory only; it never becomes part of an address or a message. | `kind`, `value` | none |
|
||||||
| `ToolCheck` | none (system concept) | Records which tools are present. | `hasGit`, `hasCurl`, `hasJq` | none |
|
| `ToolCheck` | none (system concept) | Records which tools are present. | `hasGit`, `hasCurl`, `hasJq` | none |
|
||||||
| `PromptSet` | none (system concept) | The questions still to ask; a detail preset in `config.env` is not in it. | `prompts` | none |
|
| `PromptSet` | none (system concept) | The questions still to ask; a detail preset in `config.env` is not in it. | `prompts` | none |
|
||||||
| `ProjectRequest` | Project | Holds the details of the project being created. | `name`, `description`, `visibility`, `directory`, `enablePlanGate` | none |
|
| `ProjectRequest` | Project | Holds the details of the project being created. | `name`, `description`, `visibility`, `directory`, `enablePlanGate`, `license` | none |
|
||||||
| `Owner` | Owner | A user or organization on a host. | `name`, `kind` | none |
|
| `Owner` | Owner | A user or organization on a host. | `name`, `kind` | none |
|
||||||
| `PreflightResult` | none (system concept) | Records the outcome of the preflight checks. | `tokensWork`, `ownersAccept`, `nameIsFree`, `licenseIsOffered`, `sshPassed` | none |
|
| `PreflightResult` | none (system concept) | Records the outcome of the preflight checks. | `tokensWork`, `ownersAccept`, `nameIsFree`, `licenseIsOffered`, `sshPassed` | none |
|
||||||
| `Repository` | Repository | Common data of a repository on a host. | `name`, `description`, `visibility`, `address` | none |
|
| `Repository` | Repository | Common data of a repository on a host. | `name`, `description`, `visibility`, `address` | none |
|
||||||
| `GiteaRepository` | Gitea Repository | The source of truth. | none beyond `Repository` | none |
|
| `GiteaRepository` | Gitea Repository | The source of truth. | none beyond `Repository` | none |
|
||||||
| `GitHubRepository` | GitHub Repository | Receives its content from the mirror. | none beyond `Repository` | none |
|
| `GitHubRepository` | GitHub Repository | Receives its content from the mirror. | none beyond `Repository` | none |
|
||||||
| `LicenseFile` | License | The `AGPL-3.0` file in the Gitea repository when GitHub is chosen. | `key` | none |
|
| `LicenseFile` | License | The license file in the Gitea repository when a license applies. | `key` | none |
|
||||||
| `PushMirror` | Mirror | The Gitea to GitHub push mirror. | `interval`, `syncOnCommit` | none |
|
| `PushMirror` | Mirror | The Gitea to GitHub push mirror. | `interval`, `syncOnCommit` | none |
|
||||||
| `LocalProject` | Local Project | The project directory on the Maintainer's machine. | `directory` | none |
|
| `LocalProject` | Local Project | The project directory on the Maintainer's machine. | `directory` | none |
|
||||||
| `Remote` | Remote | A named link to a repository (`origin`, `github`), without a credential. | `name`, `address` | none |
|
| `Remote` | Remote | A named link to a repository (`origin`, `github`), without a credential. | `name`, `address` | none |
|
||||||
@@ -280,7 +281,7 @@ Repository "0..*" --> "1" Visibility
|
|||||||
| `GitHost.verifyToken() : Boolean` | [SD-001] `verifyToken()` from `Preflight` to either client; P2 |
|
| `GitHost.verifyToken() : Boolean` | [SD-001] `verifyToken()` from `Preflight` to either client; P2 |
|
||||||
| `GitHost.ownerAccepts(owner) : Boolean` | [SD-001] `ownerAccepts(giteaOwner)` and `ownerAccepts(githubOwner)`; P2 |
|
| `GitHost.ownerAccepts(owner) : Boolean` | [SD-001] `ownerAccepts(giteaOwner)` and `ownerAccepts(githubOwner)`; P2 |
|
||||||
| `GitHost.nameFree(name) : Boolean` | [SD-001] `nameFree(name)` to either client; P2 |
|
| `GitHost.nameFree(name) : Boolean` | [SD-001] `nameFree(name)` to either client; P2 |
|
||||||
| `GiteaClient.hasLicense(key) : Boolean` | [SD-001] `hasLicense(AGPL-3.0)`; P2 |
|
| `GiteaClient.hasLicense(key) : Boolean` | [SD-001] `hasLicense(license)`; P2 |
|
||||||
| `GiteaClient.createRepository(request, license) : GiteaRepository` | [SD-001] `createRepository(request, license)`; P3, P4 |
|
| `GiteaClient.createRepository(request, license) : GiteaRepository` | [SD-001] `createRepository(request, license)`; P3, P4 |
|
||||||
| `GiteaClient.addPushMirror(source, target) : PushMirror` | [SD-001] `addPushMirror(giteaRepository, gitHubRepository)`; P6 |
|
| `GiteaClient.addPushMirror(source, target) : PushMirror` | [SD-001] `addPushMirror(giteaRepository, gitHubRepository)`; P6 |
|
||||||
| `GiteaClient.requestSync(mirror) : void` | [SD-001] `requestSync(pushMirror)`; P6 |
|
| `GiteaClient.requestSync(mirror) : void` | [SD-001] `requestSync(pushMirror)`; P6 |
|
||||||
@@ -333,5 +334,5 @@ SOLID check: no class has more than one reason to change (one host API, one kind
|
|||||||
[SD-001]: ./uc-001/sd.md
|
[SD-001]: ./uc-001/sd.md
|
||||||
[MIL-005]: ./milestones/mil-005-credentials.md
|
[MIL-005]: ./milestones/mil-005-credentials.md
|
||||||
[DICT-001]: ./dictionary.md
|
[DICT-001]: ./dictionary.md
|
||||||
[f4d611b]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/f4d611b77cc70b4686506d44bf8f439045d9e0d2
|
|
||||||
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
||||||
|
[d773fa9]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/d773fa91df5a54090254e12e074880fb6526a9ff
|
||||||
|
|||||||
+3
-3
@@ -9,8 +9,8 @@
|
|||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-06 | Deprecated | Jens Tirsvad Nielsen | S02 | The IT terms are also used in DCD-001 and DCD-002<br>InstallResult and Visibility named as design-only types | [f4d611b] |
|
|
||||||
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Added Credentials File / EnvFile | [ded26a6] |
|
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Added Credentials File / EnvFile | [ded26a6] |
|
||||||
|
| 2026-10-06 | Proposed | Jens Tirsvad Nielsen | S02 | LicenseFile definition no longer tied to GitHub | [d773fa9] |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ Maps each Product Owner (PO) term to its professional IT term. PO language: Engl
|
|||||||
| Repository | en | Repository | A place on a Git Host that holds a project's history. | DM, UC | OC, SD, DCD |
|
| Repository | en | Repository | A place on a Git Host that holds a project's history. | DM, UC | OC, SD, DCD |
|
||||||
| Gitea Repository | en | GiteaRepository | The repository on Gitea; the source of truth. | DM, UC | OC, SD, DCD |
|
| Gitea Repository | en | GiteaRepository | The repository on Gitea; the source of truth. | DM, UC | OC, SD, DCD |
|
||||||
| GitHub Repository | en | GitHubRepository | The repository on GitHub; it receives its content from the mirror. | DM, UC | OC, SD, DCD |
|
| GitHub Repository | en | GitHubRepository | The repository on GitHub; it receives its content from the mirror. | DM, UC | OC, SD, DCD |
|
||||||
| License | en | LicenseFile | The legal terms file (AGPL-3.0) added to the Gitea repository when GitHub is chosen. | DM, UC | OC, SD, DCD |
|
| License | en | LicenseFile | The legal terms file added to the Gitea repository when a license applies. | DM, UC | OC, SD, DCD |
|
||||||
| Mirror | en | PushMirror | The push mirror that copies a Gitea repository to a GitHub repository. | DM, UC | OC, SD, DCD |
|
| Mirror | en | PushMirror | The push mirror that copies a Gitea repository to a GitHub repository. | DM, UC | OC, SD, DCD |
|
||||||
| Local Project | en | LocalProject | The project directory on the Maintainer's machine. | DM, UC | OC, SD, DCD |
|
| Local Project | en | LocalProject | The project directory on the Maintainer's machine. | DM, UC | OC, SD, DCD |
|
||||||
| Remote | en | Remote | A named link from a local project to a repository. | DM, UC | OC, SD, DCD |
|
| Remote | en | Remote | A named link from a local project to a repository. | DM, UC | OC, SD, DCD |
|
||||||
@@ -63,5 +63,5 @@ Maps each Product Owner (PO) term to its professional IT term. PO language: Engl
|
|||||||
[DM-002]: ./domain-model.md
|
[DM-002]: ./domain-model.md
|
||||||
[OC-001]: ./uc-001/oc.md
|
[OC-001]: ./uc-001/oc.md
|
||||||
[DCD-001]: ./uc-001/dcd.md
|
[DCD-001]: ./uc-001/dcd.md
|
||||||
[f4d611b]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/f4d611b77cc70b4686506d44bf8f439045d9e0d2
|
|
||||||
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
||||||
|
[d773fa9]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/d773fa91df5a54090254e12e074880fb6526a9ff
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-05 | Deprecated | Jens Tirsvad Nielsen | S02 | Configuration may hold preset project details (from DM-001, UC-001 step 3) | [2a6bb8e] |
|
|
||||||
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Added Credentials File (from DM-001, UC-001 step 9) | [ded26a6] |
|
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Added Credentials File (from DM-001, UC-001 step 9) | [ded26a6] |
|
||||||
|
| 2026-10-06 | Proposed | Jens Tirsvad Nielsen | S02 | License applies when configured, not only when GitHub is chosen (from DM-001) | [d773fa9] |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ Summary "1" --> "1" Project : reports on
|
|||||||
| Repository | A place on a Git Host that holds a project's history | name, description, visibility, address | [UC-001] steps 5 and 6 "repository" |
|
| Repository | A place on a Git Host that holds a project's history | name, description, visibility, address | [UC-001] steps 5 and 6 "repository" |
|
||||||
| Gitea Repository | The Repository on Gitea; the source of truth | none beyond Repository | [UC-001] step 6 |
|
| Gitea Repository | The Repository on Gitea; the source of truth | none beyond Repository | [UC-001] step 6 |
|
||||||
| GitHub Repository | The Repository on GitHub; receives its content from the Mirror | none beyond Repository | [UC-001] step 5 |
|
| GitHub Repository | The Repository on GitHub; receives its content from the Mirror | none beyond Repository | [UC-001] step 5 |
|
||||||
| License | The legal terms file added to a Gitea Repository (AGPL-3.0) when GitHub is chosen | name | [UC-001] step 6 "AGPL license" |
|
| License | The legal terms file added to a Gitea Repository when a license applies: the one set in the Configuration, or AGPL-3.0 when GitHub is chosen and none is set | name | [UC-001] step 6 "license" |
|
||||||
| Mirror | The push mirror that copies a Gitea Repository to a GitHub Repository | interval, sync on commit | [UC-001] step 7 "push mirror" |
|
| Mirror | The push mirror that copies a Gitea Repository to a GitHub Repository | interval, sync on commit | [UC-001] step 7 "push mirror" |
|
||||||
| Local Project | The project directory on the Maintainer's machine | directory | [UC-001] step 8 "local project" |
|
| Local Project | The project directory on the Maintainer's machine | directory | [UC-001] step 8 "local project" |
|
||||||
| Remote | A named link from a Local Project to a Repository (`origin`, `github`) | name, address | [UC-001] step 8 "remote" |
|
| Remote | A named link from a Local Project to a Repository (`origin`, `github`) | name, address | [UC-001] step 8 "remote" |
|
||||||
@@ -152,7 +152,7 @@ Summary "1" --> "1" Project : reports on
|
|||||||
| Owner | owns | Repository | 1 to 0..* |
|
| Owner | owns | Repository | 1 to 0..* |
|
||||||
| Project | is stored in | Gitea Repository | 1 to 1 |
|
| Project | is stored in | Gitea Repository | 1 to 1 |
|
||||||
| Project | is also stored in | GitHub Repository | 1 to 0..1 |
|
| Project | is also stored in | GitHub Repository | 1 to 0..1 |
|
||||||
| Gitea Repository | has | License | 1 to 0..1 (1 when GitHub is chosen) |
|
| Gitea Repository | has | License | 1 to 0..1 (1 when a license applies) |
|
||||||
| Mirror | copies from | Gitea Repository | 1 to 1 |
|
| Mirror | copies from | Gitea Repository | 1 to 1 |
|
||||||
| Mirror | copies to | GitHub Repository | 1 to 1 |
|
| Mirror | copies to | GitHub Repository | 1 to 1 |
|
||||||
| Mirror | is authorised by | Access Token | 0..* to 1 |
|
| Mirror | is authorised by | Access Token | 0..* to 1 |
|
||||||
@@ -180,5 +180,5 @@ Summary "1" --> "1" Project : reports on
|
|||||||
[SSD-001]: ./uc-001/ssd.md
|
[SSD-001]: ./uc-001/ssd.md
|
||||||
[DICT-001]: ./dictionary.md
|
[DICT-001]: ./dictionary.md
|
||||||
[DM-001]: ./uc-001/dm.md
|
[DM-001]: ./uc-001/dm.md
|
||||||
[2a6bb8e]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/2a6bb8e8afadfe6ca4a621da30e44a372898ca62
|
|
||||||
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
||||||
|
[d773fa9]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/d773fa91df5a54090254e12e074880fb6526a9ff
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
# MIL-006 Project License
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
| Key | Value |
|
||||||
|
| --- | --- |
|
||||||
|
| ID | MIL-006 |
|
||||||
|
| CrossReference | [BC-001], [US-001], [UC-001], [DCD-001] |
|
||||||
|
|
||||||
|
## Version History
|
||||||
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| 2026-10-06 | Proposed | Jens Tirsvad Nielsen | S02 | Initial version | [d773fa9] |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Decide whether the project's license can be set in `config.env` without weakening the existing behaviour: a license that is set applies with or without GitHub, `none` means no license, an absent key keeps today's rule (AGPL-3.0 only when GitHub is chosen), and a license the Gitea server does not offer stops the run before anything is created.
|
||||||
|
|
||||||
|
## Deliverable
|
||||||
|
|
||||||
|
`create-project.sh` that reads one more optional key from `config.env`, `PROJECT_LICENSE`, checks it, resolves the license that applies, checks that Gitea offers it, creates the Gitea repository with it and shows it in the plan and summary. `config.env.example` and the README document the key. The tests cover every case.
|
||||||
|
|
||||||
|
The key (present counts as set, as for the other project details of [MIL-004]; an empty value is refused):
|
||||||
|
|
||||||
|
| Key | Detail | Accepted value |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `PROJECT_LICENSE` | the license of the project | a Gitea license key (letters, digits, `.`, `+`, `-`, at most 64 characters), such as `AGPL-3.0` or `MIT`, or `none` |
|
||||||
|
|
||||||
|
The license that applies is resolved in this order: `PROJECT_LICENSE` when set (`none` means no license), otherwise AGPL-3.0 when GitHub is chosen, otherwise none. It is never asked: the key is an optional project detail in `config.env`, not a prompt.
|
||||||
|
|
||||||
|
## Go / No-Go Criteria
|
||||||
|
|
||||||
|
| # | Criterion (objectively checkable) | Go | No-Go |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 1 | With `PROJECT_LICENSE` set to a license the server offers, the Gitea repository is created with that license, with GitHub and without it, and the plan and summary show it as coming from `config.env` | Tests pass | Another license, none, or no marker |
|
||||||
|
| 2 | `PROJECT_LICENSE=none`: the Gitea repository has no license, also when GitHub is chosen | Tests pass | Any license applied |
|
||||||
|
| 3 | `PROJECT_LICENSE` absent: AGPL-3.0 when GitHub is chosen and none otherwise, exactly as before; the existing tests pass unchanged | Tests pass | Any change of behaviour |
|
||||||
|
| 4 | An empty or invalid value stops the run before any request to a host, names the key and never falls back to asking | Tests pass | A request made or a prompt shown |
|
||||||
|
| 5 | A license the Gitea server does not offer stops the run before anything is created and names the license | Tests pass | Anything created |
|
||||||
|
| 6 | The license is never asked, with the key set, absent or invalid | Tests pass | Any prompt for it |
|
||||||
|
| 7 | The mirror, the local history and the other steps are unchanged: with GitHub chosen the license file reaches the local project through the Gitea history, as before | Tests pass | Any other step changed |
|
||||||
|
| 8 | All acceptance criteria of US-001.06 in [US-001] are met | Verified | Any unmet |
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
| Depends on | Reason |
|
||||||
|
| --- | --- |
|
||||||
|
| [MIL-004] | The key is one more project detail read, validated and marked by the code of the configurable details |
|
||||||
|
|
||||||
|
## Traceability
|
||||||
|
|
||||||
|
| Business Case objective / KPI / user story | Reference |
|
||||||
|
| --- | --- |
|
||||||
|
| User story US-001.06 | [US-001] |
|
||||||
|
| Objective 10 (project license in `config.env`) and the amended objective 2 | [BC-001] |
|
||||||
|
| Success criterion 10 | [BC-001] |
|
||||||
|
|
||||||
|
## Ownership
|
||||||
|
|
||||||
|
| Role | Stakeholder ID (SA) |
|
||||||
|
| --- | --- |
|
||||||
|
| Owner | S01 |
|
||||||
|
| Approving reviewer | S02 |
|
||||||
|
|
||||||
|
## Target Date
|
||||||
|
|
||||||
|
2026-12-04 — proposed; the Business Case sets no deadline.
|
||||||
|
|
||||||
|
## Tasks
|
||||||
|
|
||||||
|
| # | Task | Summary | Needs its own Use Case/User Story? | Reference |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| 1 | Read and validate `PROJECT_LICENSE` | Add the key to the `config.env` parser and its validator (a license key or `none`; empty refused; errors name the key). Resolve the license that applies into the project request (key set, else AGPL-3.0 with GitHub, else none) and mark it `(from config.env)` in the summary. Never asked. Extensions of step 3 of [UC-001]. | Yes | [UC-001] |
|
||||||
|
| 2 | Apply the license on Gitea, independent of GitHub | Generalize the preflight check from the fixed AGPL-3.0 to the license that applies (checked only when one applies); create the repository with it; the plan, the summary and the reuse warning name the license that applies instead of AGPL-3.0; GitHub receives the file through the mirror as before. Extension 4c and step 6 of [UC-001]. | Yes | [UC-001] |
|
||||||
|
| 3 | Document the key | Commented example in `config.env.example`, a row in the README table of project details, and the rule for the license that applies, including `none` and the default. | No | |
|
||||||
|
| 4 | Test every case | Key set (with and without GitHub), `none`, absent, empty, invalid and not offered by the server; never asked; the summary marker; the existing tests unchanged. | No | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[BC-001]: ../business-case.md
|
||||||
|
[US-001]: ../user-stories.md
|
||||||
|
[UC-001]: ../uc-001/uc.md
|
||||||
|
[DCD-001]: ../uc-001/dcd.md
|
||||||
|
[MIL-004]: ./mil-004-configurable-details.md
|
||||||
|
[d773fa9]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/d773fa91df5a54090254e12e074880fb6526a9ff
|
||||||
+11
-6
@@ -4,23 +4,23 @@
|
|||||||
| Key | Value |
|
| Key | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| ID | PP-001 |
|
| ID | PP-001 |
|
||||||
| CrossReference | [BC-001], [SA-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [US-001] |
|
| CrossReference | [BC-001], [SA-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006], [US-001] |
|
||||||
|
|
||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-05 | Deprecated | Jens Tirsvad Nielsen | S02 | Added phase MIL-004 (proposed dates 2026-11-16 to 2026-11-20) | [2a6bb8e] |
|
|
||||||
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Added phase MIL-005 (proposed dates 2026-11-23 to 2026-11-27) | [ded26a6] |
|
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Added phase MIL-005 (proposed dates 2026-11-23 to 2026-11-27) | [ded26a6] |
|
||||||
|
| 2026-10-06 | Proposed | Jens Tirsvad Nielsen | S02 | Added phase MIL-006 (proposed dates 2026-11-30 to 2026-12-04) | [d773fa9] |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
Schedule the five phases that deliver RepoFoundry (`create-project.sh` and its documentation) in dependency order. The Business Case sets no deadline, so the dates below are proposals for S01 to confirm.
|
Schedule the six phases that deliver RepoFoundry (`create-project.sh` and its documentation) in dependency order. The Business Case sets no deadline, so the dates below are proposals for S01 to confirm.
|
||||||
|
|
||||||
## Planning Assumptions
|
## Planning Assumptions
|
||||||
|
|
||||||
- Week 1 starts 2026-10-05; the plan ends by 2026-11-27 (the last phase is proposed).
|
- Week 1 starts 2026-10-05; the plan ends by 2026-12-04 (the last phase is proposed).
|
||||||
- Phase length: two weeks.
|
- Phase length: two weeks.
|
||||||
- S01 and S02 review each phase through a pull request, as described in [SA-001]. For now one person holds both roles.
|
- S01 and S02 review each phase through a pull request, as described in [SA-001]. For now one person holds both roles.
|
||||||
- The PO language is English, so no translated copies are kept.
|
- The PO language is English, so no translated copies are kept.
|
||||||
@@ -34,6 +34,7 @@ Schedule the five phases that deliver RepoFoundry (`create-project.sh` and its d
|
|||||||
| Scaffold and Release | [MIL-003] | 2026-11-02 to 2026-11-13 | 2026-11-13 | S01 | US-001.03 | Local project, framework, README, final review | [Milestone 45] |
|
| Scaffold and Release | [MIL-003] | 2026-11-02 to 2026-11-13 | 2026-11-13 | S01 | US-001.03 | Local project, framework, README, final review | [Milestone 45] |
|
||||||
| Configurable Details | [MIL-004] | 2026-11-16 to 2026-11-20 | 2026-11-20 | S01 | US-001.04 | Project details preset in config.env | |
|
| Configurable Details | [MIL-004] | 2026-11-16 to 2026-11-20 | 2026-11-20 | S01 | US-001.04 | Project details preset in config.env | |
|
||||||
| Credentials | [MIL-005] | 2026-11-23 to 2026-11-27 | 2026-11-27 | S01 | US-001.05 | Missing credentials asked; project .env | |
|
| Credentials | [MIL-005] | 2026-11-23 to 2026-11-27 | 2026-11-27 | S01 | US-001.05 | Missing credentials asked; project .env | |
|
||||||
|
| Project License | [MIL-006] | 2026-11-30 to 2026-12-04 | 2026-12-04 | S01 | US-001.06 | PROJECT_LICENSE in config.env | |
|
||||||
|
|
||||||
```plantuml
|
```plantuml
|
||||||
@startgantt
|
@startgantt
|
||||||
@@ -48,6 +49,8 @@ Project starts 2026-10-05
|
|||||||
[Configurable Details Go/No-Go] happens 2026-11-20
|
[Configurable Details Go/No-Go] happens 2026-11-20
|
||||||
[Credentials] starts 2026-11-23 and ends 2026-11-27
|
[Credentials] starts 2026-11-23 and ends 2026-11-27
|
||||||
[Credentials Go/No-Go] happens 2026-11-27
|
[Credentials Go/No-Go] happens 2026-11-27
|
||||||
|
[Project License] starts 2026-11-30 and ends 2026-12-04
|
||||||
|
[Project License Go/No-Go] happens 2026-12-04
|
||||||
@endgantt
|
@endgantt
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -63,11 +66,12 @@ Project starts 2026-10-05
|
|||||||
| README and SSH prerequisite documentation | [MIL-003] |
|
| README and SSH prerequisite documentation | [MIL-003] |
|
||||||
| Project details set in `config.env` instead of asked | [MIL-004] |
|
| Project details set in `config.env` instead of asked | [MIL-004] |
|
||||||
| Missing credentials asked; the new project's `.env` | [MIL-005] |
|
| Missing credentials asked; the new project's `.env` | [MIL-005] |
|
||||||
|
| Project license set in `config.env` | [MIL-006] |
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
```
|
```
|
||||||
MIL-001 → MIL-002 → MIL-003 → MIL-004 → MIL-005
|
MIL-001 → MIL-002 → MIL-003 → MIL-004 → MIL-005 → MIL-006
|
||||||
```
|
```
|
||||||
|
|
||||||
A No-Go moves every later date by the time needed to rework the failed criteria.
|
A No-Go moves every later date by the time needed to rework the failed criteria.
|
||||||
@@ -96,11 +100,12 @@ A No-Go moves every later date by the time needed to rework the failed criteria.
|
|||||||
[MIL-003]: ./milestones/mil-003-scaffold-and-release.md
|
[MIL-003]: ./milestones/mil-003-scaffold-and-release.md
|
||||||
[MIL-004]: ./milestones/mil-004-configurable-details.md
|
[MIL-004]: ./milestones/mil-004-configurable-details.md
|
||||||
[MIL-005]: ./milestones/mil-005-credentials.md
|
[MIL-005]: ./milestones/mil-005-credentials.md
|
||||||
|
[MIL-006]: ./milestones/mil-006-project-license.md
|
||||||
[US-001]: ./user-stories.md
|
[US-001]: ./user-stories.md
|
||||||
[UC-001]: ./uc-001/uc.md
|
[UC-001]: ./uc-001/uc.md
|
||||||
[SSD-001]: ./uc-001/ssd.md
|
[SSD-001]: ./uc-001/ssd.md
|
||||||
[Milestone 43]: https://git.tirsystem.com/TirSystem-BashScript/RepoFoundry/milestone/43
|
[Milestone 43]: https://git.tirsystem.com/TirSystem-BashScript/RepoFoundry/milestone/43
|
||||||
[Milestone 44]: https://git.tirsystem.com/TirSystem-BashScript/RepoFoundry/milestone/44
|
[Milestone 44]: https://git.tirsystem.com/TirSystem-BashScript/RepoFoundry/milestone/44
|
||||||
[Milestone 45]: https://git.tirsystem.com/TirSystem-BashScript/RepoFoundry/milestone/45
|
[Milestone 45]: https://git.tirsystem.com/TirSystem-BashScript/RepoFoundry/milestone/45
|
||||||
[2a6bb8e]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/2a6bb8e8afadfe6ca4a621da30e44a372898ca62
|
|
||||||
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
||||||
|
[d773fa9]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/d773fa91df5a54090254e12e074880fb6526a9ff
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-06 | Proposed | Jens Tirsvad Nielsen | S02 | Added DCD-001 and DCD-002 | [f4d611b] |
|
|
||||||
| 2026-10-06 | Proposed | Jens Tirsvad Nielsen | S02 | Added MIL-005, RC-020 and RC-021 | [ded26a6] |
|
| 2026-10-06 | Proposed | Jens Tirsvad Nielsen | S02 | Added MIL-005, RC-020 and RC-021 | [ded26a6] |
|
||||||
|
| 2026-10-06 | Proposed | Jens Tirsvad Nielsen | S02 | Added MIL-006 | [d773fa9] |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -24,16 +24,17 @@ updated whenever an artifact instance is created or reviewed.
|
|||||||
|
|
||||||
| Artifact Instance | Type | Upstream (Backward Link) | Downstream (Forward Link) | Last Reviewed (RC-ID) |
|
| Artifact Instance | Type | Upstream (Backward Link) | Downstream (Forward Link) | Last Reviewed (RC-ID) |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| [BC-001] | BC | - | [SA-001], [PP-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [US-001], [UCD-001] | [RC-010], [RC-018], [RC-020] |
|
| [BC-001] | BC | - | [SA-001], [PP-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006], [US-001], [UCD-001] | [RC-010], [RC-018], [RC-020] |
|
||||||
| [SA-001] | SA | [BC-001] | [UCD-001], [UC-001], [DICT-001] | [RC-013] |
|
| [SA-001] | SA | [BC-001] | [UCD-001], [UC-001], [DICT-001] | [RC-013] |
|
||||||
| [PP-001] | PP | [BC-001], [SA-001] | [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005] | [RC-012], [RC-018], [RC-020] |
|
| [PP-001] | PP | [BC-001], [SA-001] | [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006] | [RC-012], [RC-018], [RC-020] |
|
||||||
| [MIL-001] | MIL | [BC-001], [PP-001] | [US-001] | [RC-011], [RC-016] |
|
| [MIL-001] | MIL | [BC-001], [PP-001] | [US-001] | [RC-011], [RC-016] |
|
||||||
| [MIL-002] | MIL | [BC-001], [PP-001] | [US-001] | [RC-014], [RC-017] |
|
| [MIL-002] | MIL | [BC-001], [PP-001] | [US-001] | [RC-014], [RC-017] |
|
||||||
| [MIL-003] | MIL | [BC-001], [PP-001] | [US-001] | [RC-015], [RC-017] |
|
| [MIL-003] | MIL | [BC-001], [PP-001] | [US-001] | [RC-015], [RC-017] |
|
||||||
| [MIL-004] | MIL | [BC-001], [PP-001] | [US-001] | [RC-018], [RC-019] |
|
| [MIL-004] | MIL | [BC-001], [PP-001] | [US-001] | [RC-018], [RC-019] |
|
||||||
| [MIL-005] | MIL | [BC-001], [PP-001] | [US-001] | [RC-020] |
|
| [MIL-005] | MIL | [BC-001], [PP-001] | [US-001] | [RC-020] |
|
||||||
|
| [MIL-006] | MIL | [BC-001], [PP-001] | [US-001] | - |
|
||||||
| [UCD-001] | UCD | [BC-001], [SA-001] | [US-001], [UC-001] | [RC-009] |
|
| [UCD-001] | UCD | [BC-001], [SA-001] | [US-001], [UC-001] | [RC-009] |
|
||||||
| [US-001] | US | [BC-001], [UCD-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005] | [UC-001] | [RC-001], [RC-020] |
|
| [US-001] | US | [BC-001], [UCD-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006] | [UC-001] | [RC-001], [RC-020] |
|
||||||
| [UC-001] | UC | [UCD-001], [US-001], [SA-001] | [SSD-001], [DM-001] | [RC-002], [RC-020] |
|
| [UC-001] | UC | [UCD-001], [US-001], [SA-001] | [SSD-001], [DM-001] | [RC-002], [RC-020] |
|
||||||
| [SSD-001] | SSD | [UC-001] | [OC-001] | [RC-003], [RC-020] |
|
| [SSD-001] | SSD | [UC-001] | [OC-001] | [RC-003], [RC-020] |
|
||||||
| [DM-001] | DM | [UC-001], [SSD-001] | [DM-002], [DICT-001], [OC-001], [DCD-001] | [RC-004], [RC-020] |
|
| [DM-001] | DM | [UC-001], [SSD-001] | [DM-002], [DICT-001], [OC-001], [DCD-001] | [RC-004], [RC-020] |
|
||||||
@@ -59,6 +60,7 @@ updated whenever an artifact instance is created or reviewed.
|
|||||||
[MIL-003]: ../milestones/mil-003-scaffold-and-release.md
|
[MIL-003]: ../milestones/mil-003-scaffold-and-release.md
|
||||||
[MIL-004]: ../milestones/mil-004-configurable-details.md
|
[MIL-004]: ../milestones/mil-004-configurable-details.md
|
||||||
[MIL-005]: ../milestones/mil-005-credentials.md
|
[MIL-005]: ../milestones/mil-005-credentials.md
|
||||||
|
[MIL-006]: ../milestones/mil-006-project-license.md
|
||||||
[RC-018]: ./reviews/rc-018-mil-004.md
|
[RC-018]: ./reviews/rc-018-mil-004.md
|
||||||
[RC-019]: ./reviews/rc-019-mil-004-code.md
|
[RC-019]: ./reviews/rc-019-mil-004-code.md
|
||||||
[RC-020]: ./reviews/rc-020-mil-005.md
|
[RC-020]: ./reviews/rc-020-mil-005.md
|
||||||
@@ -91,5 +93,5 @@ updated whenever an artifact instance is created or reviewed.
|
|||||||
[RC-015]: ./reviews/rc-015-mil-003.md
|
[RC-015]: ./reviews/rc-015-mil-003.md
|
||||||
[RC-016]: ./reviews/rc-016-create-project-sh.md
|
[RC-016]: ./reviews/rc-016-create-project-sh.md
|
||||||
[RC-017]: ./reviews/rc-017-e2e-security-review.md
|
[RC-017]: ./reviews/rc-017-e2e-security-review.md
|
||||||
[f4d611b]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/f4d611b77cc70b4686506d44bf8f439045d9e0d2
|
|
||||||
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
||||||
|
[d773fa9]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/d773fa91df5a54090254e12e074880fb6526a9ff
|
||||||
|
|||||||
+6
-5
@@ -9,8 +9,8 @@
|
|||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-06 | Deprecated | Jens Tirsvad Nielsen | S02 | Initial version | [f4d611b] |
|
|
||||||
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Added CredentialCollector, EnvFileWriter and EnvFile; writeEnvFile parameter | [ded26a6] |
|
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Added CredentialCollector, EnvFileWriter and EnvFile; writeEnvFile parameter | [ded26a6] |
|
||||||
|
| 2026-10-06 | Proposed | Jens Tirsvad Nielsen | S02 | ProjectRequest carries the license that applies | [d773fa9] |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -113,6 +113,7 @@ class ProjectRequest {
|
|||||||
-visibility : Visibility
|
-visibility : Visibility
|
||||||
-directory : Path
|
-directory : Path
|
||||||
-enablePlanGate : Boolean
|
-enablePlanGate : Boolean
|
||||||
|
-license : String [0..1]
|
||||||
}
|
}
|
||||||
class Owner {
|
class Owner {
|
||||||
-name : String
|
-name : String
|
||||||
@@ -249,13 +250,13 @@ Repository "0..*" --> "1" Visibility
|
|||||||
| `Credential` | Access Token | Holds a secret in memory only; it never becomes part of an address or a message. | `kind`, `value` | none |
|
| `Credential` | Access Token | Holds a secret in memory only; it never becomes part of an address or a message. | `kind`, `value` | none |
|
||||||
| `ToolCheck` | none (system concept) | Records which tools are present. | `hasGit`, `hasCurl`, `hasJq` | none |
|
| `ToolCheck` | none (system concept) | Records which tools are present. | `hasGit`, `hasCurl`, `hasJq` | none |
|
||||||
| `PromptSet` | none (system concept) | The questions still to ask; a detail preset in `config.env` is not in it. | `prompts` | none |
|
| `PromptSet` | none (system concept) | The questions still to ask; a detail preset in `config.env` is not in it. | `prompts` | none |
|
||||||
| `ProjectRequest` | Project | Holds the details of the project being created. | `name`, `description`, `visibility`, `directory`, `enablePlanGate` | none |
|
| `ProjectRequest` | Project | Holds the details of the project being created. | `name`, `description`, `visibility`, `directory`, `enablePlanGate`, `license` | none |
|
||||||
| `Owner` | Owner | A user or organization on a host. | `name`, `kind` | none |
|
| `Owner` | Owner | A user or organization on a host. | `name`, `kind` | none |
|
||||||
| `PreflightResult` | none (system concept) | Records the outcome of the preflight checks. | `tokensWork`, `ownersAccept`, `nameIsFree`, `licenseIsOffered`, `sshPassed` | none |
|
| `PreflightResult` | none (system concept) | Records the outcome of the preflight checks. | `tokensWork`, `ownersAccept`, `nameIsFree`, `licenseIsOffered`, `sshPassed` | none |
|
||||||
| `Repository` | Repository | Common data of a repository on a host. | `name`, `description`, `visibility`, `address` | none |
|
| `Repository` | Repository | Common data of a repository on a host. | `name`, `description`, `visibility`, `address` | none |
|
||||||
| `GiteaRepository` | Gitea Repository | The source of truth. | none beyond `Repository` | none |
|
| `GiteaRepository` | Gitea Repository | The source of truth. | none beyond `Repository` | none |
|
||||||
| `GitHubRepository` | GitHub Repository | Receives its content from the mirror. | none beyond `Repository` | none |
|
| `GitHubRepository` | GitHub Repository | Receives its content from the mirror. | none beyond `Repository` | none |
|
||||||
| `LicenseFile` | License | The `AGPL-3.0` file in the Gitea repository when GitHub is chosen. | `key` | none |
|
| `LicenseFile` | License | The license file in the Gitea repository when a license applies. | `key` | none |
|
||||||
| `PushMirror` | Mirror | The Gitea to GitHub push mirror. | `interval`, `syncOnCommit` | none |
|
| `PushMirror` | Mirror | The Gitea to GitHub push mirror. | `interval`, `syncOnCommit` | none |
|
||||||
| `LocalProject` | Local Project | The project directory on the Maintainer's machine. | `directory` | none |
|
| `LocalProject` | Local Project | The project directory on the Maintainer's machine. | `directory` | none |
|
||||||
| `Remote` | Remote | A named link to a repository (`origin`, `github`), without a credential. | `name`, `address` | none |
|
| `Remote` | Remote | A named link to a repository (`origin`, `github`), without a credential. | `name`, `address` | none |
|
||||||
@@ -282,7 +283,7 @@ Repository "0..*" --> "1" Visibility
|
|||||||
| `GitHost.verifyToken() : Boolean` | [SD-001] `verifyToken()` from `Preflight` to either client; P2 |
|
| `GitHost.verifyToken() : Boolean` | [SD-001] `verifyToken()` from `Preflight` to either client; P2 |
|
||||||
| `GitHost.ownerAccepts(owner) : Boolean` | [SD-001] `ownerAccepts(giteaOwner)` and `ownerAccepts(githubOwner)`; P2 |
|
| `GitHost.ownerAccepts(owner) : Boolean` | [SD-001] `ownerAccepts(giteaOwner)` and `ownerAccepts(githubOwner)`; P2 |
|
||||||
| `GitHost.nameFree(name) : Boolean` | [SD-001] `nameFree(name)` to either client; P2 |
|
| `GitHost.nameFree(name) : Boolean` | [SD-001] `nameFree(name)` to either client; P2 |
|
||||||
| `GiteaClient.hasLicense(key) : Boolean` | [SD-001] `hasLicense(AGPL-3.0)`; P2 |
|
| `GiteaClient.hasLicense(key) : Boolean` | [SD-001] `hasLicense(license)`; P2 |
|
||||||
| `GiteaClient.createRepository(request, license) : GiteaRepository` | [SD-001] `createRepository(request, license)`; P3, P4 |
|
| `GiteaClient.createRepository(request, license) : GiteaRepository` | [SD-001] `createRepository(request, license)`; P3, P4 |
|
||||||
| `GiteaClient.addPushMirror(source, target) : PushMirror` | [SD-001] `addPushMirror(giteaRepository, gitHubRepository)`; P6 |
|
| `GiteaClient.addPushMirror(source, target) : PushMirror` | [SD-001] `addPushMirror(giteaRepository, gitHubRepository)`; P6 |
|
||||||
| `GiteaClient.requestSync(mirror) : void` | [SD-001] `requestSync(pushMirror)`; P6 |
|
| `GiteaClient.requestSync(mirror) : void` | [SD-001] `requestSync(pushMirror)`; P6 |
|
||||||
@@ -336,5 +337,5 @@ SOLID check: no class has more than one reason to change (one host API, one kind
|
|||||||
[MIL-005]: ../milestones/mil-005-credentials.md
|
[MIL-005]: ../milestones/mil-005-credentials.md
|
||||||
[DICT-001]: ../dictionary.md
|
[DICT-001]: ../dictionary.md
|
||||||
[DCD-002]: ../dcd.md
|
[DCD-002]: ../dcd.md
|
||||||
[f4d611b]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/f4d611b77cc70b4686506d44bf8f439045d9e0d2
|
|
||||||
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
||||||
|
[d773fa9]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/d773fa91df5a54090254e12e074880fb6526a9ff
|
||||||
|
|||||||
+4
-4
@@ -9,8 +9,8 @@
|
|||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-05 | Deprecated | Jens Tirsvad Nielsen | S02 | Configuration may hold preset project details | [2a6bb8e] |
|
|
||||||
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Added Credentials File (a Local Project may have one) | [ded26a6] |
|
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Added Credentials File (a Local Project may have one) | [ded26a6] |
|
||||||
|
| 2026-10-06 | Proposed | Jens Tirsvad Nielsen | S02 | License applies when configured, not only when GitHub is chosen | [d773fa9] |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ Summary "1" --> "1" Project : reports on
|
|||||||
| Repository | A place on a Git Host that holds a project's history | name, description, visibility, address | [UC-001] steps 5 and 6 "repository" |
|
| Repository | A place on a Git Host that holds a project's history | name, description, visibility, address | [UC-001] steps 5 and 6 "repository" |
|
||||||
| Gitea Repository | The Repository on Gitea; the source of truth | none beyond Repository | [UC-001] step 6 |
|
| Gitea Repository | The Repository on Gitea; the source of truth | none beyond Repository | [UC-001] step 6 |
|
||||||
| GitHub Repository | The Repository on GitHub; receives its content from the Mirror | none beyond Repository | [UC-001] step 5 |
|
| GitHub Repository | The Repository on GitHub; receives its content from the Mirror | none beyond Repository | [UC-001] step 5 |
|
||||||
| License | The legal terms file added to a Gitea Repository (AGPL-3.0) when GitHub is chosen | name | [UC-001] step 6 "AGPL license" |
|
| License | The legal terms file added to a Gitea Repository when a license applies: the one set in the Configuration, or AGPL-3.0 when GitHub is chosen and none is set | name | [UC-001] step 6 "license" |
|
||||||
| Mirror | The push mirror that copies a Gitea Repository to a GitHub Repository | interval, sync on commit | [UC-001] step 7 "push mirror" |
|
| Mirror | The push mirror that copies a Gitea Repository to a GitHub Repository | interval, sync on commit | [UC-001] step 7 "push mirror" |
|
||||||
| Local Project | The project directory on the Maintainer's machine | directory | [UC-001] step 8 "local project" |
|
| Local Project | The project directory on the Maintainer's machine | directory | [UC-001] step 8 "local project" |
|
||||||
| Remote | A named link from a Local Project to a Repository (`origin`, `github`) | name, address | [UC-001] step 8 "remote" |
|
| Remote | A named link from a Local Project to a Repository (`origin`, `github`) | name, address | [UC-001] step 8 "remote" |
|
||||||
@@ -152,7 +152,7 @@ Summary "1" --> "1" Project : reports on
|
|||||||
| Owner | owns | Repository | 1 to 0..* |
|
| Owner | owns | Repository | 1 to 0..* |
|
||||||
| Project | is stored in | Gitea Repository | 1 to 1 |
|
| Project | is stored in | Gitea Repository | 1 to 1 |
|
||||||
| Project | is also stored in | GitHub Repository | 1 to 0..1 |
|
| Project | is also stored in | GitHub Repository | 1 to 0..1 |
|
||||||
| Gitea Repository | has | License | 1 to 0..1 (1 when GitHub is chosen) |
|
| Gitea Repository | has | License | 1 to 0..1 (1 when a license applies) |
|
||||||
| Mirror | copies from | Gitea Repository | 1 to 1 |
|
| Mirror | copies from | Gitea Repository | 1 to 1 |
|
||||||
| Mirror | copies to | GitHub Repository | 1 to 1 |
|
| Mirror | copies to | GitHub Repository | 1 to 1 |
|
||||||
| Mirror | is authorised by | Access Token | 0..* to 1 |
|
| Mirror | is authorised by | Access Token | 0..* to 1 |
|
||||||
@@ -180,5 +180,5 @@ Summary "1" --> "1" Project : reports on
|
|||||||
[SSD-001]: ./ssd.md
|
[SSD-001]: ./ssd.md
|
||||||
[DICT-001]: ../dictionary.md
|
[DICT-001]: ../dictionary.md
|
||||||
[DM-002]: ../domain-model.md
|
[DM-002]: ../domain-model.md
|
||||||
[2a6bb8e]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/2a6bb8e8afadfe6ca4a621da30e44a372898ca62
|
|
||||||
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
||||||
|
[d773fa9]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/d773fa91df5a54090254e12e074880fb6526a9ff
|
||||||
|
|||||||
+6
-5
@@ -9,8 +9,8 @@
|
|||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-05 | Deprecated | Jens Tirsvad Nielsen | S02 | Project details may be defined by the Configuration | [2a6bb8e] |
|
|
||||||
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Credentials asked when missing; EnvFile created in the local project (P14); writeEnvFile parameter | [ded26a6] |
|
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Credentials asked when missing; EnvFile created in the local project (P14); writeEnvFile parameter | [ded26a6] |
|
||||||
|
| 2026-10-06 | Proposed | Jens Tirsvad Nielsen | S02 | P2, P4 and an exception: the license that applies, not always AGPL-3.0 | [d773fa9] |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -55,15 +55,16 @@ Concepts below use the IT terms of [DICT-001] for the PO concepts of [DM-001]. `
|
|||||||
|
|
||||||
- A `Run` exists and its `Configuration` is valid (from `startProjectCreation`).
|
- A `Run` exists and its `Configuration` is valid (from `startProjectCreation`).
|
||||||
- `githubOwner` is present exactly when the Maintainer chose GitHub.
|
- `githubOwner` is present exactly when the Maintainer chose GitHub.
|
||||||
|
- The license that applies is not asked: it comes from the `Configuration` (`PROJECT_LICENSE`) or follows the GitHub choice.
|
||||||
- When `githubOwner` is present, the GitHub `Credential`s are known: from `.env`, or entered by the Maintainer without echo and validated before the first request.
|
- When `githubOwner` is present, the GitHub `Credential`s are known: from `.env`, or entered by the Maintainer without echo and validated before the first request.
|
||||||
- A detail that the `Configuration` defines is not asked: it is taken from the `Configuration`.
|
- A detail that the `Configuration` defines is not asked: it is taken from the `Configuration`.
|
||||||
|
|
||||||
**Postconditions**
|
**Postconditions**
|
||||||
|
|
||||||
- P1. A `ProjectRequest` instance was created with the attributes given by the Maintainer or defined by the `Configuration`, and associated with the `Run`.
|
- P1. A `ProjectRequest` instance was created with the attributes given by the Maintainer or defined by the `Configuration`, and associated with the `Run`.
|
||||||
- P2. A `PreflightResult` instance was created and associated with the `ProjectRequest`, recording that each token needed for the chosen hosts works, that each owner accepts new repositories, that the name is free on the chosen hosts, that `AGPL-3.0` is offered by Gitea when GitHub was chosen, and the outcome of the SSH test to Gitea on port 10022.
|
- P2. A `PreflightResult` instance was created and associated with the `ProjectRequest`, recording that each token needed for the chosen hosts works, that each owner accepts new repositories, that the name is free on the chosen hosts, that the license that applies is offered by Gitea (when a license applies), and the outcome of the SSH test to Gitea on port 10022.
|
||||||
- P3. A `GiteaRepository` instance was created under `giteaOwner` with the given name, description and visibility, and associated with the `ProjectRequest`.
|
- P3. A `GiteaRepository` instance was created under `giteaOwner` with the given name, description and visibility, and associated with the `ProjectRequest`.
|
||||||
- P4. If `githubOwner` is present, a `LicenseFile` instance for `AGPL-3.0` was created and associated with the `GiteaRepository`, so that repository is not empty. Otherwise the `GiteaRepository` has no `LicenseFile` and is empty.
|
- P4. If a license applies, a `LicenseFile` instance for it was created and associated with the `GiteaRepository`, so that repository is not empty. The license that applies is the one the `Configuration` defines (`PROJECT_LICENSE`; `none` means none), otherwise `AGPL-3.0` if `githubOwner` is present, otherwise none. If no license applies the `GiteaRepository` has no `LicenseFile` and is empty.
|
||||||
- P5. If `githubOwner` is present, an empty `GitHubRepository` instance was created under `githubOwner` and associated with the `ProjectRequest`.
|
- P5. If `githubOwner` is present, an empty `GitHubRepository` instance was created under `githubOwner` and associated with the `ProjectRequest`.
|
||||||
- P6. If `githubOwner` is present, a `PushMirror` instance was created, associated with the `GiteaRepository` as source and the `GitHubRepository` as target, with its effective sync setting recorded, and a first sync was requested.
|
- P6. If `githubOwner` is present, a `PushMirror` instance was created, associated with the `GiteaRepository` as source and the `GitHubRepository` as target, with its effective sync setting recorded, and a first sync was requested.
|
||||||
- P7. A `LocalProject` instance was created at `directory`, associated with the `ProjectRequest`. If the `GiteaRepository` is not empty, the `LocalProject` holds its history, including the `LicenseFile` commit.
|
- P7. A `LocalProject` instance was created at `directory`, associated with the `ProjectRequest`. If the `GiteaRepository` is not empty, the `LocalProject` holds its history, including the `LicenseFile` commit.
|
||||||
@@ -80,7 +81,7 @@ Concepts below use the IT terms of [DICT-001] for the PO concepts of [DM-001]. `
|
|||||||
| Condition (failing precondition) | Outcome |
|
| Condition (failing precondition) | Outcome |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| A token is invalid, an owner refuses new repositories, or the name is taken on a chosen host (P2) | The `Run` ends before P3; nothing was created; the error names the failed check |
|
| A token is invalid, an owner refuses new repositories, or the name is taken on a chosen host (P2) | The `Run` ends before P3; nothing was created; the error names the failed check |
|
||||||
| GitHub was chosen and Gitea does not offer `AGPL-3.0` (P2) | The `Run` ends before P3; nothing was created |
|
| A license applies and Gitea does not offer it (P2) | The `Run` ends before P3; nothing was created; the error names the license |
|
||||||
| `GiteaRepository` creation fails after a `GitHubRepository` was created (P5, P3 ordering) | The `Summary` lists the `GitHubRepository` as created, the `GiteaRepository` as failed and how to continue |
|
| `GiteaRepository` creation fails after a `GitHubRepository` was created (P5, P3 ordering) | The `Summary` lists the `GitHubRepository` as created, the `GiteaRepository` as failed and how to continue |
|
||||||
| `PushMirror` creation fails (P6) | The `Summary` lists both repositories as created, the mirror as failed and how to continue; the local steps are not run |
|
| `PushMirror` creation fails (P6) | The `Summary` lists both repositories as created, the mirror as failed and how to continue; the local steps are not run |
|
||||||
| `directory` exists, or a target file exists, and the Maintainer declines replacing it (P7, P12) | That item is skipped and listed in the `Summary` |
|
| `directory` exists, or a target file exists, and the Maintainer declines replacing it (P7, P12) | That item is skipped and listed in the `Summary` |
|
||||||
@@ -94,5 +95,5 @@ Concepts below use the IT terms of [DICT-001] for the PO concepts of [DM-001]. `
|
|||||||
[DM-001]: ./dm.md
|
[DM-001]: ./dm.md
|
||||||
[DICT-001]: ../dictionary.md
|
[DICT-001]: ../dictionary.md
|
||||||
[SD-001]: ./sd.md
|
[SD-001]: ./sd.md
|
||||||
[2a6bb8e]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/2a6bb8e8afadfe6ca4a621da30e44a372898ca62
|
|
||||||
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
||||||
|
[d773fa9]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/d773fa91df5a54090254e12e074880fb6526a9ff
|
||||||
|
|||||||
+9
-10
@@ -9,8 +9,8 @@
|
|||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-06 | Deprecated | Jens Tirsvad Nielsen | S02 | Messages aligned with the method signatures of DCD-001<br>Cited DCD-001 | [f4d611b] |
|
|
||||||
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Added CredentialCollector and EnvFileWriter and their messages (P2, P14) | [ded26a6] |
|
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Added CredentialCollector and EnvFileWriter and their messages (P2, P14) | [ded26a6] |
|
||||||
|
| 2026-10-06 | Proposed | Jens Tirsvad Nielsen | S02 | The license that applies is passed to hasLicense and createRepository; no alt on the GitHub choice | [d773fa9] |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -113,7 +113,10 @@ end
|
|||||||
create PF
|
create PF
|
||||||
PC -> PF : check(request)
|
PC -> PF : check(request)
|
||||||
activate PF
|
activate PF
|
||||||
PF -> GT : verifyToken(), ownerAccepts(giteaOwner), nameFree(name), hasLicense(AGPL-3.0)
|
PF -> GT : verifyToken(), ownerAccepts(giteaOwner), nameFree(name)
|
||||||
|
opt a license applies
|
||||||
|
PF -> GT : hasLicense(license)
|
||||||
|
end
|
||||||
opt githubOwner present
|
opt githubOwner present
|
||||||
PF -> GH : verifyToken(), ownerAccepts(githubOwner), nameFree(name)
|
PF -> GH : verifyToken(), ownerAccepts(githubOwner), nameFree(name)
|
||||||
end
|
end
|
||||||
@@ -127,11 +130,7 @@ opt githubOwner present
|
|||||||
deactivate GH
|
deactivate GH
|
||||||
end
|
end
|
||||||
|
|
||||||
alt githubOwner present
|
PC -> GT : createRepository(request, license)
|
||||||
PC -> GT : createRepository(request, license=AGPL-3.0)
|
|
||||||
else no GitHub
|
|
||||||
PC -> GT : createRepository(request, license=none)
|
|
||||||
end
|
|
||||||
activate GT
|
activate GT
|
||||||
GT --> PC : giteaRepository
|
GT --> PC : giteaRepository
|
||||||
deactivate GT
|
deactivate GT
|
||||||
@@ -194,9 +193,9 @@ destroy SR
|
|||||||
| Postcondition (from contract) | Satisfied by message |
|
| Postcondition (from contract) | Satisfied by message |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| P1 ProjectRequest created | `provideProjectDetails` received by `ProjectCreator` |
|
| P1 ProjectRequest created | `provideProjectDetails` received by `ProjectCreator` |
|
||||||
| P2 PreflightResult created | `check(request)` |
|
| P2 PreflightResult created, including that the license is offered | `check(request)` and `hasLicense(license)` |
|
||||||
| P3 GiteaRepository created | `createRepository(request, license)` |
|
| P3 GiteaRepository created | `createRepository(request, license)` |
|
||||||
| P4 LicenseFile when GitHub chosen, otherwise empty | `createRepository(..., license=AGPL-3.0)` and the `alt` branch `license=none` |
|
| P4 LicenseFile when a license applies, otherwise empty | `createRepository(request, license)`; `license` is the one the `ProjectRequest` carries (`PROJECT_LICENSE`, or AGPL-3.0 when GitHub was chosen), and is absent for `none` |
|
||||||
| P2 GitHub credentials known before the first request | `collect(configuration, GITHUB_PAT, GITHUB_USER)` inside `opt githubOwner present` |
|
| P2 GitHub credentials known before the first request | `collect(configuration, GITHUB_PAT, GITHUB_USER)` inside `opt githubOwner present` |
|
||||||
| P5 empty GitHubRepository when chosen | `createEmptyRepository(request)` |
|
| P5 empty GitHubRepository when chosen | `createEmptyRepository(request)` |
|
||||||
| P6 PushMirror and first sync | `addPushMirror(...)` and `requestSync(pushMirror)` |
|
| P6 PushMirror and first sync | `addPushMirror(...)` and `requestSync(pushMirror)` |
|
||||||
@@ -217,5 +216,5 @@ destroy SR
|
|||||||
|
|
||||||
[OC-001]: ./oc.md
|
[OC-001]: ./oc.md
|
||||||
[DCD-001]: ./dcd.md
|
[DCD-001]: ./dcd.md
|
||||||
[f4d611b]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/f4d611b77cc70b4686506d44bf8f439045d9e0d2
|
|
||||||
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
||||||
|
[d773fa9]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/d773fa91df5a54090254e12e074880fb6526a9ff
|
||||||
|
|||||||
+5
-3
@@ -9,8 +9,8 @@
|
|||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-05 | Deprecated | Jens Tirsvad Nielsen | S02 | Parameters may come from config.env; the message is unchanged | [2a6bb8e] |
|
|
||||||
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | writeEnvFile parameter and the credentials that .env does not provide | [ded26a6] |
|
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | writeEnvFile parameter and the credentials that .env does not provide | [ded26a6] |
|
||||||
|
| 2026-10-06 | Proposed | Jens Tirsvad Nielsen | S02 | The license is not a parameter: it comes from config.env or follows the GitHub choice | [d773fa9] |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -37,7 +37,9 @@ S --> A : creation summary
|
|||||||
| Step | Message | Parameters | Return | Use case step |
|
| Step | Message | Parameters | Return | Use case step |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| 1 | startProjectCreation | none | prompts for project details (after configuration and tool checks; a missing credential is asked first) | 1, 2 |
|
| 1 | startProjectCreation | none | prompts for project details (after configuration and tool checks; a missing credential is asked first) | 1, 2 |
|
||||||
| 2 | provideProjectDetails | name, description, visibility, giteaOwner, githubOwner (optional; given means GitHub is chosen and the Gitea repository gets the AGPL license; omitted means no GitHub and no license), directory, enablePlanGate (each of these may come from `config.env` instead of the Maintainer; the message is unchanged), writeEnvFile (whether to create the project's `.env`), and the credentials that `.env` does not provide (GitHub ones only when GitHub is chosen) | checks passed, then a creation summary | 3 to 10 |
|
| 2 | provideProjectDetails | name, description, visibility, giteaOwner, githubOwner (optional; given means GitHub is chosen; omitted means no GitHub), directory, enablePlanGate (each of these may come from `config.env` instead of the Maintainer; the message is unchanged), writeEnvFile (whether to create the project's `.env`), and the credentials that `.env` does not provide (GitHub ones only when GitHub is chosen) | checks passed, then a creation summary | 3 to 10 |
|
||||||
|
|
||||||
|
The license that applies is not a parameter: it is read from `config.env` (`PROJECT_LICENSE`) or, when none is set, follows the GitHub choice.
|
||||||
|
|
||||||
Steps 4 to 9 are internal to the system, so one operation covers them. A consent question (step 8a, 9a, 9b) is a prompt from the system and is out of scope for this diagram; failure flows are out of scope here.
|
Steps 4 to 9 are internal to the system, so one operation covers them. A consent question (step 8a, 9a, 9b) is a prompt from the system and is out of scope for this diagram; failure flows are out of scope here.
|
||||||
|
|
||||||
@@ -50,5 +52,5 @@ The system is one script run. It starts with the first operation and ends after
|
|||||||
[UC-001]: ./uc.md
|
[UC-001]: ./uc.md
|
||||||
[DM-001]: ./dm.md
|
[DM-001]: ./dm.md
|
||||||
[OC-001]: ./oc.md
|
[OC-001]: ./oc.md
|
||||||
[2a6bb8e]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/2a6bb8e8afadfe6ca4a621da30e44a372898ca62
|
|
||||||
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
||||||
|
[d773fa9]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/d773fa91df5a54090254e12e074880fb6526a9ff
|
||||||
|
|||||||
+9
-9
@@ -9,8 +9,8 @@
|
|||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-05 | Deprecated | Jens Tirsvad Nielsen | S02 | Step 3: details set in config.env are not asked (extensions 3a, 3b) | [2a6bb8e] |
|
|
||||||
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Credentials not in .env are asked (step 2, extension 2b); the project .env is created with consent (step 9, extensions 9c, 9d) | [ded26a6] |
|
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Credentials not in .env are asked (step 2, extension 2b); the project .env is created with consent (step 9, extensions 9c, 9d) | [ded26a6] |
|
||||||
|
| 2026-10-06 | Proposed | Jens Tirsvad Nielsen | S02 | The license comes from PROJECT_LICENSE (step 6, extension 4c); AGPL-3.0 is only the default when GitHub is chosen | [d773fa9] |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -27,12 +27,12 @@
|
|||||||
- S03 — the published procedure is documented and reusable
|
- S03 — the published procedure is documented and reusable
|
||||||
- **Preconditions:**
|
- **Preconditions:**
|
||||||
- `config.env` exists and is valid. `.env` may be missing or hold only some credentials; a credential it does not provide is asked.
|
- `config.env` exists and is valid. `.env` may be missing or hold only some credentials; a credential it does not provide is asked.
|
||||||
- `config.env` may preset any of the project details of step 3.
|
- `config.env` may preset any of the project details of step 3, and may set the project license (`PROJECT_LICENSE`).
|
||||||
- `git` and `curl` are installed.
|
- `git` and `curl` are installed.
|
||||||
- The Maintainer has a Gitea token, a GitHub PAT and a GitHub account name (only when GitHub is chosen) and SSH access to Gitea on port 10022.
|
- The Maintainer has a Gitea token, a GitHub PAT and a GitHub account name (only when GitHub is chosen) and SSH access to Gitea on port 10022.
|
||||||
- **Postconditions (success guarantee):**
|
- **Postconditions (success guarantee):**
|
||||||
- A repository exists on Gitea under the chosen owner. It is empty, or, when the Maintainer chose GitHub, it holds the AGPL license file.
|
- A repository exists on Gitea under the chosen owner. It is empty, or it holds the license file that applies: the license set in `config.env`, or AGPL-3.0 when the Maintainer chose GitHub and set none.
|
||||||
- When the Maintainer chose to create a GitHub repository, an empty repository exists on GitHub under the chosen owner, the Gitea repository is a push mirror to it, and the AGPL license file reaches GitHub through the mirror.
|
- When the Maintainer chose to create a GitHub repository, an empty repository exists on GitHub under the chosen owner, the Gitea repository is a push mirror to it, and the license file, if any, reaches GitHub through the mirror.
|
||||||
- A local project directory exists with credential-free remotes `origin` (Gitea) and, when GitHub was chosen, `github`, the `framework` submodule, installed skills and hooks, and the copied templates.
|
- A local project directory exists with credential-free remotes `origin` (Gitea) and, when GitHub was chosen, `github`, the `framework` submodule, installed skills and hooks, and the copied templates.
|
||||||
- When the Maintainer agreed, the local project has a `.env` that holds only the credentials the project needs, is readable by its owner only and is ignored by git.
|
- When the Maintainer agreed, the local project has a `.env` that holds only the credentials the project needs, is readable by its owner only and is ignored by git.
|
||||||
- The Maintainer has a summary of what was created.
|
- The Maintainer has a summary of what was created.
|
||||||
@@ -42,9 +42,9 @@
|
|||||||
1. The Maintainer starts the project creation.
|
1. The Maintainer starts the project creation.
|
||||||
2. The system loads and validates the configuration and credentials and checks that the required tools exist. A credential that `.env` does not provide is asked, without echo; the GitHub credentials are asked once GitHub is chosen.
|
2. The system loads and validates the configuration and credentials and checks that the required tools exist. A credential that `.env` does not provide is asked, without echo; the GitHub credentials are asked once GitHub is chosen.
|
||||||
3. The Maintainer provides the repository name, description, visibility, the Gitea owner, whether to also create a GitHub repository (and if so its owner), the local directory, and whether to enable the plan gate. A detail that is set in `config.env` is not asked.
|
3. The Maintainer provides the repository name, description, visibility, the Gitea owner, whether to also create a GitHub repository (and if so its owner), the local directory, and whether to enable the plan gate. A detail that is set in `config.env` is not asked.
|
||||||
4. The system checks that the tokens needed for the chosen hosts work, that the owners accept new repositories, that the name is free on those hosts, and whether SSH to Gitea works.
|
4. The system checks that the tokens needed for the chosen hosts work, that the owners accept new repositories, that the name is free on those hosts, that Gitea offers the license that applies (if any), and whether SSH to Gitea works.
|
||||||
5. Optional: if the Maintainer chose GitHub, the system creates the empty GitHub repository.
|
5. Optional: if the Maintainer chose GitHub, the system creates the empty GitHub repository.
|
||||||
6. The system creates the Gitea repository. If the Maintainer chose GitHub, the repository is created with the AGPL license file and so is not empty; otherwise it is empty and has no license.
|
6. The system creates the Gitea repository. If a license applies, the repository is created with its license file and so is not empty; otherwise it is empty. The license that applies is the one set in `config.env` (`PROJECT_LICENSE`; `none` means no license); when none is set it is AGPL-3.0 if the Maintainer chose GitHub, and none otherwise. The license is never asked.
|
||||||
7. Optional: if GitHub was chosen, the system configures the Gitea repository as a push mirror to GitHub and verifies it. A license file in the Gitea repository is pushed to GitHub by the mirror.
|
7. Optional: if GitHub was chosen, the system configures the Gitea repository as a push mirror to GitHub and verifies it. A license file in the Gitea repository is pushed to GitHub by the mirror.
|
||||||
8. The system creates the local project with the `origin` remote and, if GitHub was chosen, the `github` remote.
|
8. The system creates the local project with the `origin` remote and, if GitHub was chosen, the `github` remote.
|
||||||
9. The system adds the framework submodule, installs its skills and hooks (and the plan gate if chosen) and copies the templates. If the Maintainer agrees, it also creates the project's own `.env` with the credentials the project needs.
|
9. The system adds the framework submodule, installs its skills and hooks (and the plan gate if chosen) and copies the templates. If the Maintainer agrees, it also creates the project's own `.env` with the credentials the project needs.
|
||||||
@@ -62,7 +62,7 @@
|
|||||||
1. The system stops before any request and names the key; it does not ask for the value instead.
|
1. The system stops before any request and names the key; it does not ask for the value instead.
|
||||||
- 4a. A token is invalid, an owner does not accept the repository, or the name is taken:
|
- 4a. A token is invalid, an owner does not accept the repository, or the name is taken:
|
||||||
1. The system stops before creating anything and says which check failed. The GitHub token is only checked when GitHub was chosen.
|
1. The system stops before creating anything and says which check failed. The GitHub token is only checked when GitHub was chosen.
|
||||||
- 4c. GitHub was chosen and the Gitea server does not offer the `AGPL-3.0` license:
|
- 4c. A license applies and the Gitea server does not offer it:
|
||||||
1. The system stops before creating anything and names the missing license.
|
1. The system stops before creating anything and names the missing license.
|
||||||
- 4b. SSH to Gitea does not work:
|
- 4b. SSH to Gitea does not work:
|
||||||
1. The system uses HTTPS for `origin` and warns that the framework submodule step will fail until SSH is configured.
|
1. The system uses HTTPS for `origin` and warns that the framework submodule step will fail until SSH is configured.
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
| 3 | The GitHub owner and the Gitea owner are chosen separately; `GITHUB_USER` is only the authenticating account |
|
| 3 | The GitHub owner and the Gitea owner are chosen separately; `GITHUB_USER` is only the authenticating account |
|
||||||
| 3 | A project detail set in `config.env` (the key is present, even if empty where an empty value is allowed) is not asked; only the confirmations stay interactive |
|
| 3 | A project detail set in `config.env` (the key is present, even if empty where an empty value is allowed) is not asked; only the confirmations stay interactive |
|
||||||
| 3, 5, 7 | GitHub is optional; without it no GitHub repository, mirror or `github` remote is created and the GitHub credentials are not required |
|
| 3, 5, 7 | GitHub is optional; without it no GitHub repository, mirror or `github` remote is created and the GitHub credentials are not required |
|
||||||
| 6 | Choosing GitHub applies the AGPL license (key `AGPL-3.0`) to the Gitea repository when it is created, so that repository is not empty; without GitHub there is no license and the repository is empty |
|
| 6 | The license that applies is added to the Gitea repository when it is created, so that repository is not empty: `PROJECT_LICENSE` if set (a Gitea license key such as `MIT`, or `none`), otherwise AGPL-3.0 when GitHub is chosen, otherwise none. It is independent of the GitHub choice when set, and it is never asked |
|
||||||
| 7 | The mirror direction is Gitea to GitHub; the GitHub repository stays empty and receives its content from the mirror |
|
| 7 | The mirror direction is Gitea to GitHub; the GitHub repository stays empty and receives its content from the mirror |
|
||||||
| 8 | `origin` uses HTTPS derived from `GITEA_URL`, or SSH when the SSH test in step 4 passed; when the Gitea repository is not empty (GitHub chosen) the local project is created by fetching it, not by an unrelated `git init` history |
|
| 8 | `origin` uses HTTPS derived from `GITEA_URL`, or SSH when the SSH test in step 4 passed; when the Gitea repository is not empty (GitHub chosen) the local project is created by fetching it, not by an unrelated `git init` history |
|
||||||
| 8, 9 | Nothing is overwritten or deleted without consent, and no commit is made |
|
| 8, 9 | Nothing is overwritten or deleted without consent, and no commit is made |
|
||||||
@@ -102,5 +102,5 @@
|
|||||||
[US-001]: ../user-stories.md
|
[US-001]: ../user-stories.md
|
||||||
[SA-001]: ../stakeholder-analysis.md
|
[SA-001]: ../stakeholder-analysis.md
|
||||||
[DM-001]: ./dm.md
|
[DM-001]: ./dm.md
|
||||||
[2a6bb8e]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/2a6bb8e8afadfe6ca4a621da30e44a372898ca62
|
|
||||||
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
||||||
|
[d773fa9]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/d773fa91df5a54090254e12e074880fb6526a9ff
|
||||||
|
|||||||
+23
-6
@@ -4,13 +4,13 @@
|
|||||||
| Key | Value |
|
| Key | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| ID | US-001 |
|
| ID | US-001 |
|
||||||
| CrossReference | [BC-001], [UCD-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005] |
|
| CrossReference | [BC-001], [UCD-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006] |
|
||||||
|
|
||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-05 | Deprecated | Jens Tirsvad Nielsen | S02 | Added US-001.04: project details preset in config.env | [2a6bb8e] |
|
|
||||||
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Added US-001.05: credentials asked when missing and kept in the project .env | [ded26a6] |
|
| 2026-10-06 | Accepted | Jens Tirsvad Nielsen | S02 | Added US-001.05: credentials asked when missing and kept in the project .env | [ded26a6] |
|
||||||
|
| 2026-10-06 | Proposed | Jens Tirsvad Nielsen | S02 | Added US-001.06: the license set in config.env; US-001.02 names the license that applies | [d773fa9] |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
One epic: "Create a new project" ([UC-001]), setting up a new project on Gitea, optionally on GitHub, with the SQA-QC-Framework in place. The actor is the Maintainer, as in [UCD-001] (S01 or S02; for now one person holds both roles).
|
One epic: "Create a new project" ([UC-001]), setting up a new project on Gitea, optionally on GitHub, with the SQA-QC-Framework in place. The actor is the Maintainer, as in [UCD-001] (S01 or S02; for now one person holds both roles).
|
||||||
|
|
||||||
The epic is split into five stories, one per milestone. Each story fits one two-week phase and can be shown working at the end of it.
|
The epic is split into six stories, one per milestone. Each story fits one two-week phase and can be shown working at the end of it.
|
||||||
|
|
||||||
## Story List
|
## Story List
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ The epic is split into five stories, one per milestone. Each story fits one two-
|
|||||||
|
|
||||||
**Acceptance Criteria**
|
**Acceptance Criteria**
|
||||||
|
|
||||||
- Given valid tokens and owners, when the script runs, then a Gitea repository exists under the chosen owner: empty, or holding the AGPL license when GitHub was chosen.
|
- Given valid tokens and owners, when the script runs, then a Gitea repository exists under the chosen owner: empty, or holding the license that applies (the one set in `PROJECT_LICENSE`, or AGPL-3.0 when GitHub was chosen).
|
||||||
- Given GitHub was chosen, when the script runs, then an empty GitHub repository exists under its chosen owner (not assumed to be `GITHUB_USER`) and Gitea mirrors to it, and no credential is stored in any address.
|
- Given GitHub was chosen, when the script runs, then an empty GitHub repository exists under its chosen owner (not assumed to be `GITHUB_USER`) and Gitea mirrors to it, and no credential is stored in any address.
|
||||||
- Given a step fails, when the script stops, then it reports what was created and how to continue.
|
- Given a step fails, when the script stops, then it reports what was created and how to continue.
|
||||||
|
|
||||||
@@ -95,9 +95,25 @@ The epic is split into five stories, one per milestone. Each story fits one two-
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| [UC-001] steps 2 and 9, [MIL-005] | fits one phase | Independent: needs the local project of US-001.03 |
|
| [UC-001] steps 2 and 9, [MIL-005] | fits one phase | Independent: needs the local project of US-001.03 |
|
||||||
|
|
||||||
|
### US-001.06 — Create a new project: choose the license in `config.env`
|
||||||
|
|
||||||
|
**As a** Maintainer, **I want** to set the project's license in `config.env`, **so that** a project is not forced to AGPL-3.0 by the GitHub choice and does not need a question for it.
|
||||||
|
|
||||||
|
**Acceptance Criteria**
|
||||||
|
|
||||||
|
- Given `PROJECT_LICENSE` is set to a license the Gitea server offers, when the script creates the Gitea repository, then it holds that license, with or without GitHub, and the license is not asked.
|
||||||
|
- Given `PROJECT_LICENSE=none`, then the repository has no license even when GitHub is chosen.
|
||||||
|
- Given `PROJECT_LICENSE` is absent, then the license is AGPL-3.0 when GitHub is chosen and none otherwise, as before.
|
||||||
|
- Given the value is empty or invalid, or the server does not offer it, when the script starts or checks the hosts, then it stops before anything is created and names the key or the license.
|
||||||
|
- Given GitHub is chosen, then the license reaches the GitHub repository through the mirror, as before.
|
||||||
|
|
||||||
|
| Traces to | Size | INVEST exceptions |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| [UC-001] steps 3, 4 and 6, [MIL-006] | fits one phase | Independent: needs the configurable details of US-001.04 |
|
||||||
|
|
||||||
## INVEST Check
|
## INVEST Check
|
||||||
|
|
||||||
Valuable, Negotiable, Estimable, Small and Testable hold for each story. Independent holds only in part: the stories are ordered, each using what the one before it delivers, which follows the milestone order in [PP-001]. This is flagged as an exception on US-001.02 to US-001.05.
|
Valuable, Negotiable, Estimable, Small and Testable hold for each story. Independent holds only in part: the stories are ordered, each using what the one before it delivers, which follows the milestone order in [PP-001]. This is flagged as an exception on US-001.02 to US-001.06.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -109,6 +125,7 @@ Valuable, Negotiable, Estimable, Small and Testable hold for each story. Indepen
|
|||||||
[MIL-003]: ./milestones/mil-003-scaffold-and-release.md
|
[MIL-003]: ./milestones/mil-003-scaffold-and-release.md
|
||||||
[MIL-004]: ./milestones/mil-004-configurable-details.md
|
[MIL-004]: ./milestones/mil-004-configurable-details.md
|
||||||
[MIL-005]: ./milestones/mil-005-credentials.md
|
[MIL-005]: ./milestones/mil-005-credentials.md
|
||||||
|
[MIL-006]: ./milestones/mil-006-project-license.md
|
||||||
[PP-001]: ./project-plan.md
|
[PP-001]: ./project-plan.md
|
||||||
[2a6bb8e]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/2a6bb8e8afadfe6ca4a621da30e44a372898ca62
|
|
||||||
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
[ded26a6]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/ded26a658c666bf29d84093cb352e3635e07719b
|
||||||
|
[d773fa9]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/d773fa91df5a54090254e12e074880fb6526a9ff
|
||||||
|
|||||||
+6
-15
@@ -11,9 +11,7 @@
|
|||||||
# repository, remotes (no credential in any address), the framework as a
|
# repository, remotes (no credential in any address), the framework as a
|
||||||
# submodule, the framework's skills and git hooks (and the plan gate if
|
# submodule, the framework's skills and git hooks (and the plan gate if
|
||||||
# chosen) and its templates. Choosing GitHub also applies the AGPL-3.0
|
# chosen) and its templates. Choosing GitHub also applies the AGPL-3.0
|
||||||
# license to the Gitea repository. After a yes (default no) it also writes
|
# license to the Gitea repository. No commit is made in the new project.
|
||||||
# the new project's own .env with the credentials the project needs. No
|
|
||||||
# commit is made in the new project.
|
|
||||||
#
|
#
|
||||||
# Dry run by default
|
# Dry run by default
|
||||||
# Without --apply the script only reads from GitHub and Gitea (GET
|
# Without --apply the script only reads from GitHub and Gitea (GET
|
||||||
@@ -29,8 +27,7 @@
|
|||||||
# Options
|
# Options
|
||||||
# --apply create the repositories and the mirror (after a final yes)
|
# --apply create the repositories and the mirror (after a final yes)
|
||||||
# --config FILE service addresses (default: config.env in the project root)
|
# --config FILE service addresses (default: config.env in the project root)
|
||||||
# --env FILE credentials (default: .env in the project root); optional:
|
# --env FILE credentials (default: .env in the project root)
|
||||||
# a credential it does not provide is asked, not echoed
|
|
||||||
# -h, --help show this help
|
# -h, --help show this help
|
||||||
# --version show the version
|
# --version show the version
|
||||||
#
|
#
|
||||||
@@ -39,8 +36,7 @@
|
|||||||
# the optional GITEA_SSH_PORT (default 10022), MIRROR_INTERVAL
|
# the optional GITEA_SSH_PORT (default 10022), MIRROR_INTERVAL
|
||||||
# (default 10m0s) and FRAMEWORK_REPO (default
|
# (default 10m0s) and FRAMEWORK_REPO (default
|
||||||
# TirSystem/SQA-QC-Framework, the submodule's OWNER/NAME)
|
# TirSystem/SQA-QC-Framework, the submodule's OWNER/NAME)
|
||||||
# .env GITHUB_PAT, GITHUB_USER, GITEA_TOKEN (all optional, each
|
# .env GITHUB_PAT, GITHUB_USER, GITEA_TOKEN
|
||||||
# asked when missing)
|
|
||||||
#
|
#
|
||||||
# Environment
|
# Environment
|
||||||
# REPOFOUNDRY_NAME project name used in messages (default: RepoFoundry)
|
# REPOFOUNDRY_NAME project name used in messages (default: RepoFoundry)
|
||||||
@@ -69,8 +65,8 @@
|
|||||||
# This file is the entry point. The work is split by responsibility into
|
# This file is the entry point. The work is split by responsibility into
|
||||||
# the files in lib/ next to it (one job per file, see the first lines of
|
# the files in lib/ next to it (one job per file, see the first lines of
|
||||||
# each file): constants, output, temp, util, validate, config, tools, json,
|
# each file): constants, output, temp, util, validate, config, tools, json,
|
||||||
# http, api, prompts, credentials, project, hosts, preflight, steps, plan,
|
# http, api, prompts, project, hosts, preflight, steps, plan, repositories,
|
||||||
# repositories, mirror, git, localproject, framework, envfile, apply and cli. The files are loaded
|
# mirror, git, localproject, framework, apply and cli. The files are loaded
|
||||||
# from this directory only.
|
# from this directory only.
|
||||||
#
|
#
|
||||||
# Exit codes
|
# Exit codes
|
||||||
@@ -125,8 +121,6 @@ source "$SCRIPT_DIR/lib/http.sh"
|
|||||||
source "$SCRIPT_DIR/lib/api.sh"
|
source "$SCRIPT_DIR/lib/api.sh"
|
||||||
# shellcheck source=lib/prompts.sh
|
# shellcheck source=lib/prompts.sh
|
||||||
source "$SCRIPT_DIR/lib/prompts.sh"
|
source "$SCRIPT_DIR/lib/prompts.sh"
|
||||||
# shellcheck source=lib/credentials.sh
|
|
||||||
source "$SCRIPT_DIR/lib/credentials.sh"
|
|
||||||
# shellcheck source=lib/project.sh
|
# shellcheck source=lib/project.sh
|
||||||
source "$SCRIPT_DIR/lib/project.sh"
|
source "$SCRIPT_DIR/lib/project.sh"
|
||||||
# shellcheck source=lib/hosts.sh
|
# shellcheck source=lib/hosts.sh
|
||||||
@@ -147,8 +141,6 @@ source "$SCRIPT_DIR/lib/git.sh"
|
|||||||
source "$SCRIPT_DIR/lib/localproject.sh"
|
source "$SCRIPT_DIR/lib/localproject.sh"
|
||||||
# shellcheck source=lib/framework.sh
|
# shellcheck source=lib/framework.sh
|
||||||
source "$SCRIPT_DIR/lib/framework.sh"
|
source "$SCRIPT_DIR/lib/framework.sh"
|
||||||
# shellcheck source=lib/envfile.sh
|
|
||||||
source "$SCRIPT_DIR/lib/envfile.sh"
|
|
||||||
# shellcheck source=lib/apply.sh
|
# shellcheck source=lib/apply.sh
|
||||||
source "$SCRIPT_DIR/lib/apply.sh"
|
source "$SCRIPT_DIR/lib/apply.sh"
|
||||||
# shellcheck source=lib/cli.sh
|
# shellcheck source=lib/cli.sh
|
||||||
@@ -174,10 +166,9 @@ main() {
|
|||||||
check_tools
|
check_tools
|
||||||
setup_temp_dir
|
setup_temp_dir
|
||||||
load_configuration
|
load_configuration
|
||||||
collect_credentials GITEA_TOKEN
|
|
||||||
collect_project_details
|
collect_project_details
|
||||||
if ((PROJECT[has_github])); then
|
if ((PROJECT[has_github])); then
|
||||||
collect_credentials GITHUB_PAT GITHUB_USER
|
require_github_credentials
|
||||||
fi
|
fi
|
||||||
init_steps
|
init_steps
|
||||||
print_summary
|
print_summary
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ create_all() {
|
|||||||
add_framework
|
add_framework
|
||||||
install_framework
|
install_framework
|
||||||
copy_templates
|
copy_templates
|
||||||
create_env_file
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# confirm_framework_access: the framework comes over SSH. Without SSH the
|
# confirm_framework_access: the framework comes over SSH. Without SSH the
|
||||||
|
|||||||
+19
-15
@@ -4,7 +4,7 @@
|
|||||||
#
|
#
|
||||||
# Part of create-project.sh: sourced by it, never run on its own.
|
# Part of create-project.sh: sourced by it, never run on its own.
|
||||||
#
|
#
|
||||||
# Provides: unquote_value, parse_env_file, parse_env_entry, validate_config, check_preset, check_preset_choice, validate_project_presets, validate_credentials, warn_if_env_unsafe, load_configuration
|
# Provides: unquote_value, parse_env_file, parse_env_entry, validate_config, check_preset, check_preset_choice, validate_project_presets, validate_credentials, require_github_credentials, warn_if_env_unsafe, load_configuration
|
||||||
|
|
||||||
# unquote_value RAW: strip matching quotes (or a trailing " # comment" on an
|
# unquote_value RAW: strip matching quotes (or a trailing " # comment" on an
|
||||||
# unquoted value) and return the value in REPLY. Fails on unbalanced quotes.
|
# unquoted value) and return the value in REPLY. Fails on unbalanced quotes.
|
||||||
@@ -144,23 +144,20 @@ validate_project_presets() {
|
|||||||
check_preset_choice ENABLE_PLAN_GATE yes no
|
check_preset_choice ENABLE_PLAN_GATE yes no
|
||||||
}
|
}
|
||||||
|
|
||||||
# validate_credentials: check the credentials that .env provides. A credential
|
|
||||||
# that is not provided is not an error: it is asked later (collect_credentials).
|
|
||||||
validate_credentials() {
|
validate_credentials() {
|
||||||
# Register secrets first so that no later message can show them.
|
if [[ -z ${CREDENTIALS[GITEA_TOKEN]:-} ]]; then
|
||||||
if [[ -n ${CREDENTIALS[GITEA_TOKEN]:-} ]]; then
|
die "GITEA_TOKEN is missing in $ENV_FILE (see .env.example)"
|
||||||
SECRET_VALUES+=("${CREDENTIALS[GITEA_TOKEN]}")
|
|
||||||
fi
|
fi
|
||||||
|
# Register secrets first so that no later message can show them.
|
||||||
|
SECRET_VALUES+=("${CREDENTIALS[GITEA_TOKEN]}")
|
||||||
if [[ -n ${CREDENTIALS[GITHUB_PAT]:-} ]]; then
|
if [[ -n ${CREDENTIALS[GITHUB_PAT]:-} ]]; then
|
||||||
SECRET_VALUES+=("${CREDENTIALS[GITHUB_PAT]}")
|
SECRET_VALUES+=("${CREDENTIALS[GITHUB_PAT]}")
|
||||||
fi
|
fi
|
||||||
if [[ -n ${CREDENTIALS[GITEA_TOKEN]:-} ]] &&
|
is_valid_token "${CREDENTIALS[GITEA_TOKEN]}" ||
|
||||||
! is_valid_token "${CREDENTIALS[GITEA_TOKEN]}"; then
|
die "GITEA_TOKEN in $ENV_FILE is not a valid token (8 to 255 letters, digits or _ . ~ + / = -)"
|
||||||
die "GITEA_TOKEN in $ENV_FILE is not a valid token ($HINT_TOKEN)"
|
|
||||||
fi
|
|
||||||
if [[ -n ${CREDENTIALS[GITHUB_PAT]:-} ]] &&
|
if [[ -n ${CREDENTIALS[GITHUB_PAT]:-} ]] &&
|
||||||
! is_valid_token "${CREDENTIALS[GITHUB_PAT]}"; then
|
! is_valid_token "${CREDENTIALS[GITHUB_PAT]}"; then
|
||||||
die "GITHUB_PAT in $ENV_FILE is not a valid token ($HINT_TOKEN)"
|
die "GITHUB_PAT in $ENV_FILE is not a valid token (8 to 255 letters, digits or _ . ~ + / = -)"
|
||||||
fi
|
fi
|
||||||
if [[ -n ${CREDENTIALS[GITHUB_USER]:-} ]] &&
|
if [[ -n ${CREDENTIALS[GITHUB_USER]:-} ]] &&
|
||||||
! is_valid_github_owner "${CREDENTIALS[GITHUB_USER]}"; then
|
! is_valid_github_owner "${CREDENTIALS[GITHUB_USER]}"; then
|
||||||
@@ -168,6 +165,16 @@ validate_credentials() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# GitHub credentials are only needed when the Maintainer chose GitHub.
|
||||||
|
require_github_credentials() {
|
||||||
|
local key
|
||||||
|
for key in GITHUB_PAT GITHUB_USER; do
|
||||||
|
if [[ -z ${CREDENTIALS[$key]:-} ]]; then
|
||||||
|
die "GitHub was chosen but $key is missing in $ENV_FILE (see .env.example)"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
warn_if_env_unsafe() {
|
warn_if_env_unsafe() {
|
||||||
local file="$1" dir mode
|
local file="$1" dir mode
|
||||||
case "$(uname -s 2>/dev/null || true)" in
|
case "$(uname -s 2>/dev/null || true)" in
|
||||||
@@ -193,10 +200,7 @@ warn_if_env_unsafe() {
|
|||||||
load_configuration() {
|
load_configuration() {
|
||||||
parse_env_file "$CONFIG_FILE" CONFIG_KEYS CONFIG
|
parse_env_file "$CONFIG_FILE" CONFIG_KEYS CONFIG
|
||||||
validate_config
|
validate_config
|
||||||
# .env is optional: a credential it does not provide is asked.
|
|
||||||
if [[ -e $ENV_FILE ]]; then
|
|
||||||
parse_env_file "$ENV_FILE" CREDENTIAL_KEYS CREDENTIALS
|
parse_env_file "$ENV_FILE" CREDENTIAL_KEYS CREDENTIALS
|
||||||
warn_if_env_unsafe "$ENV_FILE"
|
|
||||||
fi
|
|
||||||
validate_credentials
|
validate_credentials
|
||||||
|
warn_if_env_unsafe "$ENV_FILE"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,10 +26,8 @@ readonly HINT_DESCRIPTION="at most $MAX_DESCRIPTION_LENGTH characters and no con
|
|||||||
readonly HINT_GITEA_OWNER="use letters, digits, '.', '_' or '-' (at most 39)"
|
readonly HINT_GITEA_OWNER="use letters, digits, '.', '_' or '-' (at most 39)"
|
||||||
readonly HINT_GITHUB_OWNER="use letters, digits or '-' (at most 39)"
|
readonly HINT_GITHUB_OWNER="use letters, digits or '-' (at most 39)"
|
||||||
readonly HINT_DIRECTORY="must not be empty, start with '-' or contain control characters"
|
readonly HINT_DIRECTORY="must not be empty, start with '-' or contain control characters"
|
||||||
readonly HINT_TOKEN="8 to 255 letters, digits or _ . ~ + / = -"
|
|
||||||
readonly ENV_FILE_NAME=".env"
|
|
||||||
readonly PLAN_STEPS=("GitHub repository" "Gitea repository" "Push mirror"
|
readonly PLAN_STEPS=("GitHub repository" "Gitea repository" "Push mirror"
|
||||||
"Local project" "Framework" "Skills and hooks" "Templates" "Project .env")
|
"Local project" "Framework" "Skills and hooks" "Templates")
|
||||||
# shellcheck disable=SC2034 # read through namerefs (parse_env_file)
|
# shellcheck disable=SC2034 # read through namerefs (parse_env_file)
|
||||||
readonly CONFIG_KEYS=(GITHUB_API_URL GITHUB_WEB_URL GITEA_URL GITEA_API_URL
|
readonly CONFIG_KEYS=(GITHUB_API_URL GITHUB_WEB_URL GITEA_URL GITEA_API_URL
|
||||||
GITEA_SSH_PORT MIRROR_INTERVAL FRAMEWORK_REPO
|
GITEA_SSH_PORT MIRROR_INTERVAL FRAMEWORK_REPO
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
# shellcheck shell=bash
|
|
||||||
# shellcheck disable=SC2004,SC2034,SC2154 # shared state and arrays are declared in constants.sh
|
|
||||||
# credentials.sh - Asking for a credential that .env does not provide.
|
|
||||||
#
|
|
||||||
# Part of create-project.sh: sourced by it, never run on its own.
|
|
||||||
#
|
|
||||||
# Provides: credential_label, collect_credentials
|
|
||||||
|
|
||||||
# credential_label KEY: the name of a credential as the Maintainer sees it.
|
|
||||||
credential_label() {
|
|
||||||
case "$1" in
|
|
||||||
GITEA_TOKEN) printf 'Gitea access token' ;;
|
|
||||||
GITHUB_PAT) printf 'GitHub personal access token' ;;
|
|
||||||
GITHUB_USER) printf 'GitHub account name (the account the token belongs to)' ;;
|
|
||||||
*) printf '%s' "$1" ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
# collect_credentials KEY...: ask for each credential that is not already
|
|
||||||
# provided. A token is read without echo and registered as a secret at once,
|
|
||||||
# so no later message can show it; the GitHub account name is not secret and
|
|
||||||
# is read like any other answer. An empty value in .env counts as not provided.
|
|
||||||
collect_credentials() {
|
|
||||||
local key
|
|
||||||
for key in "$@"; do
|
|
||||||
if [[ -n ${CREDENTIALS[$key]:-} ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
case "$key" in
|
|
||||||
GITHUB_USER)
|
|
||||||
prompt_value "$(credential_label "$key")" "" is_valid_github_owner \
|
|
||||||
"use letters, digits or '-' (at most 39)"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
prompt_secret "$(credential_label "$key")" is_valid_token "$HINT_TOKEN"
|
|
||||||
SECRET_VALUES+=("$REPLY")
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
CREDENTIALS[$key]="$REPLY"
|
|
||||||
REPLY=""
|
|
||||||
done
|
|
||||||
}
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
# shellcheck shell=bash
|
|
||||||
# shellcheck disable=SC2004,SC2034,SC2154 # shared state and arrays are declared in constants.sh
|
|
||||||
# envfile.sh - The .env file of the new project: the one place a credential is written.
|
|
||||||
#
|
|
||||||
# Part of create-project.sh: sourced by it, never run on its own.
|
|
||||||
#
|
|
||||||
# Provides: env_file_keys, env_file_key_list, exclude_env_file, write_env_file, create_env_file
|
|
||||||
|
|
||||||
# env_file_keys: the credentials the new project needs, one per line: the
|
|
||||||
# Gitea token, and the GitHub token and account name when GitHub was chosen.
|
|
||||||
env_file_keys() {
|
|
||||||
printf '%s\n' GITEA_TOKEN
|
|
||||||
if ((PROJECT[has_github])); then
|
|
||||||
printf '%s\n' GITHUB_PAT GITHUB_USER
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# env_file_key_list: the same keys on one line, for messages.
|
|
||||||
env_file_key_list() {
|
|
||||||
local keys
|
|
||||||
keys="$(env_file_keys | tr '\n' ' ')"
|
|
||||||
printf '%s' "${keys% }"
|
|
||||||
}
|
|
||||||
|
|
||||||
# exclude_env_file DIR: make git ignore .env in DIR without touching a tracked
|
|
||||||
# file: the entry goes into .git/info/exclude, which is never committed. It
|
|
||||||
# does nothing when .env is already ignored.
|
|
||||||
exclude_env_file() {
|
|
||||||
local dir="$1" gitdir exclude
|
|
||||||
if git_project "$dir" check-ignore -q -- "$ENV_FILE_NAME"; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
gitdir="$(git_project "$dir" rev-parse --absolute-git-dir)"
|
|
||||||
exclude="$gitdir/info/exclude"
|
|
||||||
mkdir -p -- "$gitdir/info"
|
|
||||||
# Start on a fresh line when the file does not end with one.
|
|
||||||
if [[ -s $exclude && -n "$(tail -c 1 -- "$exclude")" ]]; then
|
|
||||||
printf '\n' >>"$exclude"
|
|
||||||
fi
|
|
||||||
printf '%s\n' "# RepoFoundry: the credentials file of this project" "$ENV_FILE_NAME" >>"$exclude"
|
|
||||||
git_project "$dir" check-ignore -q -- "$ENV_FILE_NAME" ||
|
|
||||||
die "could not make git ignore $ENV_FILE_NAME in $dir; nothing was written to it"
|
|
||||||
}
|
|
||||||
|
|
||||||
# write_env_file DIR IS_REPLACE: write the credentials to DIR/.env. The file is
|
|
||||||
# created private (mode 600) from the start, never readable by others, even
|
|
||||||
# for a moment: it is written under umask 077 as a temporary file next to the
|
|
||||||
# target and moved into place. An existing file is only replaced when
|
|
||||||
# IS_REPLACE is 1, and a file that appears in the meantime is never replaced.
|
|
||||||
write_env_file() {
|
|
||||||
local dir="$1" is_replace="$2" target tmp key
|
|
||||||
target="$dir/$ENV_FILE_NAME"
|
|
||||||
tmp="$(umask 077 && mktemp "$dir/$ENV_FILE_NAME.XXXXXX")"
|
|
||||||
TEMP_FILES+=("$tmp")
|
|
||||||
{
|
|
||||||
while IFS= read -r key; do
|
|
||||||
printf '%s=%s\n' "$key" "${CREDENTIALS[$key]}"
|
|
||||||
done < <(env_file_keys)
|
|
||||||
} >"$tmp"
|
|
||||||
if ((is_replace)); then
|
|
||||||
mv -f -- "$tmp" "$target"
|
|
||||||
else
|
|
||||||
mv -n -- "$tmp" "$target"
|
|
||||||
if [[ -e $tmp ]]; then
|
|
||||||
die "$target appeared while it was being written; it was not replaced"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# create_env_file: the last step. Only after a yes (default no) is the .env
|
|
||||||
# written, and an existing one is only replaced after another yes. Nothing
|
|
||||||
# printed names a value, only the keys.
|
|
||||||
create_env_file() {
|
|
||||||
local label="Project .env" dir="${PROJECT[directory]}" keys is_replace=0
|
|
||||||
keys="$(env_file_key_list)"
|
|
||||||
begin_step "$label"
|
|
||||||
prompt_yes_no "Create a $ENV_FILE_NAME file in the project with the credentials it needs ($keys); only you can read it and git ignores it" n
|
|
||||||
if ! ((REPLY)); then
|
|
||||||
finish_step "$label" "skipped" "(you declined)"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
if git_project "$dir" ls-files --error-unmatch -- "$ENV_FILE_NAME" >/dev/null 2>&1; then
|
|
||||||
finish_step "$label" "skipped" "($ENV_FILE_NAME is tracked by git; it was not written)"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
if [[ -e $dir/$ENV_FILE_NAME || -L $dir/$ENV_FILE_NAME ]]; then
|
|
||||||
prompt_yes_no "$ENV_FILE_NAME already exists in the project. Replace it" n
|
|
||||||
if ! ((REPLY)); then
|
|
||||||
finish_step "$label" "kept" "(the existing $ENV_FILE_NAME was left as it was)"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
is_replace=1
|
|
||||||
fi
|
|
||||||
exclude_env_file "$dir"
|
|
||||||
write_env_file "$dir" "$is_replace"
|
|
||||||
finish_step "$label" "created" "($keys; only you can read it, git ignores it)"
|
|
||||||
}
|
|
||||||
@@ -54,5 +54,4 @@ print_plan() {
|
|||||||
else
|
else
|
||||||
say "$(printf ' %-18s: %s' "Framework" "NOT possible without SSH to Gitea; you will be asked whether to go on without it")"
|
say "$(printf ' %-18s: %s' "Framework" "NOT possible without SSH to Gitea; you will be asked whether to go on without it")"
|
||||||
fi
|
fi
|
||||||
say "$(printf ' %-18s: %s' "Project .env" "you are asked whether to create it ($(env_file_key_list))")"
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-22
@@ -4,7 +4,7 @@
|
|||||||
#
|
#
|
||||||
# Part of create-project.sh: sourced by it, never run on its own.
|
# Part of create-project.sh: sourced by it, never run on its own.
|
||||||
#
|
#
|
||||||
# Provides: prompt_value, prompt_secret, prompt_choice, prompt_yes_no
|
# Provides: prompt_value, prompt_choice, prompt_yes_no
|
||||||
|
|
||||||
# prompt_value LABEL DEFAULT VALIDATOR HINT: ask until VALIDATOR accepts the
|
# prompt_value LABEL DEFAULT VALIDATOR HINT: ask until VALIDATOR accepts the
|
||||||
# answer; the accepted answer is returned in REPLY.
|
# answer; the accepted answer is returned in REPLY.
|
||||||
@@ -27,27 +27,6 @@ prompt_value() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
# prompt_secret LABEL VALIDATOR HINT: like prompt_value for a secret. What is
|
|
||||||
# typed is not shown (read -s) and a refused answer is never repeated in the
|
|
||||||
# message. An empty answer is refused; there is no default.
|
|
||||||
prompt_secret() {
|
|
||||||
local label="$1" validator="$2" hint="$3" answer
|
|
||||||
while true; do
|
|
||||||
printf '%s (input is hidden): ' "$label" >&2
|
|
||||||
IFS= read -rs answer || {
|
|
||||||
printf '\n' >&2
|
|
||||||
die "no input available for '$label'"
|
|
||||||
}
|
|
||||||
printf '\n' >&2 # the newline that hidden input did not echo
|
|
||||||
answer="$(trim "$answer")"
|
|
||||||
if [[ -n $answer ]] && "$validator" "$answer"; then
|
|
||||||
REPLY="$answer"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
warn "invalid $label: $hint"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
# prompt_choice LABEL DEFAULT CHOICE...: the answer is returned in REPLY.
|
# prompt_choice LABEL DEFAULT CHOICE...: the answer is returned in REPLY.
|
||||||
prompt_choice() {
|
prompt_choice() {
|
||||||
local label="$1" default="$2" answer
|
local label="$1" default="$2" answer
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ validate_credentials"
|
|||||||
assert_status "$case_name" 1 "$STATUS"
|
assert_status "$case_name" 1 "$STATUS"
|
||||||
assert_contains "$case_name message" "$ERR" "$expected"
|
assert_contains "$case_name message" "$ERR" "$expected"
|
||||||
done <<'EOF'
|
done <<'EOF'
|
||||||
|
no Gitea token|GITHUB_USER=octo\n|GITEA_TOKEN is missing
|
||||||
token too short|GITEA_TOKEN=short\n|not a valid token
|
token too short|GITEA_TOKEN=short\n|not a valid token
|
||||||
token with a backslash|GITEA_TOKEN=abc\\defgh12345\n|not a valid token
|
token with a backslash|GITEA_TOKEN=abc\\defgh12345\n|not a valid token
|
||||||
bad GitHub token|GITEA_TOKEN=abcdefgh12345\nGITHUB_PAT=bad token\n|GITHUB_PAT
|
bad GitHub token|GITEA_TOKEN=abcdefgh12345\nGITHUB_PAT=bad token\n|GITHUB_PAT
|
||||||
@@ -103,6 +104,18 @@ bad GitHub user|GITEA_TOKEN=abcdefgh12345\nGITHUB_USER=-bad-\n|GITHUB_USER
|
|||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test_github_credentials_required_only_when_chosen() {
|
||||||
|
printf 'GITEA_TOKEN=%s\n' "$FAKE_GITEA_TOKEN" >"$WORK/e.env"
|
||||||
|
run_lib "" "parse_env_file \"$WORK/e.env\" CREDENTIAL_KEYS CREDENTIALS
|
||||||
|
validate_credentials
|
||||||
|
echo no-github-ok
|
||||||
|
ENV_FILE=\"$WORK/e.env\"
|
||||||
|
require_github_credentials"
|
||||||
|
assert_contains "Gitea-only .env is valid" "$OUT" "no-github-ok"
|
||||||
|
assert_status "GitHub credentials missing" 1 "$STATUS"
|
||||||
|
assert_contains "names the missing key" "$ERR" "GITHUB_PAT is missing"
|
||||||
|
}
|
||||||
|
|
||||||
test_validators() {
|
test_validators() {
|
||||||
local fn value expected
|
local fn value expected
|
||||||
while IFS='|' read -r fn value expected; do
|
while IFS='|' read -r fn value expected; do
|
||||||
|
|||||||
@@ -1,305 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# test-credentials.sh - tests for the credentials that .env does not provide
|
|
||||||
# and for the .env file of the new project (MIL-005): they are asked without
|
|
||||||
# echo, the project .env is only written after a yes, owner-only and ignored
|
|
||||||
# by git, and no token appears anywhere else. Sourced by run-tests.sh.
|
|
||||||
|
|
||||||
# shellcheck disable=SC2016 # snippet and fixture text is literal on purpose
|
|
||||||
|
|
||||||
readonly NL=$'\n'
|
|
||||||
|
|
||||||
# credentials_input: the answers of a run with no .env at all and GitHub
|
|
||||||
# chosen: the Gitea token, the details, then the GitHub token and account.
|
|
||||||
credentials_input() {
|
|
||||||
printf '%s' "$FAKE_GITEA_TOKEN$NL$ANSWERS_GITHUB$FAKE_GITHUB_PAT${NL}octo-user$NL"
|
|
||||||
}
|
|
||||||
|
|
||||||
run_dry_cred() {
|
|
||||||
run_cli "$1" --config "$WORK/config.env" --env "$WORK/.env"
|
|
||||||
}
|
|
||||||
|
|
||||||
run_apply_cred() {
|
|
||||||
run_cli "$1" --apply --config "$WORK/config.env" --env "$WORK/.env"
|
|
||||||
}
|
|
||||||
|
|
||||||
# without_env: remove the .env of the fixtures.
|
|
||||||
without_env() {
|
|
||||||
rm -f -- "$WORK/.env"
|
|
||||||
}
|
|
||||||
|
|
||||||
# env_mode FILE: the permission bits, empty where the platform has none.
|
|
||||||
env_mode() {
|
|
||||||
case "$(uname -s 2>/dev/null || true)" in
|
|
||||||
MINGW* | MSYS* | CYGWIN*) ;;
|
|
||||||
*) stat -c '%a' -- "$1" 2>/dev/null || stat -f '%Lp' -- "$1" 2>/dev/null || true ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
# ------------------------------------------------------------ prompt_secret
|
|
||||||
|
|
||||||
test_prompt_secret_asks_again_and_never_repeats_the_answer() {
|
|
||||||
run_lib $'short\n\nlongenoughtoken1\n' \
|
|
||||||
'prompt_secret "Gitea access token" is_valid_token "needs 8 characters"; echo "[$REPLY]"'
|
|
||||||
assert_status "valid answer found" 0 "$STATUS"
|
|
||||||
assert_eq "valid answer returned" "[longenoughtoken1]" "$OUT"
|
|
||||||
assert_contains "told why" "$ERR" "invalid Gitea access token: needs 8 characters"
|
|
||||||
assert_not_contains "refused answer not repeated" "$ERR" "short"
|
|
||||||
assert_contains "says the input is hidden" "$ERR" "(input is hidden)"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_prompt_secret_stops_when_input_ends() {
|
|
||||||
run_lib "" 'prompt_secret "Gitea access token" is_valid_token "x" </dev/null'
|
|
||||||
assert_status "end of input" 1 "$STATUS"
|
|
||||||
assert_contains "message names the credential" "$ERR" "no input available for 'Gitea access token'"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ------------------------------------------------------ collect_credentials
|
|
||||||
|
|
||||||
test_collect_credentials_asks_only_what_is_missing() {
|
|
||||||
run_lib "$FAKE_GITHUB_PAT${NL}octo-user$NL" \
|
|
||||||
'CREDENTIALS[GITEA_TOKEN]=giteaFAKEtoken1234567890
|
|
||||||
collect_credentials GITEA_TOKEN GITHUB_PAT GITHUB_USER
|
|
||||||
printf "%s|%s\n" "${CREDENTIALS[GITHUB_USER]}" "${#SECRET_VALUES[@]}"'
|
|
||||||
assert_status "asked" 0 "$STATUS"
|
|
||||||
assert_eq "account name kept, one secret registered" "octo-user|1" "$OUT"
|
|
||||||
assert_contains "GitHub token asked" "$ERR" "GitHub personal access token"
|
|
||||||
assert_contains "account asked" "$ERR" "GitHub account name"
|
|
||||||
assert_not_contains "Gitea token not asked" "$ERR" "Gitea access token"
|
|
||||||
assert_not_contains "no token shown" "$ERR$OUT" "$FAKE_GITHUB_PAT"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_a_token_that_is_asked_is_registered_as_a_secret() {
|
|
||||||
run_lib "$FAKE_GITEA_TOKEN$NL" \
|
|
||||||
'collect_credentials GITEA_TOKEN
|
|
||||||
warn "the token is giteaFAKEtoken1234567890 here"'
|
|
||||||
assert_status "asked" 0 "$STATUS"
|
|
||||||
assert_not_contains "redacted in later messages" "$ERR" "$FAKE_GITEA_TOKEN"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_an_empty_value_in_env_counts_as_not_provided() {
|
|
||||||
printf 'GITEA_TOKEN=\nGITHUB_USER=\n' >"$WORK/e.env"
|
|
||||||
run_lib "$FAKE_GITEA_TOKEN$NL" \
|
|
||||||
'parse_env_file "'"$WORK"'/e.env" CREDENTIAL_KEYS CREDENTIALS
|
|
||||||
validate_credentials
|
|
||||||
collect_credentials GITEA_TOKEN
|
|
||||||
echo asked-ok'
|
|
||||||
assert_status "empty value tolerated" 0 "$STATUS"
|
|
||||||
assert_contains "asked instead" "$ERR" "Gitea access token"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_validate_credentials_no_longer_requires_any() {
|
|
||||||
printf '# nothing\n' >"$WORK/e.env"
|
|
||||||
run_lib "" 'parse_env_file "'"$WORK"'/e.env" CREDENTIAL_KEYS CREDENTIALS
|
|
||||||
validate_credentials
|
|
||||||
echo fine'
|
|
||||||
assert_status "no credential required" 0 "$STATUS"
|
|
||||||
assert_eq "no error" "fine" "$OUT"
|
|
||||||
printf 'GITEA_TOKEN=short\n' >"$WORK/e.env"
|
|
||||||
run_lib "" 'parse_env_file "'"$WORK"'/e.env" CREDENTIAL_KEYS CREDENTIALS
|
|
||||||
validate_credentials'
|
|
||||||
assert_status "a provided bad token is still refused" 1 "$STATUS"
|
|
||||||
assert_contains "named" "$ERR" "GITEA_TOKEN"
|
|
||||||
}
|
|
||||||
|
|
||||||
# --------------------------------------------------------------- the run
|
|
||||||
|
|
||||||
test_env_is_optional_and_the_token_is_asked_without_echo() {
|
|
||||||
setup_hosts
|
|
||||||
without_env
|
|
||||||
run_dry_cred "$FAKE_GITEA_TOKEN$NL$ANSWERS_GITEA_ONLY"
|
|
||||||
assert_status "dry run without .env" 0 "$STATUS"
|
|
||||||
assert_contains "token asked" "$ERR" "Gitea access token (input is hidden)"
|
|
||||||
assert_contains "plan printed" "$OUT" "Plan:"
|
|
||||||
assert_not_contains "token not shown" "$OUT$ERR" "$FAKE_GITEA_TOKEN"
|
|
||||||
assert_not_contains "only reads" "$(calls)" "POST"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_a_provided_credential_is_not_asked() {
|
|
||||||
setup_hosts
|
|
||||||
run_dry_cred "$ANSWERS_GITHUB"
|
|
||||||
assert_status "all provided" 0 "$STATUS"
|
|
||||||
assert_not_contains "no token prompt" "$ERR" "(input is hidden)"
|
|
||||||
assert_not_contains "no account prompt" "$ERR" "GitHub account name"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_github_credentials_are_asked_only_when_github_is_chosen() {
|
|
||||||
setup_hosts
|
|
||||||
printf 'GITEA_TOKEN=%s\n' "$FAKE_GITEA_TOKEN" >"$WORK/.env"
|
|
||||||
run_dry_cred "$ANSWERS_GITEA_ONLY"
|
|
||||||
assert_status "Gitea only" 0 "$STATUS"
|
|
||||||
assert_not_contains "no GitHub token asked" "$ERR" "GitHub personal access token"
|
|
||||||
assert_not_contains "no GitHub account asked" "$ERR" "GitHub account name"
|
|
||||||
run_dry_cred "$ANSWERS_GITHUB$FAKE_GITHUB_PAT${NL}octo-user$NL"
|
|
||||||
assert_status "GitHub chosen" 0 "$STATUS"
|
|
||||||
assert_contains "GitHub token asked" "$ERR" "GitHub personal access token (input is hidden)"
|
|
||||||
assert_contains "GitHub account asked" "$ERR" "GitHub account name"
|
|
||||||
assert_not_contains "token not shown" "$OUT$ERR" "$FAKE_GITHUB_PAT"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_an_invalid_asked_value_is_asked_again_and_never_shown() {
|
|
||||||
setup_hosts
|
|
||||||
without_env
|
|
||||||
run_dry_cred "bad token${NL}$FAKE_GITEA_TOKEN$NL$ANSWERS_GITEA_ONLY"
|
|
||||||
assert_status "second answer accepted" 0 "$STATUS"
|
|
||||||
assert_contains "told it is invalid" "$ERR" "invalid Gitea access token"
|
|
||||||
assert_not_contains "refused value not shown" "$ERR$OUT" "bad token"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_input_that_ends_stops_before_any_request() {
|
|
||||||
setup_hosts
|
|
||||||
without_env
|
|
||||||
run_dry_cred ""
|
|
||||||
assert_status "stopped" 1 "$STATUS"
|
|
||||||
assert_contains "key named" "$ERR" "no input available for 'Gitea access token'"
|
|
||||||
assert_eq "no request made" "" "$(calls)"
|
|
||||||
assert_not_contains "no creation report" "$OUT" "This is what exists now"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_asked_tokens_do_not_leak_under_bash_x() {
|
|
||||||
setup_hosts
|
|
||||||
without_env
|
|
||||||
STATUS=0
|
|
||||||
PATH="$WORK/bin:$PATH" STUB_DIR="$WORK" TMPDIR="$WORK/tmp" "$BASH" -x "$SCRIPT" \
|
|
||||||
--config "$WORK/config.env" --env "$WORK/.env" <<<"$(credentials_input)" \
|
|
||||||
>"$WORK/out.txt" 2>"$WORK/err.txt" || STATUS=$?
|
|
||||||
assert_status "run under bash -x" 0 "$STATUS"
|
|
||||||
assert_not_contains "no Gitea token in the trace" "$(cat "$WORK/err.txt" "$WORK/out.txt")" "$FAKE_GITEA_TOKEN"
|
|
||||||
assert_not_contains "no GitHub token in the trace" "$(cat "$WORK/err.txt" "$WORK/out.txt")" "$FAKE_GITHUB_PAT"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ---------------------------------------------------------- the project .env
|
|
||||||
|
|
||||||
test_the_dry_run_names_the_env_step_and_writes_nothing() {
|
|
||||||
setup_hosts
|
|
||||||
run_dry_cred "$ANSWERS_GITHUB"
|
|
||||||
assert_contains "plan line" "$OUT" "Project .env : you are asked whether to create it (GITEA_TOKEN GITHUB_PAT GITHUB_USER)"
|
|
||||||
assert_file_missing "no .env" "$WORK/my-app/.env"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_the_project_env_is_not_created_without_a_yes() {
|
|
||||||
setup_hosts
|
|
||||||
run_apply_cred "${ANSWERS_GITHUB}y$NL$NL"
|
|
||||||
assert_status "run" 0 "$STATUS"
|
|
||||||
assert_file_missing "default is no" "$WORK/my-app/.env"
|
|
||||||
assert_contains "reported" "$OUT" "Project .env : skipped (you declined)"
|
|
||||||
setup_hosts
|
|
||||||
run_apply_cred "${ANSWERS_GITHUB}y${NL}n$NL"
|
|
||||||
assert_file_missing "explicit no" "$WORK/my-app/.env"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_the_project_env_holds_only_the_needed_keys_and_is_private() {
|
|
||||||
setup_hosts
|
|
||||||
run_apply_cred "${ANSWERS_GITHUB}y${NL}y$NL"
|
|
||||||
assert_status "run" 0 "$STATUS"
|
|
||||||
assert_file_exists ".env created" "$WORK/my-app/.env"
|
|
||||||
assert_eq "exactly the needed keys" "GITEA_TOKEN=$FAKE_GITEA_TOKEN${NL}GITHUB_PAT=$FAKE_GITHUB_PAT${NL}GITHUB_USER=octo-user" "$(cat "$WORK/my-app/.env")"
|
|
||||||
assert_eq "owner-only" "$(env_mode "$WORK/my-app/.env")" "$([[ -z "$(env_mode "$WORK/my-app/.env")" ]] || echo 600)"
|
|
||||||
assert_contains "reported with the keys, not the values" "$OUT" "Project .env : created (GITEA_TOKEN GITHUB_PAT GITHUB_USER;"
|
|
||||||
assert_not_contains "no token in the output" "$OUT$ERR" "$FAKE_GITEA_TOKEN"
|
|
||||||
assert_not_contains "no GitHub token in the output" "$OUT$ERR" "$FAKE_GITHUB_PAT"
|
|
||||||
# Git ignores it without any tracked file changing.
|
|
||||||
check
|
|
||||||
if ! git -C "$WORK/my-app" check-ignore -q -- .env; then
|
|
||||||
fail ".env is not ignored by git"
|
|
||||||
fi
|
|
||||||
assert_not_contains "not listed by git status" "$(git -C "$WORK/my-app" status --porcelain)" ".env"
|
|
||||||
assert_contains "excluded locally" "$(cat "$WORK/my-app/.git/info/exclude")" ".env"
|
|
||||||
check
|
|
||||||
if [[ -e $WORK/my-app/.gitignore ]]; then
|
|
||||||
fail "a .gitignore was written; only .git/info/exclude may change"
|
|
||||||
fi
|
|
||||||
# No temporary file is left behind.
|
|
||||||
assert_eq "no leftover file" "" "$(find "$WORK/my-app" -maxdepth 1 -name '.env.*' -print)"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_the_project_env_without_github_holds_only_the_gitea_token() {
|
|
||||||
setup_hosts
|
|
||||||
run_apply_cred "${ANSWERS_GITEA_ONLY}y${NL}y$NL"
|
|
||||||
assert_status "run" 0 "$STATUS"
|
|
||||||
assert_eq "one key" "GITEA_TOKEN=$FAKE_GITEA_TOKEN" "$(cat "$WORK/my-app/.env")"
|
|
||||||
assert_contains "reported" "$OUT" "Project .env : created (GITEA_TOKEN;"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_asked_credentials_are_what_the_project_env_holds() {
|
|
||||||
setup_hosts
|
|
||||||
without_env
|
|
||||||
run_apply_cred "$(credentials_input)${NL}y${NL}y$NL"
|
|
||||||
assert_status "run" 0 "$STATUS"
|
|
||||||
assert_eq "the asked values" "GITEA_TOKEN=$FAKE_GITEA_TOKEN${NL}GITHUB_PAT=$FAKE_GITHUB_PAT${NL}GITHUB_USER=octo-user" "$(cat "$WORK/my-app/.env")"
|
|
||||||
assert_not_contains "no token in the output" "$OUT$ERR" "$FAKE_GITEA_TOKEN"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_no_token_is_in_any_file_but_the_project_env() {
|
|
||||||
setup_hosts
|
|
||||||
without_env
|
|
||||||
run_apply_cred "$(credentials_input)${NL}y${NL}y$NL"
|
|
||||||
assert_status "run" 0 "$STATUS"
|
|
||||||
local hits
|
|
||||||
# The new project (with its .git folder), the script's temporary directory
|
|
||||||
# and its output; the stub curl's own request log is not part of the product.
|
|
||||||
hits="$(grep -rIl -F -e "$FAKE_GITEA_TOKEN" -e "$FAKE_GITHUB_PAT" "$WORK/my-app" "$WORK/tmp" "$WORK/out.txt" "$WORK/err.txt" 2>/dev/null |
|
|
||||||
grep -v -e '/my-app/\.env$' || true)"
|
|
||||||
assert_eq "only the project .env holds a token" "" "$hits"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_an_existing_env_is_kept_unless_the_maintainer_says_replace() {
|
|
||||||
setup_hosts
|
|
||||||
mkdir -p "$WORK/my-app"
|
|
||||||
printf 'keep\n' >"$WORK/my-app/.env"
|
|
||||||
run_apply_cred "${ANSWERS_GITHUB}y${NL}y${NL}y${NL}n$NL"
|
|
||||||
assert_status "declined replacing" 0 "$STATUS"
|
|
||||||
assert_eq "unchanged" "keep" "$(cat "$WORK/my-app/.env")"
|
|
||||||
assert_contains "reported" "$OUT" "Project .env : kept (the existing .env was left as it was)"
|
|
||||||
remove_workdir
|
|
||||||
new_workdir
|
|
||||||
setup_hosts
|
|
||||||
mkdir -p "$WORK/my-app"
|
|
||||||
printf 'keep\n' >"$WORK/my-app/.env"
|
|
||||||
run_apply_cred "${ANSWERS_GITHUB}y${NL}y${NL}y${NL}y$NL"
|
|
||||||
assert_status "agreed to replace" 0 "$STATUS"
|
|
||||||
assert_contains "replaced" "$(cat "$WORK/my-app/.env")" "GITEA_TOKEN=$FAKE_GITEA_TOKEN"
|
|
||||||
assert_eq "private after replacing" "$(env_mode "$WORK/my-app/.env")" "$([[ -z "$(env_mode "$WORK/my-app/.env")" ]] || echo 600)"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_a_tracked_env_is_never_written() {
|
|
||||||
mkdir -p "$WORK/p"
|
|
||||||
git -C "$WORK/p" init -q
|
|
||||||
printf 'tracked\n' >"$WORK/p/.env"
|
|
||||||
git -C "$WORK/p" add .env
|
|
||||||
git -C "$WORK/p" -c user.name=t -c user.email=t@example.test commit -q -m init
|
|
||||||
run_lib "y$NL" \
|
|
||||||
'PROJECT[directory]="'"$WORK"'/p"; PROJECT[has_github]=0
|
|
||||||
CREDENTIALS[GITEA_TOKEN]=giteaFAKEtoken1234567890
|
|
||||||
init_steps
|
|
||||||
create_env_file
|
|
||||||
echo "${STEP_STATUS["Project .env"]}"'
|
|
||||||
assert_status "run" 0 "$STATUS"
|
|
||||||
assert_eq "skipped" "skipped" "$OUT"
|
|
||||||
assert_eq "unchanged" "tracked" "$(cat "$WORK/p/.env")"
|
|
||||||
assert_contains "says why" "$(cat "$WORK/err.txt" "$WORK/out.txt")" "skipped"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_exclude_is_added_once_and_keeps_the_existing_entries() {
|
|
||||||
mkdir -p "$WORK/p"
|
|
||||||
git -C "$WORK/p" init -q
|
|
||||||
printf 'build/' >"$WORK/p/.git/info/exclude" # no trailing newline
|
|
||||||
run_lib "" \
|
|
||||||
'exclude_env_file "'"$WORK"'/p"
|
|
||||||
exclude_env_file "'"$WORK"'/p"
|
|
||||||
echo done'
|
|
||||||
assert_status "run" 0 "$STATUS"
|
|
||||||
local exclude
|
|
||||||
exclude="$(cat "$WORK/p/.git/info/exclude")"
|
|
||||||
assert_contains "old entry kept" "$exclude" "build/"
|
|
||||||
assert_eq "entry added once" "1" "$(grep -c '^\.env$' "$WORK/p/.git/info/exclude")"
|
|
||||||
assert_eq "old entry still on its own line" "1" "$(grep -c '^build/$' "$WORK/p/.git/info/exclude")"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_exclude_does_nothing_when_env_is_already_ignored() {
|
|
||||||
mkdir -p "$WORK/p"
|
|
||||||
git -C "$WORK/p" init -q
|
|
||||||
printf '.env\n' >"$WORK/p/.gitignore"
|
|
||||||
run_lib "" 'exclude_env_file "'"$WORK"'/p"; echo done'
|
|
||||||
assert_status "run" 0 "$STATUS"
|
|
||||||
assert_eq "exclude file untouched" "0" "$(grep -c '^\.env$' "$WORK/p/.git/info/exclude" || true)"
|
|
||||||
}
|
|
||||||
@@ -47,12 +47,12 @@ test_full_run_without_github() {
|
|||||||
assert_contains "plan says GitHub is not used" "$OUT" "GitHub repository : not used"
|
assert_contains "plan says GitHub is not used" "$OUT" "GitHub repository : not used"
|
||||||
}
|
}
|
||||||
|
|
||||||
test_github_chosen_without_credentials_stops_when_input_ends() {
|
test_github_chosen_without_credentials_fails() {
|
||||||
write_fixtures
|
write_fixtures
|
||||||
printf 'GITEA_TOKEN=%s\n' "$FAKE_GITEA_TOKEN" >"$WORK/.env"
|
printf 'GITEA_TOKEN=%s\n' "$FAKE_GITEA_TOKEN" >"$WORK/.env"
|
||||||
run_cli "$ANSWERS_GITHUB" --config "$WORK/config.env" --env "$WORK/.env"
|
run_cli "$ANSWERS_GITHUB" --config "$WORK/config.env" --env "$WORK/.env"
|
||||||
assert_status "missing GitHub credentials, no answer" 1 "$STATUS"
|
assert_status "missing GitHub credentials" 1 "$STATUS"
|
||||||
assert_contains "names the credential" "$ERR" "no input available for 'GitHub personal access token'"
|
assert_contains "names the key" "$ERR" "GITHUB_PAT is missing"
|
||||||
assert_not_contains "no token in the error" "$OUT$ERR" "$FAKE_GITEA_TOKEN"
|
assert_not_contains "no token in the error" "$OUT$ERR" "$FAKE_GITEA_TOKEN"
|
||||||
assert_eq "temporary files removed" "" "$(find "$WORK/tmp" -mindepth 1)"
|
assert_eq "temporary files removed" "" "$(find "$WORK/tmp" -mindepth 1)"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user