Add .sc.yml config and infer app/deployment from the checkout #7

Merged
geusebio merged 1 commit from feature/deployment-per-branch into main 2026-08-03 15:46:28 +00:00
Owner

Every sc parameter can now be set four ways, resolving flag > environment > .sc.yml > detected default — and with none of them set, sc deploy works bare in a git checkout.

.sc.yml

The per-project file: the nearest one searching upwards from the working directory (so it works from a subdirectory), or --config <path> for a specific one. .sc.yaml is accepted too; both in one directory is an error rather than a coin toss.

app: example-app
deployment: staging
endpoint: http://127.0.0.1:7500
token: someonescomputer_…
files: [compose.yaml, compose.override.yaml]
dry-run: false
no-browser: false

Every key is a flag name, and unknown keys are rejected — a typo like endpont: should fail loudly, not deploy somewhere unexpected. Relative files entries resolve against the file, not the working directory. files accepts a bare string as well as a list, and file: is an accepted alias.

Credentials follow the same chain: --token > $SC_TOKEN > token: in .sc.yml > the sc login store. A token in the project file sits inside the build context and ships with the upload unless .dockerignore excludes it, so sc warns when it uses one.

Detected defaults

Parameter Detected from Example
app the git repository's directory name, slugified ~/code/My Cool Appmy-cool-app
deployment the current branch, slugified feature/New UIfeature-new-ui

The repository root is used, so services/api/ gives the same answer as the root. Git is read directly rather than shelled out to — sc is a static binary and shouldn't need git on PATH — including a worktree's or submodule's .git file. A detached HEAD yields no deployment name (a commit id makes a poor one), and outside a checkout the working directory's name is used.

--app is no longer a required flag, since it can now come from three other places. A run with nothing to infer from says so rather than printing usage.

Deployment per branch

The resolved name goes on the wire as manifest.deployment. The server side (platform PR) treats it as part of the bundle's identity, so the same tree pushed from a second branch is a new revision rather than a 409 duplicate; re-pushing the same tree on the same branch still conflicts as before.

Verification

go vet ./... and go test ./... are green. New tests cover the precedence chain for every parameter (including all four credential sources), .sc.yml discovery/strictness/aliases, and directory/branch detection through both a .git directory and a worktree's .git file.

Run against the local stack (:7650), the same tree under two names:

$ sc deploy --app test-webserver --deployment main
  build app              .  sha256:74b67f1cce71  (17.5 KiB)
Deployment 019fc3db-c7b2-… created — seq 2, status pending

$ sc deploy --app test-webserver --deployment feature-new-ui
  build app              .  sha256:74b67f1cce71  (17.5 KiB)   ← identical context
Deployment 019fc3db-c827-… created — seq 3, status pending

$ sc deploy --app test-webserver --deployment main
sc: bundle upload failed: 409 Conflict: An identical bundle has already been deployed.

And bare, with no arguments at all, in a checkout:

$ sc deploy --dry-run
Application:  my-cool-app  (from directory)
Deployment:   feature-new-ui  (from branch)

Notes for the reviewer

  • New dependency: gopkg.in/yaml.v3 (promoted from indirect).
  • client.UploadBundle gained a deployment parameter — it is omitted from the JSON when empty, so an unnamed upload is byte-identical to before.
  • Needs the platform PR for the name to be stored; without it the server ignores the field and behaviour is unchanged.
Every `sc` parameter can now be set four ways, resolving **flag > environment > `.sc.yml` > detected default** — and with none of them set, `sc deploy` works bare in a git checkout. ## `.sc.yml` The per-project file: the nearest one searching upwards from the working directory (so it works from a subdirectory), or `--config <path>` for a specific one. `.sc.yaml` is accepted too; both in one directory is an error rather than a coin toss. ```yaml app: example-app deployment: staging endpoint: http://127.0.0.1:7500 token: someonescomputer_… files: [compose.yaml, compose.override.yaml] dry-run: false no-browser: false ``` Every key is a flag name, and **unknown keys are rejected** — a typo like `endpont:` should fail loudly, not deploy somewhere unexpected. Relative `files` entries resolve against the file, not the working directory. `files` accepts a bare string as well as a list, and `file:` is an accepted alias. **Credentials** follow the same chain: `--token` > `$SC_TOKEN` > `token:` in `.sc.yml` > the `sc login` store. A token in the project file sits inside the build context and ships with the upload unless `.dockerignore` excludes it, so `sc` warns when it uses one. ## Detected defaults | Parameter | Detected from | Example | | --- | --- | --- | | `app` | the git repository's directory name, slugified | `~/code/My Cool App` → `my-cool-app` | | `deployment` | the current branch, slugified | `feature/New UI` → `feature-new-ui` | The repository *root* is used, so `services/api/` gives the same answer as the root. Git is read directly rather than shelled out to — `sc` is a static binary and shouldn't need git on `PATH` — including a worktree's or submodule's `.git` *file*. A detached HEAD yields no deployment name (a commit id makes a poor one), and outside a checkout the working directory's name is used. `--app` is no longer a required flag, since it can now come from three other places. A run with nothing to infer from says so rather than printing usage. ## Deployment per branch The resolved name goes on the wire as `manifest.deployment`. The server side (platform PR) treats it as part of the bundle's identity, so **the same tree pushed from a second branch is a new revision rather than a 409 duplicate**; re-pushing the same tree on the same branch still conflicts as before. ## Verification `go vet ./...` and `go test ./...` are green. New tests cover the precedence chain for every parameter (including all four credential sources), `.sc.yml` discovery/strictness/aliases, and directory/branch detection through both a `.git` directory and a worktree's `.git` file. Run against the local stack (`:7650`), the same tree under two names: ``` $ sc deploy --app test-webserver --deployment main build app . sha256:74b67f1cce71 (17.5 KiB) Deployment 019fc3db-c7b2-… created — seq 2, status pending $ sc deploy --app test-webserver --deployment feature-new-ui build app . sha256:74b67f1cce71 (17.5 KiB) ← identical context Deployment 019fc3db-c827-… created — seq 3, status pending $ sc deploy --app test-webserver --deployment main sc: bundle upload failed: 409 Conflict: An identical bundle has already been deployed. ``` And bare, with no arguments at all, in a checkout: ``` $ sc deploy --dry-run Application: my-cool-app (from directory) Deployment: feature-new-ui (from branch) ``` ## Notes for the reviewer - New dependency: `gopkg.in/yaml.v3` (promoted from indirect). - `client.UploadBundle` gained a `deployment` parameter — it is omitted from the JSON when empty, so an unnamed upload is byte-identical to before. - Needs the platform PR for the name to be stored; without it the server ignores the field and behaviour is unchanged.
Add .sc.yml config and infer app/deployment from the checkout
All checks were successful
CI / build (pull_request) Successful in 5m46s
2242cddcea
Every parameter can now be set four ways, resolving flag > environment >
.sc.yml > detected default. That includes credentials: --token, $SC_TOKEN,
`token:` in .sc.yml, then the `sc login` store.

.sc.yml is the per-project file — the nearest one searching upwards from the
working directory, so it works from a subdirectory; --config points at a
specific file. Keys are flag names and unknown keys are rejected, so a typo
fails loudly instead of deploying somewhere unexpected. Relative `files`
entries resolve against the file rather than the working directory.

With nothing configured at all, `sc deploy` now works bare in a git repo:
the application slug comes from the repository's directory name and the
deployment name from the current branch, both slugified. Git is read directly
rather than shelled out to — sc is a static binary and shouldn't need git on
PATH — including a worktree's or submodule's `.git` file. A detached HEAD
yields no deployment name; a commit id makes a poor one.

The resolved deployment name goes on the wire as manifest.deployment. The
default is therefore a deployment per branch, and the server treats the name
as part of the bundle's identity, so the same tree pushed from a second
branch is a new revision rather than a duplicate.

--app is no longer a required flag, since it can now come from three other
places; a run with nothing to infer from says so instead of printing usage.
Sign in to join this conversation.
No reviewers
No labels
in-progress
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Grey.ooo/someones.computer_agent!7
No description provided.