Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 64 additions & 19 deletions docs/manifest/apps.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,37 @@ See [Environment variables](/manifest/environment-variables) for detailed docume

## Commands

Override default commands for build, test, lint, and format:
Customise commands for build, test, lint, and format. Commands can be specified in three formats:

### Boolean format

Enable or disable a command:

```json
{
"commands": {
"test": false,
"build": true
}
}
```

### String format

Override the command with a simple string:

```json
{
"commands": {
"build": "go build -o bin/api ./cmd/api",
"test": "go test -race ./..."
}
}
```

### Object format

Full control with additional options:

```json
{
Expand All @@ -216,27 +246,48 @@ Override default commands for build, test, lint, and format:
"type": "golang",
"commands": {
"build": {
"run": "go build -o bin/api ./cmd/api",
"enabled": true
"command": "go build -o bin/api ./cmd/api",
"working_directory": "./cmd/api",
"timeout": "10m"
},
"test": {
"run": "go test -race ./...",
"enabled": true
"command": "go test -race ./...",
"skip_ci": false
},
"lint": {
"run": "golangci-lint run",
"enabled": true
},
"format": {
"run": "gofmt -w .",
"enabled": true
"command": "golangci-lint run"
}
}
}
]
}
```

| Field | Description | Default |
|-------|-------------|---------|
| `command` | Shell command to execute | Required |
| `working_directory` | Directory to run the command in | App's `path` |
| `skip_ci` | Skip this command in CI/CD workflows | `false` |
| `timeout` | Maximum execution time (e.g., `5m`, `1h`) | None |

### Working directory

By default, commands run in the app's `path` directory. Use `working_directory` to run commands in a different location:

```json
{
"name": "web",
"path": "apps/web",
"commands": {
"build": "pnpm build",
"test": {
"command": "pnpm test",
"working_directory": "apps/web/src"
}
}
}
```

Commands are used in generated CI/CD workflows.

## Monitoring
Expand Down Expand Up @@ -348,14 +399,8 @@ A fully configured app:
}
},
"commands": {
"build": {
"run": "pnpm build",
"enabled": true
},
"lint": {
"run": "pnpm lint",
"enabled": true
}
"build": "pnpm build",
"lint": "pnpm lint"
},
"monitoring": {
"http": true,
Expand Down
11 changes: 6 additions & 5 deletions internal/appdef/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import (
// Commands can be specified as a boolean (enable/disable), a string (command override),
// or an object (full configuration with timeout and CI settings).
type CommandSpec struct {
Name string `json:"-"`
Cmd string `json:"command,omitempty" description:"The shell command to execute (e.g., 'pnpm build')"`
SkipCI bool `json:"skip_ci,omitempty" description:"Whether to skip running this command in CI/CD pipelines"`
Timeout string `json:"timeout,omitempty" description:"Maximum execution time for the command (e.g., '5m', '1h')"`
Disabled bool `json:"-"` // Set during unmarshal
Name string `json:"-"`
Cmd string `json:"command,omitempty" description:"The shell command to execute (e.g., 'pnpm build')"`
SkipCI bool `json:"skip_ci,omitempty" description:"Whether to skip running this command in CI/CD pipelines"`
Timeout string `json:"timeout,omitempty" description:"Maximum execution time for the command (e.g., '5m', '1h')"`
WorkingDirectory string `json:"working_directory,omitempty" description:"Working directory for the command (defaults to app path if not specified)"`
Disabled bool `json:"-"` // Set during unmarshal
}

// Ensure CommandSpec implements jsonschema.OneOfExposer
Expand Down
8 changes: 8 additions & 0 deletions internal/appdef/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ func TestCommandSpecUnmarshalJSON(t *testing.T) {
input: []byte(`{"command":"run tests","skip_ci":true,"timeout":"5m"}`),
want: CommandSpec{Cmd: "run tests", SkipCI: true, Timeout: "5m"},
},
"Full Object with WorkingDirectory": {
input: []byte(`{"command":"run tests","skip_ci":true,"timeout":"5m","working_directory":"./subdir"}`),
want: CommandSpec{Cmd: "run tests", SkipCI: true, Timeout: "5m", WorkingDirectory: "./subdir"},
},
"Object with only WorkingDirectory": {
input: []byte(`{"command":"pnpm build","working_directory":"./packages/core"}`),
want: CommandSpec{Cmd: "pnpm build", WorkingDirectory: "./packages/core"},
},
"Invalid JSON": {
input: []byte(`{"invalid":`),
wantErr: true,
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/infra/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (

var mtx sync.Mutex

func setup(t *testing.T, appDef *appdef.Definition, mock *mockinfra.MockManager, initErr bool) (cmdtools.CommandInput, func()) {
func setup(t *testing.T, appDef *appdef.Definition, mock *mockinfra.MockManager, initErr bool) (cmdtools.CommandInput, func()) { //nolint:unparam
t.Helper()
t.Skip("Need better DI")

Expand Down
39 changes: 25 additions & 14 deletions internal/playground/.github/dependabot.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,43 +10,54 @@ updates:
time: "04:00"
open-pull-requests-limit: 30
ignore:
# Ignore patch updates to reduce PR volume
- dependency-name: "*"
update-types: ["version-update:semver-patch"]
# Payload ecosystem is managed via 'webkit payload bump' command
# These dependencies are automatically updated from Payload's template package.json
- dependency-name: "payload"
- dependency-name: "@payloadcms/*"
- dependency-name: "@ainsleydev/payload-helper"
- dependency-name: "cross-env"
- dependency-name: "dotenv"
- dependency-name: "graphql"
- dependency-name: "next"
- dependency-name: "react"
- dependency-name: "react-dom"
- dependency-name: "sharp"
groups:
payload:
svelte:
patterns:
- "@payloadcms/*"
- "payload"
- "@ainsleydev/payload-helper"
- "svelte"
- "@sveltejs/*"
update-types:
- "minor"
- "patch"
core:
react:
patterns:
- "next"
- "react"
- "react-dom"
- "graphql"
- "sharp"
- "cross-env"
- "dotenv"
update-types:
- "minor"
- "patch"
dependencies:
patterns:
- "*"
exclude-patterns:
- "@payloadcms/*"
- "payload"
- "@ainsleydev/payload-helper"
- "svelte"
- "@sveltejs/*"
- "next"
- "react"
- "react-dom"
- "graphql"
- "sharp"
# Exclude all Payload template dependencies (managed by 'webkit payload bump')
- "payload"
- "@payloadcms/*"
- "@ainsleydev/payload-helper"
- "cross-env"
- "dotenv"
- "graphql"
- "sharp"
- package-ecosystem: "gomod"
directory: "/api"
schedule:
Expand Down
3 changes: 0 additions & 3 deletions internal/playground/.github/workflows/backup.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ jobs:
run: |
# Delete backups older than 30 days
rclone delete b2_backup:${BUCKET_NAME}${BACKUP_PATH} --min-age 30d

- name: Ping Peekaping Heartbeat Monitor
if: success()
uses: ./.github/actions/peekaping-ping
Expand Down Expand Up @@ -147,7 +146,6 @@ jobs:
- name: Verify Backup
run: |
echo "Backup completed successfully!"

- name: Ping Peekaping Heartbeat Monitor
if: success()
uses: ./.github/actions/peekaping-ping
Expand Down Expand Up @@ -210,7 +208,6 @@ jobs:
- name: Verify Backup
run: |
echo "Codebase backup completed successfully!"

- name: Ping Peekaping Heartbeat Monitor
if: success()
uses: ./.github/actions/peekaping-ping
Expand Down
9 changes: 5 additions & 4 deletions internal/playground/.github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ jobs:
matrix:
service:
- name: cms
context: ./cms
context: cms
dockerfile: ./cms/Dockerfile
- name: web
context: ./web
context: web
dockerfile: ./web/Dockerfile
- name: api
context: ./api
context: api
dockerfile: ./api/Dockerfile
steps:
- name: Checkout Repository
Expand Down Expand Up @@ -373,6 +373,7 @@ jobs:
-e docker_image=${{ github.event.repository.name }}-cms
-e docker_image_tag=sha-${{ steps.determine_sha.outputs.sha }}
-e docker_port=3000
-e health_check_path=/
-e enable_https=true
-e admin_email=hello@ainsley.dev
-e env_file_source_path=/tmp/cms.env
Expand Down Expand Up @@ -408,7 +409,7 @@ jobs:
# Notify Slack on release failure
notify-failure:
runs-on: ubuntu-latest
needs: [build-and-push,deploy-vm-cms,deploy-app-web]
needs: [build-and-push, deploy-vm-cms, deploy-app-web]
if: failure()
steps:
- name: Checkout Repository
Expand Down
24 changes: 12 additions & 12 deletions internal/playground/.webkit/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"version": "v0.7.4",
"generated_at": "2025-11-24T19:50:05.385737Z",
"version": "v0.9.8",
"generated_at": "2025-12-15T09:17:57.472267068Z",
"files": {
"./turbo.json": {
"path": "./turbo.json",
Expand Down Expand Up @@ -86,9 +86,9 @@
"path": ".github/dependabot.yaml",
"generator": "files:GitSettings",
"source": "project",
"hash": "f1ce4b0dcad7973e83ce319052e08282eb6c9ee839deb93ccf2e8f07d1f72df1",
"hash": "dd5045db25b3ea4c4c94e073479c2d7f00d4d380ddddba25ab47cae2c26315ca",
"scaffolded": false,
"generated_at": "2025-11-24T19:50:05.376785Z"
"generated_at": "2025-12-15T09:16:05.705711066Z"
},
".github/settings.yml": {
"path": ".github/settings.yml",
Expand All @@ -102,25 +102,25 @@
"path": ".github/workflows/backup.yaml",
"generator": "cicd:BackupWorkflow",
"source": "resource:store",
"hash": "25dabcd4231f662b2267b92e631700d9c0286b9088f59b05102cc99f55a84de6",
"hash": "1014a62481cb9cbc4bcbe0aa67777ba953c0157670269ca6793b2fe51ad21914",
"scaffolded": false,
"generated_at": "2025-11-24T19:50:05.381915Z"
"generated_at": "2025-12-15T09:16:05.711894006Z"
},
".github/workflows/pr.yaml": {
"path": ".github/workflows/pr.yaml",
"generator": "cicd:PR",
"source": "project",
"hash": "7206cb778668a8df1bc8b330ba887bacc5874109f72f231b1e72f96e7b17e1fd",
"hash": "3d498e017141afd45db9159a9b82d229ccc2130ad4f46893ccc745a9d7188b96",
"scaffolded": false,
"generated_at": "2025-11-24T19:50:05.380818Z"
"generated_at": "2025-12-15T09:17:57.461325727Z"
},
".github/workflows/release.yaml": {
"path": ".github/workflows/release.yaml",
"generator": "cicd:ReleaseWorkflow",
"source": "app:api",
"hash": "8095399f3678fb40b987cc3bd542f09adad52eb00e93ba44a7d41af52532213d",
"hash": "a75be6c0a208ec49fcae66e2a2763908ed4f95f9c6cfdeb2340a0e7eb85bb07d",
"scaffolded": false,
"generated_at": "2025-11-20T13:42:31.968943Z"
"generated_at": "2025-12-15T09:16:05.710992465Z"
},
".github/workflows/server-maintenance.yaml": {
"path": ".github/workflows/server-maintenance.yaml",
Expand Down Expand Up @@ -166,9 +166,9 @@
"path": "README.md",
"generator": "docs:Readme",
"source": "project",
"hash": "f1c694886a54e9aca154614baa293b0740092ea8220b2c396a21777b54846955",
"hash": "e8f101a3b06b3221567b3a49f44544c66a3efa26c53df7f749d7336c1e81160a",
"scaffolded": false,
"generated_at": "2025-11-24T19:50:05.383946Z"
"generated_at": "2025-12-15T09:16:05.717099432Z"
},
"api/.env": {
"path": "api/.env",
Expand Down
Loading
Loading