Plan the default configuration files: working folder first, then the checkout

- --config and --env, else ./config.env and ./.env, else the checkout's
- Files named before any request; a file from the working folder needs a yes
- UC-002, US-002, MIL-007 criteria 9 and 10, models and contracts updated
- Review record RC-029
This commit is contained in:
2026-10-07 12:42:05 +08:00
parent 88b4e5ce6c
commit 0ab50068bf
15 changed files with 201 additions and 69 deletions
+19 -6
View File
@@ -10,6 +10,7 @@
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-07 | Proposed | Jens Tirsvad Nielsen | S02 | Initial version | [1cd27f7] |
| 2026-10-07 | Proposed | Jens Tirsvad Nielsen | S02 | Default configuration files: --config and --env, else ./config.env and ./.env in the working folder, else the checkout's | pending |
---
@@ -24,6 +25,7 @@ Covers [UC-002]. Adds the classes that start the script through a command link.
class Launcher {
+resolveCheckout(invocation : Path) : Checkout
+currentFolder() : WorkingFolder
+locateConfigFiles(configPath : Path [0..1], envPath : Path [0..1], checkout : Checkout, workingFolder : WorkingFolder) : ConfigFiles
+startFromWorkingFolder(configPath : Path [0..1], envPath : Path [0..1]) : PromptSet
}
class Checkout {
@@ -33,14 +35,22 @@ class Checkout {
}
class WorkingFolder {
-path : Path
+configFile() : Path [0..1]
+envFile() : Path [0..1]
}
class ConfigFiles {
-configFile : Path
-envFile : Path
}
class ProjectCreator {
+startProjectCreation(checkout : Checkout, workingFolder : WorkingFolder, configPath : Path [0..1], envPath : Path [0..1]) : PromptSet
+startProjectCreation(workingFolder : WorkingFolder, configFiles : ConfigFiles) : PromptSet
}
class Run
Launcher "1" --> "1" ProjectCreator : starts
Launcher ..> Checkout : creates
Launcher ..> WorkingFolder : creates
Launcher ..> ConfigFiles : creates
Run "1" *-- "1" ConfigFiles
Run "1" *-- "1" Checkout
Run "1" *-- "1" WorkingFolder
@enduml
@@ -50,9 +60,10 @@ Run "1" *-- "1" WorkingFolder
| Class | Refines (Domain Model concept) | Responsibility | Attributes | Operations |
| --- | --- | --- | --- | --- |
| `Launcher` | Command Link (the object that follows it) | Follows the command link to the checkout, takes the folder the Maintainer stands in, and starts the run. | none | `resolveCheckout`, `currentFolder`, `startFromWorkingFolder` |
| `Launcher` | Command Link (the object that follows it) | Follows the command link to the checkout, takes the folder the Maintainer stands in, chooses the two configuration files, and starts the run. | none | `resolveCheckout`, `currentFolder`, `locateConfigFiles`, `startFromWorkingFolder` |
| `Checkout` | Checkout | Names the folder that holds the script's own files and the default `config.env` and `.env`. | `path` | `configFile`, `envFile` |
| `WorkingFolder` | Working Folder | Names the base of the default directory of the new project. | `path` | none |
| `WorkingFolder` | Working Folder | Names the base of the default directory of the new project and the files it may hold. | `path` | `configFile`, `envFile` |
| `ConfigFiles` | none (system concept of [OC-002]) | Carries the two files chosen for the `Configuration`. | `configFile`, `envFile` | none |
The concept Command Link has no class: it is a link the Maintainer makes with the shell, and the system only follows it.
@@ -63,8 +74,10 @@ The concept Command Link has no class: it is a link the Maintainer makes with th
| `Launcher.startFromWorkingFolder(configPath, envPath) : PromptSet` | [SD-002] `startFromWorkingFolder`; P1, P6 |
| `Launcher.resolveCheckout(invocation) : Checkout` | [SD-002] `resolveCheckout(invocation)`; P2 |
| `Launcher.currentFolder() : WorkingFolder` | [SD-002] `currentFolder()`; P3 |
| `Checkout.configFile() : Path`, `Checkout.envFile() : Path` | [SD-002] `startProjectCreation`; P5 |
| `ProjectCreator.startProjectCreation(checkout, workingFolder, configPath, envPath) : PromptSet` | [SD-002] `startProjectCreation`; P4, P5, P6. Replaces the signature of [DCD-001] by adding `checkout`, `workingFolder`, `configPath` and `envPath` |
| `Launcher.locateConfigFiles(configPath, envPath, checkout, workingFolder) : ConfigFiles` | [SD-002] `locateConfigFiles(...)`; P5 |
| `WorkingFolder.configFile() : Path [0..1]`, `WorkingFolder.envFile() : Path [0..1]` | [SD-002] `locateConfigFiles`; P5 |
| `Checkout.configFile() : Path`, `Checkout.envFile() : Path` | [SD-002] `locateConfigFiles`; P5 |
| `ProjectCreator.startProjectCreation(workingFolder, configFiles) : PromptSet` | [SD-002] `startProjectCreation`; P4, P6, P7. Replaces the signature of [DCD-001] by adding `workingFolder` and `configFiles` |
## Pattern Annotations
@@ -75,7 +88,7 @@ The concept Command Link has no class: it is a link the Maintainer makes with th
## Dependency Check
`Launcher` depends on `ProjectCreator`, `Checkout` and `WorkingFolder`; none of them depends on `Launcher`, so no cycle is added.
`Launcher` depends on `ProjectCreator`, `Checkout`, `WorkingFolder` and `ConfigFiles`; none of them depends on `Launcher`, so no cycle is added.
---
+4 -1
View File
@@ -10,6 +10,7 @@
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-07 | Proposed | Jens Tirsvad Nielsen | S02 | Initial version | [1cd27f7] |
| 2026-10-07 | Proposed | Jens Tirsvad Nielsen | S02 | Default configuration files: --config and --env, else ./config.env and ./.env in the working folder, else the checkout's | pending |
---
@@ -46,6 +47,7 @@ Maintainer "1" --> "0..*" CommandLink : makes
CommandLink "0..*" --> "1" Checkout : leads to
Maintainer "1" --> "1" WorkingFolder : starts the script in
Checkout "1" --> "1" Configuration : holds by default
WorkingFolder "1" --> "0..1" Configuration : may hold
WorkingFolder "1" --> "0..*" LocalProject : is the base of
@enduml
```
@@ -56,7 +58,7 @@ WorkingFolder "1" --> "0..*" LocalProject : is the base of
| --- | --- | --- | --- |
| Command Link | A name in a folder on the shell's search path that leads to the script in the checkout | name, folder | [UC-002] step 1 "command link" |
| Checkout | The folder that holds RepoFoundry: the script, its own files and by default `config.env` and `.env` | path | [UC-002] step 4 "checkout" |
| Working Folder | The folder in which the Maintainer starts the script and under which the new project is created by default | path | [UC-002] step 2 "working folder" |
| Working Folder | The folder in which the Maintainer starts the script, under which the new project is created by default, and which may hold its own `config.env` and `.env` | path | [UC-002] step 2 "working folder" |
## Association Table
@@ -66,6 +68,7 @@ WorkingFolder "1" --> "0..*" LocalProject : is the base of
| Command Link | leads to | Checkout | 0..* to 1 |
| Maintainer | starts the script in | Working Folder | 1 to 1 |
| Checkout | holds by default | Configuration | 1 to 1 |
| Working Folder | may hold | Configuration | 1 to 0..1 |
| Working Folder | is the base of | Local Project | 1 to 0..* |
## Generalizations
+9 -6
View File
@@ -10,10 +10,11 @@
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-07 | Proposed | Jens Tirsvad Nielsen | S02 | Initial version | [1cd27f7] |
| 2026-10-07 | Proposed | Jens Tirsvad Nielsen | S02 | Default configuration files: --config and --env, else ./config.env and ./.env in the working folder, else the checkout's | pending |
---
Concepts below use the IT terms of [DICT-001] for the PO concepts of [DM-003]. `Run` and `PromptSet` are the system concepts of [OC-001]. The operation `provideProjectDetails` is the one of [OC-001]; the only change is the base of its default `directory`, stated in P4.
Concepts below use the IT terms of [DICT-001] for the PO concepts of [DM-003]. `Run` and `PromptSet` are the system concepts of [OC-001]; `ConfigFiles` is a system concept of this contract: the two files chosen for the `Configuration`. The operation `provideProjectDetails` is the one of [OC-001]; the only change is the base of its default `directory`, stated in P4.
## Contract: startFromWorkingFolder
@@ -21,7 +22,7 @@ Concepts below use the IT terms of [DICT-001] for the PO concepts of [DM-003]. `
| --- | --- |
| Operation | `startFromWorkingFolder(configPath: Path [0..1], envPath: Path [0..1]): PromptSet` |
| Traces to | `startFromWorkingFolder` in [SSD-002] |
| Concepts | Run, CommandLink, Checkout, WorkingFolder, Configuration |
| Concepts | Run, CommandLink, Checkout, WorkingFolder, ConfigFiles, Configuration |
**Preconditions**
@@ -34,16 +35,18 @@ Concepts below use the IT terms of [DICT-001] for the PO concepts of [DM-003]. `
- P2. A `Checkout` instance was created and associated with the `Run`, with `path` set to the folder that holds the script's own files, reached through the `CommandLink`, however many links lie between them.
- P3. A `WorkingFolder` instance was created and associated with the `Run`, with `path` set to the folder in which the Maintainer started the script. It was not changed by following the `CommandLink`.
- P4. The default of `directory` in the `PromptSet` is `./<name>` under the `WorkingFolder`, never under the `Checkout`.
- P5. A `Configuration` instance was created and associated with the `Run` from `configPath`, or from `config.env` in the `Checkout` when `configPath` is absent, and from `envPath`, or from `.env` in the `Checkout` when `envPath` is absent; the validation of [OC-001] `startProjectCreation` P2 and P3 applies.
- P6. The `Run` was associated with a `PromptSet` that is returned.
- P5. A `ConfigFiles` instance was created and associated with the `Run`. Its `configFile` is `configPath` when given, otherwise `config.env` in the `WorkingFolder` when it exists, otherwise `config.env` in the `Checkout`; its `envFile` is chosen in the same way from `envPath` and `.env`. Each file is chosen on its own. The paths are named in the output before any request to a host.
- P6. A `Configuration` instance was created and associated with the `Run` from the `ConfigFiles`; the validation of [OC-001] `startProjectCreation` P2 and P3 applies.
- P7. The `Run` was associated with a `PromptSet` that is returned.
**Exceptions**
| Condition (failing precondition) | Outcome |
| --- | --- |
| The `Checkout`'s own files are not found from the link target | The `Run` ends with an error naming the folder it looked in; nothing was changed |
| `config.env` or `.env` is not found in the `Checkout` and no path was given (P5) | The `Run` ends with an error naming the path it looked in and the options `--config` and `--env`; nothing was changed |
| A value in `config.env` or `.env` is malformed (P5) | As in [OC-001] `startProjectCreation`: the error names the key, never its value; nothing was changed |
| `config.env` or `.env` is not named and is in neither the `WorkingFolder` nor the `Checkout` (P5) | The `Run` ends with an error naming both places it looked in and the options `--config` and `--env`; nothing was changed |
| A chosen file is in the `WorkingFolder` and the Maintainer does not confirm it (P5) | The `Run` ends before any request to a host; nothing was changed |
| A value in `config.env` or `.env` is malformed (P6) | As in [OC-001] `startProjectCreation`: the error names the key, never its value; nothing was changed |
---
+21 -11
View File
@@ -10,6 +10,7 @@
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-07 | Proposed | Jens Tirsvad Nielsen | S02 | Initial version | [1cd27f7] |
| 2026-10-07 | Proposed | Jens Tirsvad Nielsen | S02 | Default configuration files: --config and --env, else ./config.env and ./.env in the working folder, else the checkout's | pending |
---
@@ -28,6 +29,7 @@ participant ":Launcher" as L
participant ":ProjectCreator" as PC
participant ":Checkout" as CK
participant ":WorkingFolder" as WF
participant ":ConfigFiles" as CF
Maintainer -> L : startFromWorkingFolder(configPath, envPath)
activate L
@@ -37,13 +39,20 @@ L -> CK : Checkout(path)
L -> L : currentFolder()
create WF
L -> WF : WorkingFolder(path)
alt the Checkout's own files are not found
L -> L : locateConfigFiles(configPath, envPath, checkout, workingFolder)
create CF
L -> CF : ConfigFiles(configFile, envFile)
alt a chosen file is in the working folder
L -> Maintainer : confirm the files and the Gitea address
Maintainer --> L : yes or no
end
alt the Checkout's own files, or both places for a config file, are not found
L --> Maintainer : error naming the folder looked in
end
L -> PC : startProjectCreation(checkout, workingFolder, configPath, envPath)
L -> PC : startProjectCreation(workingFolder, configFiles)
activate PC
alt config.env or .env not found, or a value malformed
PC --> L : error naming the path or the key
alt a value in config.env or .env is malformed
PC --> L : error naming the key
end
PC --> L : promptSet
deactivate PC
@@ -56,9 +65,9 @@ deactivate L
| Pattern (GRASP / GoF) | Applied to | Rationale |
| --- | --- | --- |
| Information Expert | `Launcher.resolveCheckout` | The launcher knows how the script was invoked, so it is the one that can follow the command link |
| Information Expert | `Launcher.resolveCheckout`, `Launcher.locateConfigFiles` | The launcher knows how the script was invoked, so it is the one that can follow the command link |
| Controller | `Launcher` | One object takes the system operation and hands the work to `ProjectCreator`; `ProjectCreator` stays unaware of links |
| Low Coupling | `ProjectCreator` receives `checkout` and `workingFolder` as values | The use case [UC-001] runs unchanged whatever way the script was started |
| Low Coupling | `ProjectCreator` receives `workingFolder` and `configFiles` as values | The use case [UC-001] runs unchanged whatever way the script was started |
### Postcondition Coverage
@@ -67,14 +76,15 @@ deactivate L
| P1 Run | `startFromWorkingFolder` (the run starts with it) |
| P2 Checkout | `resolveCheckout(invocation)` and the creation of `Checkout` |
| P3 WorkingFolder | `currentFolder()` and the creation of `WorkingFolder` |
| P4 default directory under the WorkingFolder | `startProjectCreation(checkout, workingFolder, ...)`; the prompt default is built from `workingFolder` |
| P5 Configuration | `startProjectCreation` loads `config.env` and `.env` from `checkout` or from the given paths (`load` of [SD-001]) |
| P6 PromptSet | the returned `promptSet` |
| Exceptions: files not found; configuration not found or malformed | the two `alt` fragments |
| P4 default directory under the WorkingFolder | `startProjectCreation(workingFolder, configFiles)`; the prompt default is built from `workingFolder` |
| P5 ConfigFiles | `locateConfigFiles(...)` and the creation of `ConfigFiles`; the paths are named before any request |
| P6 Configuration | `startProjectCreation(workingFolder, configFiles)` loads the two files (`load` of [SD-001]) |
| P7 PromptSet | the returned `promptSet` |
| Exceptions: files not found, not confirmed, or malformed | the `alt` fragments |
### Responsibility Check
`Launcher` only finds the checkout and the working folder; it reads no configuration and makes no repository. `ProjectCreator` keeps every other responsibility of [SD-001].
`Launcher` only finds the checkout, the working folder and the two files; it reads no configuration and makes no repository. `ProjectCreator` keeps every other responsibility of [SD-001].
---
+3 -1
View File
@@ -10,6 +10,7 @@
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-07 | Proposed | Jens Tirsvad Nielsen | S02 | Initial version | [1cd27f7] |
| 2026-10-07 | Proposed | Jens Tirsvad Nielsen | S02 | Names the confirmation of a configuration file from the working folder as out of scope | pending |
---
@@ -37,7 +38,7 @@ S --> A : creation summary with the project's full path
| 3 to 4 | startFromWorkingFolder | configPath (optional), envPath (optional) | prompts for project details whose default directory is under the working folder | 3, 4, 5 |
| 5 | provideProjectDetails | the parameters of `provideProjectDetails` in [UC-001] | creation summary that names the full path of the new project | 5, 6 |
Failure flows (extensions 1a, 3a, 4a and 4b of [UC-002]) are out of scope for this diagram: they end the run with a message and add no system operation. `provideProjectDetails` is the operation of [UC-001] and is not repeated in [OC-002]; the only difference is the base of the default `directory`. Making the command link (step 1) and opening the shell (step 2) are done by the Maintainer outside the system, so they are not system operations.
Failure flows (extensions 1a, 3a, 4a and 4b of [UC-002]) are out of scope for this diagram: they end the run with a message and add no system operation. The confirmation of a file from the working folder (extension 4c) is a prompt from the system, out of scope as the consent questions of [SSD-001] are. `provideProjectDetails` is the operation of [UC-001] and is not repeated in [OC-002]; the only difference is the base of the default `directory`. Making the command link (step 1) and opening the shell (step 2) are done by the Maintainer outside the system, so they are not system operations.
## Lifecycle Notes
@@ -48,4 +49,5 @@ One script run, as in [UC-001]. The command link persists between runs; the syst
[UC-002]: ./uc.md
[DM-003]: ./dm.md
[OC-002]: ./oc.md
[SSD-001]: ../uc-001/ssd.md
[1cd27f7]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/1cd27f77ed844773a969210a11de0d8bb98ac98f
+9 -5
View File
@@ -10,6 +10,7 @@
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-07 | Proposed | Jens Tirsvad Nielsen | S02 | Initial version | [1cd27f7] |
| 2026-10-07 | Proposed | Jens Tirsvad Nielsen | S02 | Default configuration files: --config and --env, else ./config.env and ./.env in the working folder, else the checkout's; the files used are named and a file from the working folder is confirmed (step 4, extensions 4b and 4c, rules) | pending |
---
@@ -25,7 +26,7 @@
- S02 — starting through a link never reads or writes outside the checkout and the current folder
- S03 — the README says exactly how to make the command global
- **Preconditions:**
- The checkout of RepoFoundry exists and holds `config.env` and `.env` as described in the README, or the Maintainer points to them with `--config` and `--env`.
- The checkout of RepoFoundry exists. `config.env` and `.env` exist as described in the README in the working folder or in the checkout, or the Maintainer points to them with `--config` and `--env`.
- A folder that is on the shell's `PATH` exists and the Maintainer may write to it.
- **Postconditions (success guarantee):**
- A command link exists in a `PATH` folder and leads to the script in the checkout.
@@ -37,7 +38,7 @@
1. The Maintainer makes the script reachable by name: creates a command link in a `PATH` folder that leads to `src/create-project.sh` in the checkout (the README gives the command).
2. The Maintainer opens a shell in the folder in which the new project is to be created (the working folder).
3. The Maintainer starts the script by the name of the command link.
4. The system follows the command link to the checkout, loads its own files from there, and reads `config.env` and `.env` from the checkout, or from the files named by `--config` and `--env`.
4. The system follows the command link to the checkout, loads its own files from there, and chooses `config.env` and `.env`, each one separately: the file named by `--config` or `--env`, otherwise the one in the working folder, otherwise the one in the checkout. It names the files it will use before any request to a host.
5. The system runs [UC-001] (`<<include>>`) with the working folder as the base of the default directory of the new project.
6. The system reports a summary that names the full path of the new project.
@@ -49,8 +50,10 @@
1. The shell reports that the command cannot run; the README says how to recreate the link.
- 4a. The checkout's own files cannot be found from the link target:
1. The system stops before any change and names the folder it looked in.
- 4b. `config.env` or `.env` is not found:
1. The system stops before any change, names the path it looked in and says that `--config` and `--env` can point elsewhere.
- 4b. `config.env` or `.env` is not named, and is in neither the working folder nor the checkout:
1. The system stops before any change, names both places it looked in and says that `--config` and `--env` can point elsewhere.
- 4c. A chosen file comes from the working folder:
1. The system names the file and the Gitea address it holds and asks the Maintainer to confirm, default no, before any request to a host; on no, the system stops before any request and any change.
### Special Requirements / Business Rules
@@ -58,7 +61,8 @@
| --- | --- |
| 1 | The command link is made by the Maintainer with the shell, not by the script; the script never edits `PATH`, a shell profile or a system folder |
| 4 | The system finds its own files by following the command link, however many links lie on the way, on every supported platform |
| 4 | `config.env` and `.env` are read from the checkout, never from the working folder, unless `--config` and `--env` name them |
| 4 | `config.env` and `.env` are chosen one by one in this order: `--config` / `--env`; `./config.env` / `./.env` in the working folder; the checkout's. A project may therefore use its own `.env` with the checkout's `config.env` |
| 4 | A folder can hold a `config.env` that points the Gitea address elsewhere, and so send the token there. A file from the working folder is therefore confirmed before the first request, and every file used is named in the output |
| 5 | The base of the default directory is the working folder, never the checkout |
| 3 to 6 | Behaviour, prompts and summary are the same as when the script is started by its path from the checkout |