rampway 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +183 -0
- package/build/src/cli.d.ts +3 -0
- package/build/src/cli.d.ts.map +1 -0
- package/build/src/cli.js +104 -0
- package/build/src/cli.js.map +1 -0
- package/build/src/commands/context.d.ts +12 -0
- package/build/src/commands/context.d.ts.map +1 -0
- package/build/src/commands/context.js +16 -0
- package/build/src/commands/context.js.map +1 -0
- package/build/src/commands/deploy.d.ts +6 -0
- package/build/src/commands/deploy.d.ts.map +1 -0
- package/build/src/commands/deploy.js +14 -0
- package/build/src/commands/deploy.js.map +1 -0
- package/build/src/commands/doctor.d.ts +14 -0
- package/build/src/commands/doctor.d.ts.map +1 -0
- package/build/src/commands/doctor.js +54 -0
- package/build/src/commands/doctor.js.map +1 -0
- package/build/src/commands/init.d.ts +8 -0
- package/build/src/commands/init.d.ts.map +1 -0
- package/build/src/commands/init.js +42 -0
- package/build/src/commands/init.js.map +1 -0
- package/build/src/commands/plan.d.ts +6 -0
- package/build/src/commands/plan.d.ts.map +1 -0
- package/build/src/commands/plan.js +24 -0
- package/build/src/commands/plan.js.map +1 -0
- package/build/src/commands/releases.d.ts +27 -0
- package/build/src/commands/releases.d.ts.map +1 -0
- package/build/src/commands/releases.js +91 -0
- package/build/src/commands/releases.js.map +1 -0
- package/build/src/commands/rollback.d.ts +6 -0
- package/build/src/commands/rollback.d.ts.map +1 -0
- package/build/src/commands/rollback.js +12 -0
- package/build/src/commands/rollback.js.map +1 -0
- package/build/src/commands/rollbridge.d.ts +21 -0
- package/build/src/commands/rollbridge.d.ts.map +1 -0
- package/build/src/commands/rollbridge.js +69 -0
- package/build/src/commands/rollbridge.js.map +1 -0
- package/build/src/commands/validate.d.ts +6 -0
- package/build/src/commands/validate.d.ts.map +1 -0
- package/build/src/commands/validate.js +12 -0
- package/build/src/commands/validate.js.map +1 -0
- package/build/src/config/load-config.d.ts +10 -0
- package/build/src/config/load-config.d.ts.map +1 -0
- package/build/src/config/load-config.js +71 -0
- package/build/src/config/load-config.js.map +1 -0
- package/build/src/config/validate-config.d.ts +7 -0
- package/build/src/config/validate-config.d.ts.map +1 -0
- package/build/src/config/validate-config.js +117 -0
- package/build/src/config/validate-config.js.map +1 -0
- package/build/src/core/deploy-runner.d.ts +46 -0
- package/build/src/core/deploy-runner.d.ts.map +1 -0
- package/build/src/core/deploy-runner.js +221 -0
- package/build/src/core/deploy-runner.js.map +1 -0
- package/build/src/core/expo-web-artifacts.d.ts +10 -0
- package/build/src/core/expo-web-artifacts.d.ts.map +1 -0
- package/build/src/core/expo-web-artifacts.js +16 -0
- package/build/src/core/expo-web-artifacts.js.map +1 -0
- package/build/src/core/git-source.d.ts +22 -0
- package/build/src/core/git-source.d.ts.map +1 -0
- package/build/src/core/git-source.js +63 -0
- package/build/src/core/git-source.js.map +1 -0
- package/build/src/core/health-checks.d.ts +8 -0
- package/build/src/core/health-checks.d.ts.map +1 -0
- package/build/src/core/health-checks.js +19 -0
- package/build/src/core/health-checks.js.map +1 -0
- package/build/src/core/hooks.d.ts +12 -0
- package/build/src/core/hooks.d.ts.map +1 -0
- package/build/src/core/hooks.js +26 -0
- package/build/src/core/hooks.js.map +1 -0
- package/build/src/core/locks.d.ts +16 -0
- package/build/src/core/locks.d.ts.map +1 -0
- package/build/src/core/locks.js +32 -0
- package/build/src/core/locks.js.map +1 -0
- package/build/src/core/node-package-tasks.d.ts +26 -0
- package/build/src/core/node-package-tasks.d.ts.map +1 -0
- package/build/src/core/node-package-tasks.js +143 -0
- package/build/src/core/node-package-tasks.js.map +1 -0
- package/build/src/core/path-change-gate.d.ts +15 -0
- package/build/src/core/path-change-gate.d.ts.map +1 -0
- package/build/src/core/path-change-gate.js +95 -0
- package/build/src/core/path-change-gate.js.map +1 -0
- package/build/src/core/paths.d.ts +7 -0
- package/build/src/core/paths.d.ts.map +1 -0
- package/build/src/core/paths.js +20 -0
- package/build/src/core/paths.js.map +1 -0
- package/build/src/core/redaction.d.ts +22 -0
- package/build/src/core/redaction.d.ts.map +1 -0
- package/build/src/core/redaction.js +39 -0
- package/build/src/core/redaction.js.map +1 -0
- package/build/src/core/release-id.d.ts +6 -0
- package/build/src/core/release-id.d.ts.map +1 -0
- package/build/src/core/release-id.js +20 -0
- package/build/src/core/release-id.js.map +1 -0
- package/build/src/core/release-manager.d.ts +49 -0
- package/build/src/core/release-manager.d.ts.map +1 -0
- package/build/src/core/release-manager.js +115 -0
- package/build/src/core/release-manager.js.map +1 -0
- package/build/src/core/task-runner.d.ts +38 -0
- package/build/src/core/task-runner.d.ts.map +1 -0
- package/build/src/core/task-runner.js +102 -0
- package/build/src/core/task-runner.js.map +1 -0
- package/build/src/core/velocious-migrate.d.ts +11 -0
- package/build/src/core/velocious-migrate.d.ts.map +1 -0
- package/build/src/core/velocious-migrate.js +20 -0
- package/build/src/core/velocious-migrate.js.map +1 -0
- package/build/src/runtimes/index.d.ts +56 -0
- package/build/src/runtimes/index.d.ts.map +1 -0
- package/build/src/runtimes/index.js +132 -0
- package/build/src/runtimes/index.js.map +1 -0
- package/build/src/runtimes/none-runtime.d.ts +22 -0
- package/build/src/runtimes/none-runtime.d.ts.map +1 -0
- package/build/src/runtimes/none-runtime.js +23 -0
- package/build/src/runtimes/none-runtime.js.map +1 -0
- package/build/src/runtimes/rollbridge-runtime.d.ts +137 -0
- package/build/src/runtimes/rollbridge-runtime.d.ts.map +1 -0
- package/build/src/runtimes/rollbridge-runtime.js +224 -0
- package/build/src/runtimes/rollbridge-runtime.js.map +1 -0
- package/build/src/tasks.d.ts +5 -0
- package/build/src/tasks.d.ts.map +1 -0
- package/build/src/tasks.js +5 -0
- package/build/src/tasks.js.map +1 -0
- package/build/src/test-helpers.d.ts +25 -0
- package/build/src/test-helpers.d.ts.map +1 -0
- package/build/src/test-helpers.js +40 -0
- package/build/src/test-helpers.js.map +1 -0
- package/build/src/transports/local-transport.d.ts +67 -0
- package/build/src/transports/local-transport.d.ts.map +1 -0
- package/build/src/transports/local-transport.js +121 -0
- package/build/src/transports/local-transport.js.map +1 -0
- package/build/src/transports/ssh-transport.d.ts +189 -0
- package/build/src/transports/ssh-transport.d.ts.map +1 -0
- package/build/src/transports/ssh-transport.js +369 -0
- package/build/src/transports/ssh-transport.js.map +1 -0
- package/build/src/types.d.ts +290 -0
- package/build/src/types.d.ts.map +1 -0
- package/build/src/types.js +8 -0
- package/build/src/types.js.map +1 -0
- package/docs/config-reference.md +264 -0
- package/docs/migration-from-capistrano.md +167 -0
- package/docs/roadmap.md +27 -0
- package/examples/local/rampway.config.mjs +20 -0
- package/examples/monorepo/rampway.config.mjs +73 -0
- package/package.json +92 -0
package/README.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Rampway Deploy
|
|
2
|
+
|
|
3
|
+
Rampway is a JavaScript-native release-directory deployment tool: the useful parts of Capistrano, built for Node/Expo/Velocious projects and designed to hand runtime changes to Rollbridge.
|
|
4
|
+
|
|
5
|
+
Package: `rampway`
|
|
6
|
+
CLI: `rampway`
|
|
7
|
+
Config: `rampway.config.mjs`
|
|
8
|
+
|
|
9
|
+
## Current MVP
|
|
10
|
+
|
|
11
|
+
This initial scaffold includes:
|
|
12
|
+
|
|
13
|
+
- ESM config loading and validation
|
|
14
|
+
- deterministic deploy plans
|
|
15
|
+
- local release-directory deploys for tests/dogfooding
|
|
16
|
+
- linked file/dir checks and symlink creation
|
|
17
|
+
- deploy lock acquisition/release
|
|
18
|
+
- release metadata (`REVISION`, `TRESTLE_RELEASE.json`)
|
|
19
|
+
- atomic `current` symlink publishing
|
|
20
|
+
- safe cleanup
|
|
21
|
+
- rollback to previous or selected release
|
|
22
|
+
- JSONL deploy reports at `shared/log/rampway-deployments.jsonl`
|
|
23
|
+
- secret redaction helpers
|
|
24
|
+
- basic runtime adapter interface with `none` and Rollbridge validate/deploy/status/logs/recover helpers
|
|
25
|
+
|
|
26
|
+
SSH transport command execution supports both local-copy and remote-git deployments. `remote-git` prepares each release checkout on the target host, so the target needs `git` and access to the configured repository.
|
|
27
|
+
|
|
28
|
+
Full config reference: [docs/config-reference.md](docs/config-reference.md)
|
|
29
|
+
Migrating from Capistrano: [docs/migration-from-capistrano.md](docs/migration-from-capistrano.md)
|
|
30
|
+
|
|
31
|
+
## Commands
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
rampway init
|
|
35
|
+
rampway validate production
|
|
36
|
+
rampway plan production
|
|
37
|
+
rampway plan production --json
|
|
38
|
+
rampway deploy production
|
|
39
|
+
rampway status production
|
|
40
|
+
rampway releases production
|
|
41
|
+
rampway releases production --json
|
|
42
|
+
rampway rollback production
|
|
43
|
+
rampway doctor production
|
|
44
|
+
rampway doctor production --json
|
|
45
|
+
|
|
46
|
+
# Rollbridge runtime helpers for the current release
|
|
47
|
+
rampway rollbridge-validate production
|
|
48
|
+
rampway rollbridge-status production
|
|
49
|
+
rampway rollbridge-logs production
|
|
50
|
+
rampway rollbridge-recover production --yes
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
For local development without installing the package globally:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
node src/cli.js init
|
|
57
|
+
node src/cli.js validate --config examples/local/rampway.config.mjs local
|
|
58
|
+
node src/cli.js plan --config examples/local/rampway.config.mjs local
|
|
59
|
+
node src/cli.js deploy --config examples/local/rampway.config.mjs local --yes
|
|
60
|
+
|
|
61
|
+
# Monorepo example with backend + frontend stages
|
|
62
|
+
node src/cli.js validate --config examples/monorepo/rampway.config.mjs local
|
|
63
|
+
node src/cli.js plan --config examples/monorepo/rampway.config.mjs local
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Config example
|
|
67
|
+
|
|
68
|
+
Reusable Node package install helpers can be imported from `rampway/tasks` when writing `rampway.config.mjs`:
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
import {npmInstall, pnpmInstall, checkExpoWebArtifacts, velociousMigrate, onlyIfChanged} from "rampway/tasks"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
```js
|
|
75
|
+
// rampway.config.mjs
|
|
76
|
+
export default {
|
|
77
|
+
application: "routergeist",
|
|
78
|
+
stages: {
|
|
79
|
+
production: {
|
|
80
|
+
repo: "git@github.com:kaspernj/routergeist.git",
|
|
81
|
+
branch: "master",
|
|
82
|
+
deployTo: "/home/dev/routergeist",
|
|
83
|
+
strategy: "remote-git",
|
|
84
|
+
transport: {type: "ssh"},
|
|
85
|
+
hosts: [{host: "server.example", user: "dev", roles: ["app", "web", "db"]}],
|
|
86
|
+
keepReleases: 5,
|
|
87
|
+
linkedFiles: [
|
|
88
|
+
{path: "backend/src/config/secrets.js", required: true}
|
|
89
|
+
],
|
|
90
|
+
linkedDirs: ["log", "tmp/pids", "tmp/cache", "storage"],
|
|
91
|
+
tasks: {
|
|
92
|
+
install: [
|
|
93
|
+
npmInstall({cwd: "backend", production: true}),
|
|
94
|
+
pnpmInstall({cwd: "app", production: true})
|
|
95
|
+
],
|
|
96
|
+
migrate: [
|
|
97
|
+
velociousMigrate({cwd: "backend", env: {NODE_ENV: "production"}})
|
|
98
|
+
],
|
|
99
|
+
build: [
|
|
100
|
+
"cd app && npm run web:export",
|
|
101
|
+
checkExpoWebArtifacts({dir: "app/dist"}),
|
|
102
|
+
{command: "npm run assets:verify", cwd: "app", env: {NODE_ENV: "production"}}
|
|
103
|
+
]
|
|
104
|
+
},
|
|
105
|
+
runtime: {
|
|
106
|
+
type: "rollbridge",
|
|
107
|
+
command: "npx rollbridge",
|
|
108
|
+
packageDir: "backend",
|
|
109
|
+
config: "config/rollbridge.production.mjs",
|
|
110
|
+
healthPath: "/health",
|
|
111
|
+
daemonLogPath: "/home/dev/routergeist/shared/log/rollbridge.log",
|
|
112
|
+
daemonPidPath: "/home/dev/routergeist/shared/tmp/pids/rollbridge.pid",
|
|
113
|
+
socketPath: "/tmp/rollbridge-routergeist.sock",
|
|
114
|
+
versionPath: "/home/dev/routergeist/shared/tmp/rollbridge-version"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`npmInstall`, `pnpmInstall`, `yarnInstall`, `bunInstall`, and `nodePackageInstall` return normal task entries with the right install command for common Node package managers. They accept `cwd`, `env`, `optional`, `production`, and lockfile options such as `clean: false` for `npm install` instead of `npm ci`, or `frozenLockfile: false` for package managers that need explicit CI lockfile opt-outs (`--no-frozen-lockfile` for pnpm and `--no-immutable` for Yarn). Yarn production installs are intentionally not guessed; use a custom task command when that project needs a specific Yarn workspace/plugin flow.
|
|
122
|
+
|
|
123
|
+
`checkExpoWebArtifacts` returns a task entry that fails if the Expo web build directory does not contain an `index.html`. It accepts `dir` (default `"dist"`), `cwd`, and `optional`.
|
|
124
|
+
|
|
125
|
+
`velociousMigrate` returns a task entry that runs `npx velocious db:migrate`. It accepts `command` (override), `cwd`, `env`, and `optional`.
|
|
126
|
+
|
|
127
|
+
`onlyIfChanged(paths, task)` wraps a task entry so it is skipped when none of the given relative paths have changed since the previous deploy. On the first deploy (no previous release), all tasks run regardless.
|
|
128
|
+
|
|
129
|
+
Task entries can be strings or objects.
|
|
130
|
+
|
|
131
|
+
- `command` — required shell command to run.
|
|
132
|
+
- `cwd` — optional release-relative working directory.
|
|
133
|
+
- `env` — optional environment variables passed to the command.
|
|
134
|
+
- `optional` — when `true`, the deploy records the task failure and continues.
|
|
135
|
+
|
|
136
|
+
Task groups run in config order. Required task failures stop the deploy before publish. Deploy failures include whether `current` changed and recovery hints for the affected stage, such as rerunning a before-publish failure, inspecting a newly created failed release directory, or inspecting `rampway status`, `rampway releases`, and `rampway rollback` after a failure that happened after publish. Existing release-id collisions do not suggest deleting the release directory.
|
|
137
|
+
|
|
138
|
+
## Deployment reports
|
|
139
|
+
|
|
140
|
+
Every successful deploy or rollback appends one JSON object per line to `shared/log/rampway-deployments.jsonl`. Deploy events include:
|
|
141
|
+
|
|
142
|
+
- `event: "deploy"`
|
|
143
|
+
- `application`, `stage`, `releaseId`, `revision`, and `branch`
|
|
144
|
+
- `deployedAt` and `durationMs`
|
|
145
|
+
- `previousRelease`
|
|
146
|
+
- `healthChecks: "passed"`
|
|
147
|
+
- sanitized runtime status
|
|
148
|
+
- `cleanupRemoved` release IDs
|
|
149
|
+
|
|
150
|
+
Rollback events include `event: "rollback"`, the target `releaseId`, `rolledBackAt`, and `previousRelease`. Reports intentionally record runtime result summaries, not runtime configuration secrets.
|
|
151
|
+
|
|
152
|
+
## Releasing
|
|
153
|
+
|
|
154
|
+
Tag pushes trigger the `.github/workflows/release.yml` workflow, which validates the package, publishes it to npm, and then creates a GitHub Release with auto-generated notes. Bump the version locally and push tags:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
npm run release:patch # 0.1.0 → 0.1.1
|
|
158
|
+
npm run release:minor # 0.1.1 → 0.2.0
|
|
159
|
+
npm run release:major # 0.2.0 → 1.0.0
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Each command runs `npm version` (updating `package.json` and creating a `v`-prefixed tag) and pushes the commit and tag. The workflow picks up the tag, publishes the package, and creates the GitHub Release only after publishing succeeds.
|
|
163
|
+
|
|
164
|
+
Publishing requires an npm access token stored as the repository secret `NPM_TOKEN`.
|
|
165
|
+
|
|
166
|
+
## Runtime adapters
|
|
167
|
+
|
|
168
|
+
Rampway resolves runtimes through a small adapter registry. Built-in adapters are `none` and `rollbridge`; future adapters can register a runtime type without changing the deploy lifecycle core. Runtime adapters implement `plan()` and `deploy(...)`; optional maintenance methods such as `status`, `logs`, and `recover` can be exposed by adapter-specific commands.
|
|
169
|
+
|
|
170
|
+
Rollbridge runtime options:
|
|
171
|
+
|
|
172
|
+
- `command` — shell command used to invoke Rollbridge, defaulting to `npx rollbridge`.
|
|
173
|
+
- `packageDir` — release-relative directory where Rollbridge commands run.
|
|
174
|
+
- `config` — optional Rollbridge config path passed as `--config`.
|
|
175
|
+
- `daemonLogPath`, `daemonPidPath`, and `daemonStartTimeoutMs` — optional daemon flags forwarded to `rollbridge deploy`.
|
|
176
|
+
- `versionPath` — optional shared file where Rampway records the deployed Rollbridge package version.
|
|
177
|
+
- `socketPath` — optional Rollbridge socket removed after a version-change shutdown if a stale daemon leaves it behind.
|
|
178
|
+
|
|
179
|
+
When `versionPath` is configured, Rampway reads the release's installed Rollbridge package version before deploy. If it differs from the recorded version and the current runtime is responsive, Rampway shuts down the current Rollbridge daemon, removes configured stale daemon artifacts, deploys the new release, and records the new version.
|
|
180
|
+
|
|
181
|
+
## Safety model
|
|
182
|
+
|
|
183
|
+
Rampway prepares a complete release before flipping `current`. If a deploy fails before publish, `current` remains unchanged. Rollbridge runtime deploys are validated and health-checked with `rollbridge status` before `current` is updated. Cleanup never removes the current release. Rollback changes `current` to a previously prepared release and records a deployment event.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli.js"],"names":[],"mappings":""}
|
package/build/src/cli.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { validateCommand } from "./commands/validate.js";
|
|
5
|
+
import { planCommand } from "./commands/plan.js";
|
|
6
|
+
import { doctorCommand } from "./commands/doctor.js";
|
|
7
|
+
import { deployCommand } from "./commands/deploy.js";
|
|
8
|
+
import { releasesCommand, statusCommand } from "./commands/releases.js";
|
|
9
|
+
import { rollbackCommand } from "./commands/rollback.js";
|
|
10
|
+
import { rollbridgeValidateCommand, rollbridgeStatusCommand, rollbridgeLogsCommand, rollbridgeRecoverCommand } from "./commands/rollbridge.js";
|
|
11
|
+
import { initCommand } from "./commands/init.js";
|
|
12
|
+
/** @type {Record<string, Function>} */
|
|
13
|
+
const COMMANDS = {
|
|
14
|
+
init: initCommand,
|
|
15
|
+
validate: validateCommand,
|
|
16
|
+
plan: planCommand,
|
|
17
|
+
deploy: deployCommand,
|
|
18
|
+
releases: releasesCommand,
|
|
19
|
+
status: statusCommand,
|
|
20
|
+
rollback: rollbackCommand,
|
|
21
|
+
"rollbridge-validate": rollbridgeValidateCommand,
|
|
22
|
+
"rollbridge-status": rollbridgeStatusCommand,
|
|
23
|
+
"rollbridge-logs": rollbridgeLogsCommand,
|
|
24
|
+
"rollbridge-recover": rollbridgeRecoverCommand,
|
|
25
|
+
doctor: doctorCommand
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* @param {string[]} argv
|
|
29
|
+
* @returns {Promise<void>}
|
|
30
|
+
*/
|
|
31
|
+
async function main(argv) {
|
|
32
|
+
let { command, stageName, options } = parseArgs(argv);
|
|
33
|
+
// Stage-first Capistrano-style invocation: `rampway production deploy`
|
|
34
|
+
// (the first positional matches a known deploy/<stage>.js file and the second is a valid command)
|
|
35
|
+
if (command && stageName && !COMMANDS[command] && COMMANDS[stageName] && stageFileExists(command, options.config)) {
|
|
36
|
+
[command, stageName] = [stageName, command];
|
|
37
|
+
}
|
|
38
|
+
if (!COMMANDS[command])
|
|
39
|
+
throw new Error(`Unknown command '${command}'. Supported: ${Object.keys(COMMANDS).join(", ")}`);
|
|
40
|
+
if (!stageName && command !== "init")
|
|
41
|
+
throw new Error(`Usage: rampway <command> <stage> OR rampway <stage> <command> [--config path]`);
|
|
42
|
+
await COMMANDS[command]({ stageName, options });
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* @param {string} stageName
|
|
46
|
+
* @param {string} [configPath]
|
|
47
|
+
* @returns {boolean}
|
|
48
|
+
*/
|
|
49
|
+
function stageFileExists(stageName, configPath) {
|
|
50
|
+
if (configPath)
|
|
51
|
+
return false;
|
|
52
|
+
// Capistrano-style: stage configs live in deploy/environments/<stage>.js.
|
|
53
|
+
// Walk up from cwd to find the project root that contains deploy/config.js.
|
|
54
|
+
let dir = process.cwd();
|
|
55
|
+
for (let i = 0; i < 5; i++) {
|
|
56
|
+
const candidate = path.join(dir, "deploy", "environments", `${stageName}.js`);
|
|
57
|
+
try {
|
|
58
|
+
if (fs.statSync(candidate).isFile())
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
catch { /* continue */ }
|
|
62
|
+
const parent = path.dirname(dir);
|
|
63
|
+
if (parent === dir)
|
|
64
|
+
break;
|
|
65
|
+
dir = parent;
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* @param {string[]} argv
|
|
71
|
+
* @returns {{command: string, stageName: string, options: import('#types').CommandOptions}}
|
|
72
|
+
*/
|
|
73
|
+
function parseArgs(argv) {
|
|
74
|
+
const positional = [];
|
|
75
|
+
/** @type {Record<string, string|boolean>} */
|
|
76
|
+
const options = {};
|
|
77
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
78
|
+
const arg = argv[index];
|
|
79
|
+
if (arg.startsWith("--")) {
|
|
80
|
+
const name = arg.slice(2);
|
|
81
|
+
if (["yes", "dry-run", "force", "allow-dirty", "json"].includes(name))
|
|
82
|
+
options[toCamel(name)] = true;
|
|
83
|
+
else {
|
|
84
|
+
index += 1;
|
|
85
|
+
options[toCamel(name)] = argv[index];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else
|
|
89
|
+
positional.push(arg);
|
|
90
|
+
}
|
|
91
|
+
return { command: positional[0], stageName: positional[1], options };
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* @param {string} name
|
|
95
|
+
* @returns {string}
|
|
96
|
+
*/
|
|
97
|
+
function toCamel(name) {
|
|
98
|
+
return name.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
99
|
+
}
|
|
100
|
+
main(process.argv.slice(2)).catch(error => {
|
|
101
|
+
console.error(error.message);
|
|
102
|
+
process.exitCode = 1;
|
|
103
|
+
});
|
|
104
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.js"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAC,eAAe,EAAC,MAAM,wBAAwB,CAAA;AACtD,OAAO,EAAC,WAAW,EAAC,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAC,aAAa,EAAC,MAAM,sBAAsB,CAAA;AAClD,OAAO,EAAC,aAAa,EAAC,MAAM,sBAAsB,CAAA;AAClD,OAAO,EAAC,eAAe,EAAE,aAAa,EAAC,MAAM,wBAAwB,CAAA;AACrE,OAAO,EAAC,eAAe,EAAC,MAAM,wBAAwB,CAAA;AACtD,OAAO,EAAC,yBAAyB,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,wBAAwB,EAAC,MAAM,0BAA0B,CAAA;AAC5I,OAAO,EAAC,WAAW,EAAC,MAAM,oBAAoB,CAAA;AAE9C,uCAAuC;AACvC,MAAM,QAAQ,GAAG;IACf,IAAI,EAAE,WAAW;IACjB,QAAQ,EAAE,eAAe;IACzB,IAAI,EAAE,WAAW;IACjB,MAAM,EAAE,aAAa;IACrB,QAAQ,EAAE,eAAe;IACzB,MAAM,EAAE,aAAa;IACrB,QAAQ,EAAE,eAAe;IACzB,qBAAqB,EAAE,yBAAyB;IAChD,mBAAmB,EAAE,uBAAuB;IAC5C,iBAAiB,EAAE,qBAAqB;IACxC,oBAAoB,EAAE,wBAAwB;IAC9C,MAAM,EAAE,aAAa;CACtB,CAAA;AAED;;;GAGG;AACH,KAAK,UAAU,IAAI,CAAC,IAAI;IACtB,IAAI,EAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAC,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;IAEnD,uEAAuE;IACvE,kGAAkG;IAClG,IAAI,OAAO,IAAI,SAAS,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC,SAAS,CAAC,IAAI,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClH,CAAC,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IAC7C,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,OAAO,iBAAiB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACvH,IAAI,CAAC,SAAS,IAAI,OAAO,KAAK,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,kFAAkF,CAAC,CAAA;IACzI,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAC,SAAS,EAAE,OAAO,EAAC,CAAC,CAAA;AAC/C,CAAC;AAED;;;;GAIG;AACH,SAAS,eAAe,CAAC,SAAS,EAAE,UAAU;IAC5C,IAAI,UAAU;QAAE,OAAO,KAAK,CAAA;IAE5B,0EAA0E;IAC1E,4EAA4E;IAC5E,IAAI,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IACvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,SAAS,KAAK,CAAC,CAAA;QAC7E,IAAI,CAAC;YAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE;gBAAE,OAAO,IAAI,CAAA;QAAC,CAAC;QACxD,MAAM,CAAC,CAAC,cAAc,CAAC,CAAC;QACxB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAChC,IAAI,MAAM,KAAK,GAAG;YAAE,MAAK;QACzB,GAAG,GAAG,MAAM,CAAA;IACd,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;GAGG;AACH,SAAS,SAAS,CAAC,IAAI;IACrB,MAAM,UAAU,GAAG,EAAE,CAAA;IACrB,6CAA6C;IAC7C,MAAM,OAAO,GAAG,EAAE,CAAA;IAClB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAA;QACvB,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;YACzB,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAA;iBAC/F,CAAC;gBACJ,KAAK,IAAI,CAAC,CAAA;gBACV,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAA;YACtC,CAAC;QACH,CAAC;;YAAM,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC7B,CAAC;IACD,OAAO,EAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,OAAO,EAAC,CAAA;AACpE,CAAC;AAED;;;GAGG;AACH,SAAS,OAAO,CAAC,IAAI;IACnB,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAA;AACvE,CAAC;AAED,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;IACxC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAC5B,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAA;AACtB,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {import('#types').CommandOptions} options
|
|
3
|
+
* @param {string} stageName
|
|
4
|
+
* @returns {Promise<{config: object, configPath: string, stage: import('#types').StageConfig, transport: import('#types').Transport}>}
|
|
5
|
+
*/
|
|
6
|
+
export function commandContext(options: import("#types").CommandOptions, stageName: string): Promise<{
|
|
7
|
+
config: object;
|
|
8
|
+
configPath: string;
|
|
9
|
+
stage: import("#types").StageConfig;
|
|
10
|
+
transport: import("#types").Transport;
|
|
11
|
+
}>;
|
|
12
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/commands/context.js"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,wCAJW,OAAO,QAAQ,EAAE,cAAc,aAC/B,MAAM,GACJ,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,QAAQ,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,OAAO,QAAQ,EAAE,SAAS,CAAA;CAAC,CAAC,CAOrI"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { loadConfig } from "../config/load-config.js";
|
|
2
|
+
import { validateConfig } from "../config/validate-config.js";
|
|
3
|
+
import { LocalTransport } from "../transports/local-transport.js";
|
|
4
|
+
import { SshTransport } from "../transports/ssh-transport.js";
|
|
5
|
+
/**
|
|
6
|
+
* @param {import('#types').CommandOptions} options
|
|
7
|
+
* @param {string} stageName
|
|
8
|
+
* @returns {Promise<{config: object, configPath: string, stage: import('#types').StageConfig, transport: import('#types').Transport}>}
|
|
9
|
+
*/
|
|
10
|
+
export async function commandContext(options, stageName) {
|
|
11
|
+
const { config, configPath } = await loadConfig(options.config, stageName);
|
|
12
|
+
const stage = validateConfig(/** @type {Record<string, unknown>} */ (config), stageName);
|
|
13
|
+
const transport = stage.transport.type === "ssh" ? SshTransport.fromStage(stage) : new LocalTransport();
|
|
14
|
+
return { config, configPath, stage, transport };
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/commands/context.js"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAA;AACnD,OAAO,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAA;AAC3D,OAAO,EAAC,cAAc,EAAC,MAAM,kCAAkC,CAAA;AAC/D,OAAO,EAAC,YAAY,EAAC,MAAM,gCAAgC,CAAA;AAE3D;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAO,EAAE,SAAS;IACrD,MAAM,EAAC,MAAM,EAAE,UAAU,EAAC,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IACxE,MAAM,KAAK,GAAG,cAAc,CAAC,sCAAsC,CAAC,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC,CAAA;IACxF,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,cAAc,EAAE,CAAA;IACvG,OAAO,EAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAC,CAAA;AAC/C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../../src/commands/deploy.js"],"names":[],"mappings":"AAGA;;;GAGG;AACH,sEAHW,OAAO,QAAQ,EAAE,WAAW,GAC1B,OAAO,CAAC,IAAI,CAAC,CAOzB"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { commandContext as defaultCommandContext } from "./context.js";
|
|
2
|
+
import { deploy } from "../core/deploy-runner.js";
|
|
3
|
+
/**
|
|
4
|
+
* @param {import('#types').CommandArgs} args
|
|
5
|
+
* @returns {Promise<void>}
|
|
6
|
+
*/
|
|
7
|
+
export async function deployCommand({ stageName, options, commandContext = defaultCommandContext }) {
|
|
8
|
+
const { stage, transport } = await commandContext(options, stageName);
|
|
9
|
+
if (!options.yes && stageName === "production")
|
|
10
|
+
throw new Error("Refusing production deploy without --yes in non-interactive MVP mode.");
|
|
11
|
+
const report = await deploy({ transport, stage, sourcePath: options.source ?? process.cwd(), revision: options.revision ?? options.branch ?? stage.revision ?? stage.branch, branch: options.branch ?? stage.branch, dryRun: options.dryRun, force: options.force });
|
|
12
|
+
console.log(JSON.stringify(report, null, 2));
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=deploy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../../src/commands/deploy.js"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,IAAI,qBAAqB,EAAC,MAAM,cAAc,CAAA;AACpE,OAAO,EAAC,MAAM,EAAC,MAAM,0BAA0B,CAAA;AAE/C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,EAAC,SAAS,EAAE,OAAO,EAAE,cAAc,GAAG,qBAAqB,EAAC;IAC9F,MAAM,EAAC,KAAK,EAAE,SAAS,EAAC,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;IACnE,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,SAAS,KAAK,YAAY;QAAE,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAA;IACxI,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,EAAC,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAC,CAAC,CAAA;IAClQ,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;AAC9C,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {import('#types').CommandArgs} args
|
|
3
|
+
* @returns {Promise<void>}
|
|
4
|
+
*/
|
|
5
|
+
export function doctorCommand({ stageName, options, commandContext }: import("#types").CommandArgs): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* @param {{configPath: string, stage: import('#types').StageConfig}} opts
|
|
8
|
+
* @returns {import('#types').DoctorReport}
|
|
9
|
+
*/
|
|
10
|
+
export function doctorReport({ configPath, stage }: {
|
|
11
|
+
configPath: string;
|
|
12
|
+
stage: import("#types").StageConfig;
|
|
13
|
+
}): import("#types").DoctorReport;
|
|
14
|
+
//# sourceMappingURL=doctor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/commands/doctor.js"],"names":[],"mappings":"AAIA;;;GAGG;AACH,sEAHW,OAAO,QAAQ,EAAE,WAAW,GAC1B,OAAO,CAAC,IAAI,CAAC,CAyBzB;AAED;;;GAGG;AACH,oDAHW;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,QAAQ,EAAE,WAAW,CAAA;CAAC,GACvD,OAAO,QAAQ,EAAE,YAAY,CAqBzC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { commandContext as defaultCommandContext } from "./context.js";
|
|
2
|
+
const DEPLOYABLE_STRATEGIES = new Set(["local-copy", "remote-git"]);
|
|
3
|
+
/**
|
|
4
|
+
* @param {import('#types').CommandArgs} args
|
|
5
|
+
* @returns {Promise<void>}
|
|
6
|
+
*/
|
|
7
|
+
export async function doctorCommand({ stageName, options, commandContext = defaultCommandContext }) {
|
|
8
|
+
const { configPath, stage } = await commandContext(options, stageName);
|
|
9
|
+
const report = doctorReport({ configPath, stage });
|
|
10
|
+
if (options.json) {
|
|
11
|
+
console.log(JSON.stringify(report, null, 2));
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
console.log("Rampway doctor");
|
|
15
|
+
console.log(`Config: ok (${report.configPath})`);
|
|
16
|
+
console.log(`Application: ${report.application}`);
|
|
17
|
+
console.log(`Stage: ${report.stage}`);
|
|
18
|
+
console.log(`Transport: ${report.transport.type}`);
|
|
19
|
+
console.log(`Strategy: ${report.strategy}`);
|
|
20
|
+
console.log(`Deploy path: ${report.deployTo}`);
|
|
21
|
+
console.log(`Runtime: ${report.runtime.type}`);
|
|
22
|
+
console.log(`Linked files: ${report.linkedFiles}`);
|
|
23
|
+
console.log(`Linked dirs: ${report.linkedDirs}`);
|
|
24
|
+
console.log(`Task groups: ${report.taskGroups}`);
|
|
25
|
+
console.log(`Health checks: ${report.healthChecks}`);
|
|
26
|
+
console.log(`Result: ${report.ok ? "ok" : "warnings"}`);
|
|
27
|
+
for (const warning of report.warnings)
|
|
28
|
+
console.log(`Warning: ${warning}`);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* @param {{configPath: string, stage: import('#types').StageConfig}} opts
|
|
32
|
+
* @returns {import('#types').DoctorReport}
|
|
33
|
+
*/
|
|
34
|
+
export function doctorReport({ configPath, stage }) {
|
|
35
|
+
const warnings = [];
|
|
36
|
+
if (!DEPLOYABLE_STRATEGIES.has(stage.strategy))
|
|
37
|
+
warnings.push(`Strategy '${stage.strategy}' validates but deploy is not implemented yet`);
|
|
38
|
+
return {
|
|
39
|
+
ok: warnings.length === 0,
|
|
40
|
+
configPath,
|
|
41
|
+
application: stage.application,
|
|
42
|
+
stage: stage.stageName,
|
|
43
|
+
deployTo: stage.deployTo,
|
|
44
|
+
transport: { type: stage.transport.type },
|
|
45
|
+
strategy: stage.strategy,
|
|
46
|
+
runtime: { type: stage.runtime.type },
|
|
47
|
+
linkedFiles: stage.linkedFiles.length,
|
|
48
|
+
linkedDirs: stage.linkedDirs.length,
|
|
49
|
+
taskGroups: Object.keys(stage.tasks).length,
|
|
50
|
+
healthChecks: stage.healthChecks.length,
|
|
51
|
+
warnings
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/commands/doctor.js"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/commands/init.js"],"names":[],"mappings":"AA4BA;;;GAGG;AACH,sCAHW;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAC,GACZ,OAAO,CAAC,OAAO,QAAQ,EAAE,UAAU,CAAC,CAWhD"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
const TEMPLATE = `export default {
|
|
4
|
+
application: "my-app",
|
|
5
|
+
stages: {
|
|
6
|
+
production: {
|
|
7
|
+
deployTo: "/home/dev/my-app",
|
|
8
|
+
strategy: "local-copy",
|
|
9
|
+
transport: {type: "ssh"},
|
|
10
|
+
hosts: [{host: "server.example", user: "dev", roles: ["app", "web"]}],
|
|
11
|
+
keepReleases: 5,
|
|
12
|
+
linkedFiles: [
|
|
13
|
+
{path: ".env", required: true}
|
|
14
|
+
],
|
|
15
|
+
linkedDirs: ["log", "tmp/pids", "tmp/cache"],
|
|
16
|
+
tasks: {
|
|
17
|
+
install: ["npm ci --omit=dev"],
|
|
18
|
+
migrate: ["NODE_ENV=production npm run db:migrate"],
|
|
19
|
+
build: ["npm run build"]
|
|
20
|
+
},
|
|
21
|
+
runtime: {type: "none"},
|
|
22
|
+
healthChecks: [{name: "package", path: "package.json"}]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
`;
|
|
27
|
+
/**
|
|
28
|
+
* @param {{dir?: string}} [opts]
|
|
29
|
+
* @returns {Promise<import('#types').InitResult>}
|
|
30
|
+
*/
|
|
31
|
+
export async function initCommand({ dir = process.cwd() } = {}) {
|
|
32
|
+
const configPath = path.join(dir, "rampway.config.mjs");
|
|
33
|
+
try {
|
|
34
|
+
await fs.access(configPath);
|
|
35
|
+
return { created: false, path: configPath };
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
await fs.writeFile(configPath, TEMPLATE);
|
|
39
|
+
return { created: true, path: configPath };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/commands/init.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAA;AACjC,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;;;;;;;;;;CAuBhB,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,EAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,EAAC,GAAG,EAAE;IAC1D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAA;IACvD,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;QAC3B,OAAO,EAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAC,CAAA;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;QACxC,OAAO,EAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAC,CAAA;IAC1C,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/commands/plan.js"],"names":[],"mappings":"AAGA;;;GAGG;AACH,oEAHW,OAAO,QAAQ,EAAE,WAAW,GAC1B,OAAO,CAAC,IAAI,CAAC,CAoBzB"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { commandContext as defaultCommandContext } from "./context.js";
|
|
2
|
+
import { createDeployPlanDetails } from "../core/deploy-runner.js";
|
|
3
|
+
/**
|
|
4
|
+
* @param {import('#types').CommandArgs} args
|
|
5
|
+
* @returns {Promise<void>}
|
|
6
|
+
*/
|
|
7
|
+
export async function planCommand({ stageName, options, commandContext = defaultCommandContext }) {
|
|
8
|
+
const { stage } = await commandContext(options, stageName);
|
|
9
|
+
const revision = options.revision ?? options.branch ?? stage.revision ?? stage.branch;
|
|
10
|
+
const releaseId = options.releaseId ?? "<timestamp>";
|
|
11
|
+
const steps = createDeployPlanDetails(stage, { revision, releaseId });
|
|
12
|
+
const payload = { application: stage.application, stage: stage.stageName, revision, releaseId, steps };
|
|
13
|
+
if (options.json) {
|
|
14
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
console.log(`Plan for ${stage.application} ${stage.stageName}`);
|
|
18
|
+
console.log(`Revision: ${revision}`);
|
|
19
|
+
console.log(`Release: ${releaseId}`);
|
|
20
|
+
steps.forEach((step, index) => {
|
|
21
|
+
console.log(`${index + 1}. [${step.phase}] ${step.detail}`);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/commands/plan.js"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,IAAI,qBAAqB,EAAC,MAAM,cAAc,CAAA;AACpE,OAAO,EAAC,uBAAuB,EAAC,MAAM,0BAA0B,CAAA;AAEhE;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,EAAC,SAAS,EAAE,OAAO,EAAE,cAAc,GAAG,qBAAqB,EAAC;IAC5F,MAAM,EAAC,KAAK,EAAC,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;IACxD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM,CAAA;IACrF,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,aAAa,CAAA;IACpD,MAAM,KAAK,GAAG,uBAAuB,CAAC,KAAK,EAAE,EAAC,QAAQ,EAAE,SAAS,EAAC,CAAC,CAAA;IACnE,MAAM,OAAO,GAAG,EAAC,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,KAAK,EAAE,KAAK,CAAC,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAC,CAAA;IAEpG,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;QAC7C,OAAM;IACR,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC,CAAA;IAC/D,OAAO,CAAC,GAAG,CAAC,aAAa,QAAQ,EAAE,CAAC,CAAA;IACpC,OAAO,CAAC,GAAG,CAAC,YAAY,SAAS,EAAE,CAAC,CAAA;IACpC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC5B,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,MAAM,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC,CAAA;IAC7D,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {import('#types').CommandArgs} args
|
|
3
|
+
* @returns {Promise<void>}
|
|
4
|
+
*/
|
|
5
|
+
export function releasesCommand({ stageName, options, commandContext }: import("#types").CommandArgs): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* @param {{stage: import('#types').StageConfig, transport: import('#types').Transport}} opts
|
|
8
|
+
* @returns {Promise<import('#types').ReleasesReport>}
|
|
9
|
+
*/
|
|
10
|
+
export function releasesReport({ stage, transport }: {
|
|
11
|
+
stage: import("#types").StageConfig;
|
|
12
|
+
transport: import("#types").Transport;
|
|
13
|
+
}): Promise<import("#types").ReleasesReport>;
|
|
14
|
+
/**
|
|
15
|
+
* @param {import('#types').CommandArgs} args
|
|
16
|
+
* @returns {Promise<void>}
|
|
17
|
+
*/
|
|
18
|
+
export function statusCommand({ stageName, options, commandContext }: import("#types").CommandArgs): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* @param {{stage: import('#types').StageConfig, transport: import('#types').Transport}} opts
|
|
21
|
+
* @returns {Promise<import('#types').StatusReport>}
|
|
22
|
+
*/
|
|
23
|
+
export function statusReport({ stage, transport }: {
|
|
24
|
+
stage: import("#types").StageConfig;
|
|
25
|
+
transport: import("#types").Transport;
|
|
26
|
+
}): Promise<import("#types").StatusReport>;
|
|
27
|
+
//# sourceMappingURL=releases.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"releases.d.ts","sourceRoot":"","sources":["../../../src/commands/releases.js"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wEAHW,OAAO,QAAQ,EAAE,WAAW,GAC1B,OAAO,CAAC,IAAI,CAAC,CAiBzB;AAED;;;GAGG;AACH,qDAHW;IAAC,KAAK,EAAE,OAAO,QAAQ,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,OAAO,QAAQ,EAAE,SAAS,CAAA;CAAC,GAC1E,OAAO,CAAC,OAAO,QAAQ,EAAE,cAAc,CAAC,CAiBpD;AAED;;;GAGG;AACH,sEAHW,OAAO,QAAQ,EAAE,WAAW,GAC1B,OAAO,CAAC,IAAI,CAAC,CAoBzB;AAED;;;GAGG;AACH,mDAHW;IAAC,KAAK,EAAE,OAAO,QAAQ,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,OAAO,QAAQ,EAAE,SAAS,CAAA;CAAC,GAC1E,OAAO,CAAC,OAAO,QAAQ,EAAE,YAAY,CAAC,CAsBlD"}
|