mirror of
https://github.com/Dokploy/cli.git
synced 2026-06-15 20:25:22 +02:00
1
.eslintignore
Normal file
1
.eslintignore
Normal file
@@ -0,0 +1 @@
|
||||
/dist
|
||||
3
.eslintrc.json
Normal file
3
.eslintrc.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": [ "prettier"]
|
||||
}
|
||||
56
.github/workflows/onPushToMain.yml
vendored
Normal file
56
.github/workflows/onPushToMain.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
# test
|
||||
name: version, tag and github release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
- name: Check if version already exists
|
||||
id: version-check
|
||||
run: |
|
||||
package_version=$(node -p "require('./package.json').version")
|
||||
exists=$(gh api repos/${{ github.repository }}/releases/tags/v$package_version >/dev/null 2>&1 && echo "true" || echo "")
|
||||
|
||||
if [ -n "$exists" ];
|
||||
then
|
||||
echo "Version v$package_version already exists"
|
||||
echo "::warning file=package.json,line=1::Version v$package_version already exists - no release will be created. If you want to create a new release, please update the version in package.json and push again."
|
||||
echo "skipped=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "Version v$package_version does not exist. Creating release..."
|
||||
echo "skipped=false" >> $GITHUB_OUTPUT
|
||||
echo "tag=v$package_version" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
- name: Setup git
|
||||
if: ${{ steps.version-check.outputs.skipped == 'false' }}
|
||||
run: |
|
||||
git config --global user.email ${{ secrets.GH_EMAIL }}
|
||||
git config --global user.name ${{ secrets.GH_USERNAME }}
|
||||
- name: Generate oclif README
|
||||
if: ${{ steps.version-check.outputs.skipped == 'false' }}
|
||||
id: oclif-readme
|
||||
run: |
|
||||
pnpm install
|
||||
pnpm exec oclif readme
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
git add .
|
||||
git commit -am "chore: update README.md"
|
||||
git push -u origin ${{ github.ref_name }}
|
||||
fi
|
||||
- name: Create Github Release
|
||||
uses: ncipollo/release-action@2c591bcc8ecdcd2db72b97d6147f871fcd833ba5
|
||||
if: ${{ steps.version-check.outputs.skipped == 'false' }}
|
||||
with:
|
||||
name: ${{ steps.version-check.outputs.tag }}
|
||||
tag: ${{ steps.version-check.outputs.tag }}
|
||||
commit: ${{ github.ref_name }}
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
skipIfReleaseExists: true
|
||||
18
.github/workflows/onRelease.yml
vendored
Normal file
18
.github/workflows/onRelease.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: publish
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [released]
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: latest
|
||||
- run: pnpm install
|
||||
- uses: JS-DevTools/npm-publish@19c28f1ef146469e409470805ea4279d47c3d35c
|
||||
with:
|
||||
token: ${{ secrets.NPM_TOKEN }}
|
||||
23
.github/workflows/test.yml
vendored
Normal file
23
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: tests
|
||||
on:
|
||||
push:
|
||||
branches-ignore: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
unit-tests:
|
||||
strategy:
|
||||
matrix:
|
||||
os: ['ubuntu-latest', 'windows-latest']
|
||||
node_version: [lts/-1, lts/*, latest]
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node_version }}
|
||||
cache: pnpm
|
||||
- run: pnpm install
|
||||
- run: pnpm run build
|
||||
- run: pnpm run test
|
||||
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
*-debug.log
|
||||
*-error.log
|
||||
**/.DS_Store
|
||||
/.idea
|
||||
/dist
|
||||
/tmp
|
||||
/node_modules
|
||||
oclif.manifest.json
|
||||
|
||||
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
|
||||
|
||||
15
.mocharc.json
Normal file
15
.mocharc.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"require": [
|
||||
"ts-node/register"
|
||||
],
|
||||
"watch-extensions": [
|
||||
"ts"
|
||||
],
|
||||
"recursive": true,
|
||||
"reporter": "spec",
|
||||
"timeout": 60000,
|
||||
"node-option": [
|
||||
"loader=ts-node/esm",
|
||||
"experimental-specifier-resolution=node"
|
||||
]
|
||||
}
|
||||
1
.prettierrc.json
Normal file
1
.prettierrc.json
Normal file
@@ -0,0 +1 @@
|
||||
"@oclif/prettier-config"
|
||||
20
.vscode/launch.json
vendored
Normal file
20
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "attach",
|
||||
"name": "Attach",
|
||||
"port": 9229,
|
||||
"skipFiles": ["<node_internals>/**"]
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Execute Command",
|
||||
"skipFiles": ["<node_internals>/**"],
|
||||
"program": "${workspaceFolder}/bin/dev",
|
||||
"args": ["hello", "world"]
|
||||
}
|
||||
]
|
||||
}
|
||||
3
bin/dev.cmd
Normal file
3
bin/dev.cmd
Normal file
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
|
||||
node --loader ts-node/esm --no-warnings=ExperimentalWarning "%~dp0\dev" %*
|
||||
6
bin/dev.js
Executable file
6
bin/dev.js
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env -S node --loader ts-node/esm --no-warnings=ExperimentalWarning
|
||||
|
||||
// eslint-disable-next-line n/shebang
|
||||
import {execute} from '@oclif/core'
|
||||
|
||||
await execute({development: true, dir: import.meta.url})
|
||||
3
bin/run.cmd
Normal file
3
bin/run.cmd
Normal file
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
|
||||
node "%~dp0\run" %*
|
||||
5
bin/run.js
Executable file
5
bin/run.js
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import {execute} from '@oclif/core'
|
||||
|
||||
await execute({dir: import.meta.url})
|
||||
4
config.json
Normal file
4
config.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"token": "icsy0appti460sbh5be1sevami702rc8a57l2e8h",
|
||||
"url": "http://localhost:3000"
|
||||
}
|
||||
80
package.json
Normal file
80
package.json
Normal file
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"name": "dokploy",
|
||||
"description": "A CLI to manage dokploy server remotely",
|
||||
"version": "0.0.0",
|
||||
"author": "Mauricio Siu",
|
||||
"bin": {
|
||||
"dokploy": "./bin/run.js"
|
||||
},
|
||||
"bugs": "https://github.com/Dokploy/cli/issues",
|
||||
"dependencies": {
|
||||
"@oclif/core": "^3",
|
||||
"@oclif/plugin-help": "^6",
|
||||
"@oclif/plugin-plugins": "^5",
|
||||
"axios": "^1.7.2",
|
||||
"chalk": "^5.3.0",
|
||||
"cli-table3": "^0.6.5",
|
||||
"inquirer": "^9.2.23",
|
||||
"slugify": "^1.6.6",
|
||||
"superjson": "^2.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@oclif/prettier-config": "^0.2.1",
|
||||
"@oclif/test": "^4",
|
||||
"@types/chai": "^4",
|
||||
"@types/inquirer": "9.0.7",
|
||||
"@types/mocha": "^10",
|
||||
"@types/node": "^18",
|
||||
"chai": "^4",
|
||||
"eslint": "^8",
|
||||
"eslint-config-oclif": "^5",
|
||||
"eslint-config-oclif-typescript": "^3",
|
||||
"eslint-config-prettier": "^9",
|
||||
"mocha": "^10",
|
||||
"oclif": "^4",
|
||||
"shx": "^0.3.3",
|
||||
"ts-node": "^10",
|
||||
"typescript": "^5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"files": [
|
||||
"/bin",
|
||||
"/dist",
|
||||
"/oclif.manifest.json"
|
||||
],
|
||||
"homepage": "https://github.com/Dokploy/cli",
|
||||
"keywords": [
|
||||
"oclif"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"type": "module",
|
||||
"oclif": {
|
||||
"bin": "dokploy",
|
||||
"dirname": "dokploy",
|
||||
"commands": "./dist/commands",
|
||||
"plugins": [
|
||||
"@oclif/plugin-help",
|
||||
"@oclif/plugin-plugins"
|
||||
],
|
||||
"topicSeparator": " ",
|
||||
"topics": {
|
||||
"hello": {
|
||||
"description": "Say hello to the world and others"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repository": "Dokploy/cli",
|
||||
"scripts": {
|
||||
"build": "shx rm -rf dist && tsc -b",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"postpack": "shx rm -f oclif.manifest.json",
|
||||
"posttest": "pnpm run lint",
|
||||
"prepack": "oclif manifest && oclif readme",
|
||||
"test": "mocha --forbid-only \"test/**/*.test.ts\"",
|
||||
"version": "oclif readme && git add README.md"
|
||||
},
|
||||
"types": "dist/index.d.ts"
|
||||
}
|
||||
5309
pnpm-lock.yaml
generated
Normal file
5309
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
397
readme.md
397
readme.md
@@ -1 +1,396 @@
|
||||
# cli
|
||||
dokploy
|
||||
=================
|
||||
|
||||
A CLI to manage dokploy server remotely
|
||||
|
||||
|
||||
[](https://oclif.io)
|
||||
[](https://npmjs.org/package/dokploy)
|
||||
[](https://npmjs.org/package/dokploy)
|
||||
|
||||
|
||||
<!-- toc -->
|
||||
* [Usage](#usage)
|
||||
* [Commands](#commands)
|
||||
<!-- tocstop -->
|
||||
# Usage
|
||||
<!-- usage -->
|
||||
```sh-session
|
||||
$ npm install -g dokploy
|
||||
$ dokploy COMMAND
|
||||
running command...
|
||||
$ dokploy (--version)
|
||||
dokploy/0.0.0 darwin-arm64 node-v18.18.0
|
||||
$ dokploy --help [COMMAND]
|
||||
USAGE
|
||||
$ dokploy COMMAND
|
||||
...
|
||||
```
|
||||
<!-- usagestop -->
|
||||
# Commands
|
||||
<!-- commands -->
|
||||
* [`dokploy hello PERSON`](#dokploy-hello-person)
|
||||
* [`dokploy hello world`](#dokploy-hello-world)
|
||||
* [`dokploy help [COMMAND]`](#dokploy-help-command)
|
||||
* [`dokploy plugins`](#dokploy-plugins)
|
||||
* [`dokploy plugins add PLUGIN`](#dokploy-plugins-add-plugin)
|
||||
* [`dokploy plugins:inspect PLUGIN...`](#dokploy-pluginsinspect-plugin)
|
||||
* [`dokploy plugins install PLUGIN`](#dokploy-plugins-install-plugin)
|
||||
* [`dokploy plugins link PATH`](#dokploy-plugins-link-path)
|
||||
* [`dokploy plugins remove [PLUGIN]`](#dokploy-plugins-remove-plugin)
|
||||
* [`dokploy plugins reset`](#dokploy-plugins-reset)
|
||||
* [`dokploy plugins uninstall [PLUGIN]`](#dokploy-plugins-uninstall-plugin)
|
||||
* [`dokploy plugins unlink [PLUGIN]`](#dokploy-plugins-unlink-plugin)
|
||||
* [`dokploy plugins update`](#dokploy-plugins-update)
|
||||
|
||||
## `dokploy hello PERSON`
|
||||
|
||||
Say hello
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ dokploy hello PERSON -f <value>
|
||||
|
||||
ARGUMENTS
|
||||
PERSON Person to say hello to
|
||||
|
||||
FLAGS
|
||||
-f, --from=<value> (required) Who is saying hello
|
||||
|
||||
DESCRIPTION
|
||||
Say hello
|
||||
|
||||
EXAMPLES
|
||||
$ dokploy hello friend --from oclif
|
||||
hello friend from oclif! (./src/commands/hello/index.ts)
|
||||
```
|
||||
|
||||
_See code: [src/commands/hello/index.ts](https://github.com/Dokploy/cli/blob/v0.0.0/src/commands/hello/index.ts)_
|
||||
|
||||
## `dokploy hello world`
|
||||
|
||||
Say hello world
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ dokploy hello world
|
||||
|
||||
DESCRIPTION
|
||||
Say hello world
|
||||
|
||||
EXAMPLES
|
||||
$ dokploy hello world
|
||||
hello world! (./src/commands/hello/world.ts)
|
||||
```
|
||||
|
||||
_See code: [src/commands/hello/world.ts](https://github.com/Dokploy/cli/blob/v0.0.0/src/commands/hello/world.ts)_
|
||||
|
||||
## `dokploy help [COMMAND]`
|
||||
|
||||
Display help for dokploy.
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ dokploy help [COMMAND...] [-n]
|
||||
|
||||
ARGUMENTS
|
||||
COMMAND... Command to show help for.
|
||||
|
||||
FLAGS
|
||||
-n, --nested-commands Include all nested commands in the output.
|
||||
|
||||
DESCRIPTION
|
||||
Display help for dokploy.
|
||||
```
|
||||
|
||||
_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.1.0/src/commands/help.ts)_
|
||||
|
||||
## `dokploy plugins`
|
||||
|
||||
List installed plugins.
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ dokploy plugins [--json] [--core]
|
||||
|
||||
FLAGS
|
||||
--core Show core plugins.
|
||||
|
||||
GLOBAL FLAGS
|
||||
--json Format output as json.
|
||||
|
||||
DESCRIPTION
|
||||
List installed plugins.
|
||||
|
||||
EXAMPLES
|
||||
$ dokploy plugins
|
||||
```
|
||||
|
||||
_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.2.1/src/commands/plugins/index.ts)_
|
||||
|
||||
## `dokploy plugins add PLUGIN`
|
||||
|
||||
Installs a plugin into dokploy.
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ dokploy plugins add PLUGIN... [--json] [-f] [-h] [-s | -v]
|
||||
|
||||
ARGUMENTS
|
||||
PLUGIN... Plugin to install.
|
||||
|
||||
FLAGS
|
||||
-f, --force Force npm to fetch remote resources even if a local copy exists on disk.
|
||||
-h, --help Show CLI help.
|
||||
-s, --silent Silences npm output.
|
||||
-v, --verbose Show verbose npm output.
|
||||
|
||||
GLOBAL FLAGS
|
||||
--json Format output as json.
|
||||
|
||||
DESCRIPTION
|
||||
Installs a plugin into dokploy.
|
||||
|
||||
Uses bundled npm executable to install plugins into /Users/mauricio/.local/share/dokploy
|
||||
|
||||
Installation of a user-installed plugin will override a core plugin.
|
||||
|
||||
Use the DOKPLOY_NPM_LOG_LEVEL environment variable to set the npm loglevel.
|
||||
Use the DOKPLOY_NPM_REGISTRY environment variable to set the npm registry.
|
||||
|
||||
ALIASES
|
||||
$ dokploy plugins add
|
||||
|
||||
EXAMPLES
|
||||
Install a plugin from npm registry.
|
||||
|
||||
$ dokploy plugins add myplugin
|
||||
|
||||
Install a plugin from a github url.
|
||||
|
||||
$ dokploy plugins add https://github.com/someuser/someplugin
|
||||
|
||||
Install a plugin from a github slug.
|
||||
|
||||
$ dokploy plugins add someuser/someplugin
|
||||
```
|
||||
|
||||
## `dokploy plugins:inspect PLUGIN...`
|
||||
|
||||
Displays installation properties of a plugin.
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ dokploy plugins inspect PLUGIN...
|
||||
|
||||
ARGUMENTS
|
||||
PLUGIN... [default: .] Plugin to inspect.
|
||||
|
||||
FLAGS
|
||||
-h, --help Show CLI help.
|
||||
-v, --verbose
|
||||
|
||||
GLOBAL FLAGS
|
||||
--json Format output as json.
|
||||
|
||||
DESCRIPTION
|
||||
Displays installation properties of a plugin.
|
||||
|
||||
EXAMPLES
|
||||
$ dokploy plugins inspect myplugin
|
||||
```
|
||||
|
||||
_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.2.1/src/commands/plugins/inspect.ts)_
|
||||
|
||||
## `dokploy plugins install PLUGIN`
|
||||
|
||||
Installs a plugin into dokploy.
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ dokploy plugins install PLUGIN... [--json] [-f] [-h] [-s | -v]
|
||||
|
||||
ARGUMENTS
|
||||
PLUGIN... Plugin to install.
|
||||
|
||||
FLAGS
|
||||
-f, --force Force npm to fetch remote resources even if a local copy exists on disk.
|
||||
-h, --help Show CLI help.
|
||||
-s, --silent Silences npm output.
|
||||
-v, --verbose Show verbose npm output.
|
||||
|
||||
GLOBAL FLAGS
|
||||
--json Format output as json.
|
||||
|
||||
DESCRIPTION
|
||||
Installs a plugin into dokploy.
|
||||
|
||||
Uses bundled npm executable to install plugins into /Users/mauricio/.local/share/dokploy
|
||||
|
||||
Installation of a user-installed plugin will override a core plugin.
|
||||
|
||||
Use the DOKPLOY_NPM_LOG_LEVEL environment variable to set the npm loglevel.
|
||||
Use the DOKPLOY_NPM_REGISTRY environment variable to set the npm registry.
|
||||
|
||||
ALIASES
|
||||
$ dokploy plugins add
|
||||
|
||||
EXAMPLES
|
||||
Install a plugin from npm registry.
|
||||
|
||||
$ dokploy plugins install myplugin
|
||||
|
||||
Install a plugin from a github url.
|
||||
|
||||
$ dokploy plugins install https://github.com/someuser/someplugin
|
||||
|
||||
Install a plugin from a github slug.
|
||||
|
||||
$ dokploy plugins install someuser/someplugin
|
||||
```
|
||||
|
||||
_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.2.1/src/commands/plugins/install.ts)_
|
||||
|
||||
## `dokploy plugins link PATH`
|
||||
|
||||
Links a plugin into the CLI for development.
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ dokploy plugins link PATH [-h] [--install] [-v]
|
||||
|
||||
ARGUMENTS
|
||||
PATH [default: .] path to plugin
|
||||
|
||||
FLAGS
|
||||
-h, --help Show CLI help.
|
||||
-v, --verbose
|
||||
--[no-]install Install dependencies after linking the plugin.
|
||||
|
||||
DESCRIPTION
|
||||
Links a plugin into the CLI for development.
|
||||
Installation of a linked plugin will override a user-installed or core plugin.
|
||||
|
||||
e.g. If you have a user-installed or core plugin that has a 'hello' command, installing a linked plugin with a 'hello'
|
||||
command will override the user-installed or core plugin implementation. This is useful for development work.
|
||||
|
||||
|
||||
EXAMPLES
|
||||
$ dokploy plugins link myplugin
|
||||
```
|
||||
|
||||
_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.2.1/src/commands/plugins/link.ts)_
|
||||
|
||||
## `dokploy plugins remove [PLUGIN]`
|
||||
|
||||
Removes a plugin from the CLI.
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ dokploy plugins remove [PLUGIN...] [-h] [-v]
|
||||
|
||||
ARGUMENTS
|
||||
PLUGIN... plugin to uninstall
|
||||
|
||||
FLAGS
|
||||
-h, --help Show CLI help.
|
||||
-v, --verbose
|
||||
|
||||
DESCRIPTION
|
||||
Removes a plugin from the CLI.
|
||||
|
||||
ALIASES
|
||||
$ dokploy plugins unlink
|
||||
$ dokploy plugins remove
|
||||
|
||||
EXAMPLES
|
||||
$ dokploy plugins remove myplugin
|
||||
```
|
||||
|
||||
## `dokploy plugins reset`
|
||||
|
||||
Remove all user-installed and linked plugins.
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ dokploy plugins reset [--hard] [--reinstall]
|
||||
|
||||
FLAGS
|
||||
--hard Delete node_modules and package manager related files in addition to uninstalling plugins.
|
||||
--reinstall Reinstall all plugins after uninstalling.
|
||||
```
|
||||
|
||||
_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.2.1/src/commands/plugins/reset.ts)_
|
||||
|
||||
## `dokploy plugins uninstall [PLUGIN]`
|
||||
|
||||
Removes a plugin from the CLI.
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ dokploy plugins uninstall [PLUGIN...] [-h] [-v]
|
||||
|
||||
ARGUMENTS
|
||||
PLUGIN... plugin to uninstall
|
||||
|
||||
FLAGS
|
||||
-h, --help Show CLI help.
|
||||
-v, --verbose
|
||||
|
||||
DESCRIPTION
|
||||
Removes a plugin from the CLI.
|
||||
|
||||
ALIASES
|
||||
$ dokploy plugins unlink
|
||||
$ dokploy plugins remove
|
||||
|
||||
EXAMPLES
|
||||
$ dokploy plugins uninstall myplugin
|
||||
```
|
||||
|
||||
_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.2.1/src/commands/plugins/uninstall.ts)_
|
||||
|
||||
## `dokploy plugins unlink [PLUGIN]`
|
||||
|
||||
Removes a plugin from the CLI.
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ dokploy plugins unlink [PLUGIN...] [-h] [-v]
|
||||
|
||||
ARGUMENTS
|
||||
PLUGIN... plugin to uninstall
|
||||
|
||||
FLAGS
|
||||
-h, --help Show CLI help.
|
||||
-v, --verbose
|
||||
|
||||
DESCRIPTION
|
||||
Removes a plugin from the CLI.
|
||||
|
||||
ALIASES
|
||||
$ dokploy plugins unlink
|
||||
$ dokploy plugins remove
|
||||
|
||||
EXAMPLES
|
||||
$ dokploy plugins unlink myplugin
|
||||
```
|
||||
|
||||
## `dokploy plugins update`
|
||||
|
||||
Update installed plugins.
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ dokploy plugins update [-h] [-v]
|
||||
|
||||
FLAGS
|
||||
-h, --help Show CLI help.
|
||||
-v, --verbose
|
||||
|
||||
DESCRIPTION
|
||||
Update installed plugins.
|
||||
```
|
||||
|
||||
_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.2.1/src/commands/plugins/update.ts)_
|
||||
<!-- commandsstop -->
|
||||
|
||||
103
src/commands/app/create.ts
Normal file
103
src/commands/app/create.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
|
||||
import { type Project, getProjects } from "../../utils/shared.js";
|
||||
import { slugify } from "../../utils/slug.js";
|
||||
import { readAuthConfig } from "../../utils/utils.js";
|
||||
|
||||
export interface Answers {
|
||||
project: Project;
|
||||
}
|
||||
|
||||
export default class AppCreate extends Command {
|
||||
static description = "Create a new application within a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> app create"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
const { flags } = await this.parse(AppCreate);
|
||||
|
||||
let { projectId } = flags;
|
||||
|
||||
if (!projectId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to create the application in:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
projectId = project.projectId;
|
||||
|
||||
const appDetails = await inquirer.prompt([
|
||||
{
|
||||
message: "Enter the application name:",
|
||||
name: "name",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Application name is required"),
|
||||
},
|
||||
{
|
||||
message: "Enter the application description (optional):",
|
||||
name: "appDescription",
|
||||
type: "input",
|
||||
},
|
||||
]);
|
||||
|
||||
const appName = await inquirer.prompt([
|
||||
{
|
||||
default: `${slugify(project.name)}-${appDetails.name}`,
|
||||
message: "Enter the App name: (optional):",
|
||||
name: "appName",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "App name is required"),
|
||||
},
|
||||
]);
|
||||
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/application.create`,
|
||||
{
|
||||
json: {
|
||||
...appDetails,
|
||||
appName: appName.appName,
|
||||
projectId: project.projectId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error creating application"));
|
||||
}
|
||||
|
||||
this.log(
|
||||
chalk.green(`Application '${appDetails.name}' created successfully.`),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
108
src/commands/app/delete.ts
Normal file
108
src/commands/app/delete.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
|
||||
import { getProject, getProjects } from "../../utils/shared.js";
|
||||
import { readAuthConfig } from "../../utils/utils.js";
|
||||
import type { Answers } from "./create.js";
|
||||
|
||||
export default class AppDelete extends Command {
|
||||
static description = "Delete an application from a project.";
|
||||
|
||||
static examples = [
|
||||
"$ <%= config.bin %> app delete",
|
||||
"$ <%= config.bin %> app delete -p <projectId>",
|
||||
];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
const { flags } = await this.parse(AppDelete);
|
||||
|
||||
let { projectId } = flags;
|
||||
|
||||
if (!projectId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to create the application in:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
projectId = project.projectId;
|
||||
const projectSelected = await getProject(projectId, auth, this);
|
||||
|
||||
if (projectSelected.applications.length === 0) {
|
||||
this.error(chalk.yellow("No applications found in this project."));
|
||||
}
|
||||
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
// @ts-ignore
|
||||
choices: projectSelected.applications.map((app) => ({
|
||||
name: app.name,
|
||||
value: app.applicationId,
|
||||
})),
|
||||
message: "Select the application to delete:",
|
||||
name: "selectedApp",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const applicationId = appAnswers.selectedApp;
|
||||
|
||||
// // Confirmar eliminación
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to delete this application?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("Application deletion cancelled."));
|
||||
}
|
||||
|
||||
const deleteResponse = await axios.post(
|
||||
`${auth.url}/api/trpc/application.delete`,
|
||||
{
|
||||
json: {
|
||||
applicationId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!deleteResponse.data.result.data.json) {
|
||||
this.error(chalk.red("Error deleting application"));
|
||||
}
|
||||
|
||||
this.log(chalk.green("Application deleted successfully."));
|
||||
}
|
||||
}
|
||||
}
|
||||
89
src/commands/app/deploy.ts
Normal file
89
src/commands/app/deploy.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { Command } from "@oclif/core";
|
||||
import { readAuthConfig } from "../../utils/utils.js";
|
||||
import chalk from "chalk";
|
||||
import { getProject, getProjects } from "../../utils/shared.js";
|
||||
import inquirer from "inquirer";
|
||||
import type { Answers } from "./create.js";
|
||||
import axios from "axios";
|
||||
|
||||
export default class AppDeploy extends Command {
|
||||
static description = "Deploy an application to a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> app deploy"];
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to deploy the application in:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const projectId = project.projectId;
|
||||
|
||||
const projectSelected = await getProject(projectId, auth, this);
|
||||
|
||||
if (projectSelected.applications.length === 0) {
|
||||
this.error(chalk.yellow("No applications found in this project."));
|
||||
}
|
||||
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
// @ts-ignore
|
||||
choices: projectSelected.applications.map((app) => ({
|
||||
name: app.name,
|
||||
value: app.applicationId,
|
||||
})),
|
||||
message: "Select the application to deploy:",
|
||||
name: "selectedApp",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const applicationId = appAnswers.selectedApp;
|
||||
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to deploy this application?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("Application deployment cancelled."));
|
||||
}
|
||||
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/application.deploy`,
|
||||
{
|
||||
json: {
|
||||
applicationId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error deploying application"));
|
||||
}
|
||||
this.log(chalk.green("Application deploy successful."));
|
||||
}
|
||||
}
|
||||
89
src/commands/app/stop.ts
Normal file
89
src/commands/app/stop.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { Command } from "@oclif/core";
|
||||
import { readAuthConfig } from "../../utils/utils.js";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
import { getProject, getProjects } from "../../utils/shared.js";
|
||||
import type { Answers } from "./create.js";
|
||||
import axios from "axios";
|
||||
|
||||
export default class AppStop extends Command {
|
||||
static description = "Stop an application from a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> app stop"];
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to stop the application in:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const projectId = project.projectId;
|
||||
|
||||
const projectSelected = await getProject(projectId, auth, this);
|
||||
|
||||
if (projectSelected.applications.length === 0) {
|
||||
this.error(chalk.yellow("No applications found in this project."));
|
||||
}
|
||||
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
// @ts-ignore
|
||||
choices: projectSelected.applications.map((app) => ({
|
||||
name: app.name,
|
||||
value: app.applicationId,
|
||||
})),
|
||||
message: "Select the application to stop:",
|
||||
name: "selectedApp",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const applicationId = appAnswers.selectedApp;
|
||||
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to stop this application?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("Application stop cancelled."));
|
||||
}
|
||||
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/application.stop`,
|
||||
{
|
||||
json: {
|
||||
applicationId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error stopping application"));
|
||||
}
|
||||
this.log(chalk.green("Application stop successful."));
|
||||
}
|
||||
}
|
||||
106
src/commands/authenticate.ts
Normal file
106
src/commands/authenticate.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer, { type Answers, type QuestionCollection } from "inquirer";
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const configPath = path.join(__dirname, "..", "..", "config.json");
|
||||
|
||||
export default class Authenticate extends Command {
|
||||
static description = "Authenticate the user by saving server URL and token";
|
||||
|
||||
static examples = [
|
||||
"$ <%= config.bin %> <%= command.id %> --url=https://panel.dokploy.com --token=MRTHGZDGMRZWM43EMZSHGZTTMRTHGZDGONSGMZDTMY",
|
||||
"$ <%= config.bin %> <%= command.id %> -u https://panel.dokploy.com -t MRTHGZDGMRZWM43EMZSHGZTTMRTHGZDGONSGMZDTMY",
|
||||
];
|
||||
|
||||
static flags = {
|
||||
token: Flags.string({
|
||||
char: "t",
|
||||
description: "Authentication token",
|
||||
}),
|
||||
url: Flags.string({
|
||||
char: "u",
|
||||
description: "Server URL",
|
||||
}),
|
||||
};
|
||||
|
||||
async run() {
|
||||
console.log(
|
||||
chalk.blue.bold("\n Welcome to Dokploy CLI Authentication \n"),
|
||||
);
|
||||
|
||||
const { flags } = await this.parse(Authenticate);
|
||||
|
||||
let answers: Answers = {};
|
||||
|
||||
const questions: QuestionCollection[] = [];
|
||||
|
||||
let config: { token?: string; url?: string } = {};
|
||||
if (fs.existsSync(configPath)) {
|
||||
const configFileContent = fs.readFileSync(configPath, "utf8");
|
||||
config = JSON.parse(configFileContent);
|
||||
}
|
||||
|
||||
if (!flags.url) {
|
||||
questions.push({
|
||||
default: config.url,
|
||||
message: chalk.green(
|
||||
"Enter your server URL (e.g., https://panel.dokploy.com): ",
|
||||
),
|
||||
name: "url",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Server URL is required"),
|
||||
});
|
||||
}
|
||||
|
||||
if (!flags.token) {
|
||||
questions.push({
|
||||
default: config.token,
|
||||
message: chalk.green(
|
||||
"Enter your authentication token (e.g., MRTHGZDGMRZWM43EMZSHGZTTMRTHGZDGONSGMZDTMY=): ",
|
||||
),
|
||||
name: "token",
|
||||
type: "input",
|
||||
validate: (input) =>
|
||||
input ? true : "Authentication token is required",
|
||||
});
|
||||
}
|
||||
|
||||
if (questions.length > 0) {
|
||||
answers = await inquirer.prompt(questions);
|
||||
}
|
||||
|
||||
const url = flags.url || answers.url;
|
||||
const token = flags.token || answers.token;
|
||||
|
||||
config.token = token;
|
||||
config.url = url;
|
||||
|
||||
try {
|
||||
console.log(`\n${chalk.blue("Validating server...")}`);
|
||||
|
||||
await axios.post(
|
||||
`${url}/api/trpc/auth.verifyToken`,
|
||||
{},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
||||
this.log(chalk.green("Authentication details saved successfully."));
|
||||
} catch (error) {
|
||||
this.error(
|
||||
// @ts-expect-error - Type
|
||||
chalk.red(`Failed to save authentication details: ${error.message}`),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
129
src/commands/database/mariadb/create.ts
Normal file
129
src/commands/database/mariadb/create.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import { getProjects } from "../../../utils/shared.js";
|
||||
import { slugify } from "../../../utils/slug.js";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
|
||||
export default class DatabaseMariadbCreate extends Command {
|
||||
static description = "Create a new MariaDB database within a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> mariadb create"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
const { flags } = await this.parse(DatabaseMariadbCreate);
|
||||
|
||||
let { projectId } = flags;
|
||||
|
||||
if (!projectId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to create the MariaDB database in:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
projectId = project.projectId;
|
||||
|
||||
const dbDetails = await inquirer.prompt([
|
||||
{
|
||||
message: "Enter the name:",
|
||||
name: "name",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Database name is required"),
|
||||
},
|
||||
{
|
||||
message: "Database name:",
|
||||
name: "databaseName",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Database name is required"),
|
||||
},
|
||||
{
|
||||
message: "Enter the database description (optional):",
|
||||
name: "description",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
message: "Database Root Password (optional):",
|
||||
name: "databaseRootPassword",
|
||||
type: "password",
|
||||
},
|
||||
{
|
||||
message: "Database password (optional):",
|
||||
name: "databasePassword",
|
||||
type: "password",
|
||||
},
|
||||
{
|
||||
default: "mariadb:11",
|
||||
message: "Docker Image (default: mariadb:11):",
|
||||
name: "dockerImage",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
default: "mariadb",
|
||||
message: "Database User: (default: mariadb):",
|
||||
name: "databaseUser",
|
||||
type: "input",
|
||||
},
|
||||
]);
|
||||
|
||||
const appName = await inquirer.prompt([
|
||||
{
|
||||
default: `${slugify(project.name)}-${dbDetails.name}`,
|
||||
message: "Enter the App name:",
|
||||
name: "appName",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "App name is required"),
|
||||
},
|
||||
]);
|
||||
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mariadb.create`,
|
||||
{
|
||||
json: {
|
||||
...dbDetails,
|
||||
appName: appName.appName,
|
||||
projectId: project.projectId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
this.error(chalk.red("Error creating MariaDB database"));
|
||||
}
|
||||
|
||||
this.log(
|
||||
chalk.green(
|
||||
`MariaDB database '${dbDetails.name}' created successfully.`,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
113
src/commands/database/mariadb/delete.ts
Normal file
113
src/commands/database/mariadb/delete.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
|
||||
import { getProject, getProjects } from "../../../utils/shared.js";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
|
||||
export default class DatabaseMariadbDelete extends Command {
|
||||
static description = "Delete a MariaDB database from a project.";
|
||||
static examples = [
|
||||
"$ <%= config.bin %> mariadb delete",
|
||||
"$ <%= config.bin %> mariadb delete -p <projectId>",
|
||||
];
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabaseMariadbDelete);
|
||||
let { projectId } = flags;
|
||||
|
||||
if (!projectId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
if (projects.length === 0) {
|
||||
this.log(chalk.yellow("No projects found."));
|
||||
return;
|
||||
}
|
||||
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
type: "list",
|
||||
name: "selectedProject",
|
||||
message: "Select a project to delete the MariaDB database from:",
|
||||
choices: projects.map((project: any) => ({
|
||||
name: project.name,
|
||||
value: project.projectId,
|
||||
})),
|
||||
},
|
||||
]);
|
||||
projectId = answers.selectedProject;
|
||||
}
|
||||
|
||||
try {
|
||||
const project = await getProject(projectId, auth, this);
|
||||
|
||||
if (!project.mariadb || project.mariadb.length === 0) {
|
||||
this.log(chalk.yellow("No MariaDB databases found in this project."));
|
||||
return;
|
||||
}
|
||||
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
type: "list",
|
||||
name: "selectedDb",
|
||||
message: "Select the MariaDB database to delete:",
|
||||
choices: project.mariadb.map((db: any) => ({
|
||||
name: db.name,
|
||||
value: db.mariadbId,
|
||||
})),
|
||||
},
|
||||
]);
|
||||
|
||||
const mariadbId = appAnswers.selectedDb;
|
||||
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
type: "confirm",
|
||||
name: "confirmDelete",
|
||||
message: "Are you sure you want to delete this MariaDB database?",
|
||||
default: false,
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.log(chalk.yellow("Database deletion cancelled."));
|
||||
return;
|
||||
}
|
||||
|
||||
const deleteResponse = await axios.post(
|
||||
`${auth.url}/api/trpc/mariadb.remove`,
|
||||
{
|
||||
json: {
|
||||
mariadbId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!deleteResponse.data.result.data.json) {
|
||||
this.error(chalk.red("Error deleting mariadb database"));
|
||||
}
|
||||
this.log(chalk.green("MariaDB database deleted successfully."));
|
||||
} catch (error) {
|
||||
this.error(
|
||||
// @ts-ignore
|
||||
chalk.red(`Failed to delete MariaDB database: ${error.message}`),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
89
src/commands/database/mariadb/deploy.ts
Normal file
89
src/commands/database/mariadb/deploy.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { Command } from "@oclif/core";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import chalk from "chalk";
|
||||
import { getProject, getProjects } from "../../../utils/shared.js";
|
||||
import inquirer from "inquirer";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
import axios from "axios";
|
||||
|
||||
export default class DatabaseMariadbDeploy extends Command {
|
||||
static description = "Deploy an mariadb to a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> app deploy"];
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to deploy the mariadb in:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const projectId = project.projectId;
|
||||
|
||||
const projectSelected = await getProject(projectId, auth, this);
|
||||
|
||||
if (projectSelected.mariadb.length === 0) {
|
||||
this.error(chalk.yellow("No mariadb found in this project."));
|
||||
}
|
||||
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
// @ts-ignore
|
||||
choices: projectSelected.mariadb.map((app) => ({
|
||||
name: app.name,
|
||||
value: app.mariadbId,
|
||||
})),
|
||||
message: "Select the mariadb to deploy:",
|
||||
name: "selectedApp",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const mariadbId = appAnswers.selectedApp;
|
||||
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to deploy this mariadb?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("mariadb deployment cancelled."));
|
||||
}
|
||||
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mariadb.deploy`,
|
||||
{
|
||||
json: {
|
||||
mariadbId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error deploying mariadb"));
|
||||
}
|
||||
this.log(chalk.green("Mariadb deploy successful."));
|
||||
}
|
||||
}
|
||||
89
src/commands/database/mariadb/stop.ts
Normal file
89
src/commands/database/mariadb/stop.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { Command } from "@oclif/core";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
import axios from "axios";
|
||||
import { getProject, getProjects } from "../../../utils/shared.js";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
|
||||
export default class DatabaseMariadbStop extends Command {
|
||||
static description = "Stop an mariadb from a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> mariadb stop"];
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to stop the mariadb in:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const projectId = project.projectId;
|
||||
|
||||
const projectSelected = await getProject(projectId, auth, this);
|
||||
|
||||
if (projectSelected.mariadb.length === 0) {
|
||||
this.error(chalk.yellow("No mariadb found in this project."));
|
||||
}
|
||||
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
// @ts-ignore
|
||||
choices: projectSelected.mariadb.map((app) => ({
|
||||
name: app.name,
|
||||
value: app.mariadbId,
|
||||
})),
|
||||
message: "Select the mariadb to stop:",
|
||||
name: "selectedApp",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const mariadbId = appAnswers.selectedApp;
|
||||
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to stop this mariadb?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("Mariadb stop cancelled."));
|
||||
}
|
||||
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mariadb.stop`,
|
||||
{
|
||||
json: {
|
||||
mariadbId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error stopping mariadb"));
|
||||
}
|
||||
this.log(chalk.green("Mariadb stop successful."));
|
||||
}
|
||||
}
|
||||
131
src/commands/database/mongo/create.ts
Normal file
131
src/commands/database/mongo/create.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import { getProjects } from "../../../utils/shared.js";
|
||||
import { slugify } from "../../../utils/slug.js";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
|
||||
export default class DatabaseMongoCreate extends Command {
|
||||
static description = "Create a new MongoDB database within a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> mongo create"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
const { flags } = await this.parse(DatabaseMongoCreate);
|
||||
|
||||
let { projectId } = flags;
|
||||
|
||||
if (!projectId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to create the MongoDB database in:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
projectId = project.projectId;
|
||||
|
||||
const dbDetails = await inquirer.prompt([
|
||||
{
|
||||
message: "Enter the name:",
|
||||
name: "name",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Database name is required"),
|
||||
},
|
||||
{
|
||||
message: "Database name:",
|
||||
name: "databaseName",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Database name is required"),
|
||||
},
|
||||
{
|
||||
message: "Enter the database description (optional):",
|
||||
name: "description",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
message: "Database password (optional):",
|
||||
name: "databasePassword",
|
||||
type: "password",
|
||||
},
|
||||
{
|
||||
default: "mongo:6",
|
||||
message: "Docker Image (default: mongo:6):",
|
||||
name: "dockerImage",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
default: "mongo",
|
||||
message: "Database User: (default: mongo):",
|
||||
name: "databaseUser",
|
||||
type: "input",
|
||||
},
|
||||
]);
|
||||
|
||||
const appName = await inquirer.prompt([
|
||||
{
|
||||
default: `${slugify(project.name)}-${dbDetails.name}`,
|
||||
message: "Enter the App name:",
|
||||
name: "appName",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "App name is required"),
|
||||
},
|
||||
]);
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mongo.create`,
|
||||
{
|
||||
json: {
|
||||
...dbDetails,
|
||||
appName: appName.appName,
|
||||
projectId: project.projectId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
this.error(chalk.red("Error creating MongoDB database"));
|
||||
}
|
||||
|
||||
this.log(
|
||||
chalk.green(
|
||||
`MongoDB database '${dbDetails.name}' created successfully.`,
|
||||
),
|
||||
);
|
||||
} catch (error) {
|
||||
this.error(
|
||||
// @ts-ignore
|
||||
chalk.red(`Failed to create MongoDB database: ${error.message}`),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
119
src/commands/database/mongo/delete.ts
Normal file
119
src/commands/database/mongo/delete.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import { getProject, getProjects } from "../../../utils/shared.js";
|
||||
|
||||
export default class DatabaseMongoDelete extends Command {
|
||||
static description = "Delete a MongoDB database from a project.";
|
||||
|
||||
static examples = [
|
||||
"$ <%= config.bin %> mongo delete",
|
||||
"$ <%= config.bin %> mongo delete -p <projectId>",
|
||||
];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
const { flags } = await this.parse(DatabaseMongoDelete);
|
||||
let { projectId } = flags;
|
||||
|
||||
if (!projectId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
if (projects.length === 0) {
|
||||
this.log(chalk.yellow("No projects found."));
|
||||
return;
|
||||
}
|
||||
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
choices: projects.map((project: any) => ({
|
||||
name: project.name,
|
||||
value: project.projectId,
|
||||
})),
|
||||
message: "Select a project to delete the MongoDB database from:",
|
||||
name: "selectedProject",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
projectId = answers.selectedProject;
|
||||
}
|
||||
|
||||
try {
|
||||
const project = await getProject(projectId, auth, this);
|
||||
|
||||
if (!project.mongo || project.mongo.length === 0) {
|
||||
this.log(chalk.yellow("No MongoDB databases found in this project."));
|
||||
return;
|
||||
}
|
||||
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: project.mongo.map((db: any) => ({
|
||||
name: db.name,
|
||||
value: db.mongoId,
|
||||
})),
|
||||
message: "Select the MongoDB database to delete:",
|
||||
name: "selectedApp",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const mongoId = appAnswers.selectedApp;
|
||||
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to delete this MongoDB database?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.log(chalk.yellow("Database deletion cancelled."));
|
||||
return;
|
||||
}
|
||||
|
||||
const deleteResponse = await axios.post(
|
||||
`${auth.url}/api/trpc/mongo.remove`,
|
||||
{
|
||||
json: {
|
||||
mongoId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!deleteResponse.data.result.data.json) {
|
||||
this.error(chalk.red("Error deleting MongoDB database"));
|
||||
}
|
||||
|
||||
this.log(chalk.green("MongoDB database deleted successfully."));
|
||||
} catch (error) {
|
||||
this.error(
|
||||
// @ts-ignore
|
||||
chalk.red(`Failed to delete MongoDB database: ${error.message}`),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
89
src/commands/database/mongo/deploy.ts
Normal file
89
src/commands/database/mongo/deploy.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { Command } from "@oclif/core";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import chalk from "chalk";
|
||||
import { getProject, getProjects } from "../../../utils/shared.js";
|
||||
import inquirer from "inquirer";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
import axios from "axios";
|
||||
|
||||
export default class DatabaseMongoDeploy extends Command {
|
||||
static description = "Deploy an mongo to a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> app deploy"];
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to deploy the mongo in:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const projectId = project.projectId;
|
||||
|
||||
const projectSelected = await getProject(projectId, auth, this);
|
||||
|
||||
if (projectSelected.mongo.length === 0) {
|
||||
this.error(chalk.yellow("No mongo found in this project."));
|
||||
}
|
||||
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
// @ts-ignore
|
||||
choices: projectSelected.mongo.map((app) => ({
|
||||
name: app.name,
|
||||
value: app.mongoId,
|
||||
})),
|
||||
message: "Select the mongo to deploy:",
|
||||
name: "selectedApp",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const mongoId = appAnswers.selectedApp;
|
||||
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to deploy this mongo?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("mongo deployment cancelled."));
|
||||
}
|
||||
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mongo.deploy`,
|
||||
{
|
||||
json: {
|
||||
mongoId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error deploying mongo"));
|
||||
}
|
||||
this.log(chalk.green("Mongo deploy successful."));
|
||||
}
|
||||
}
|
||||
89
src/commands/database/mongo/stop.ts
Normal file
89
src/commands/database/mongo/stop.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { Command } from "@oclif/core";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
import axios from "axios";
|
||||
import { getProject, getProjects } from "../../../utils/shared.js";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
|
||||
export default class DatabaseMongoStop extends Command {
|
||||
static description = "Stop an mongo from a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> mongo stop"];
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to stop the mongo in:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const projectId = project.projectId;
|
||||
|
||||
const projectSelected = await getProject(projectId, auth, this);
|
||||
|
||||
if (projectSelected.mongo.length === 0) {
|
||||
this.error(chalk.yellow("No mongo found in this project."));
|
||||
}
|
||||
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
// @ts-ignore
|
||||
choices: projectSelected.mongo.map((app) => ({
|
||||
name: app.name,
|
||||
value: app.mongoId,
|
||||
})),
|
||||
message: "Select the mongo to stop:",
|
||||
name: "selectedApp",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const mongoId = appAnswers.selectedApp;
|
||||
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to stop this mongo?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("mongo stop cancelled."));
|
||||
}
|
||||
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mongo.stop`,
|
||||
{
|
||||
json: {
|
||||
mongoId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error stopping mongo"));
|
||||
}
|
||||
this.log(chalk.green("Mongo stop successful."));
|
||||
}
|
||||
}
|
||||
137
src/commands/database/mysql/create.ts
Normal file
137
src/commands/database/mysql/create.ts
Normal file
@@ -0,0 +1,137 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
|
||||
import { slugify } from "../../../utils/slug.js";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import { getProjects } from "../../../utils/shared.js";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
|
||||
export default class DatabaseMysqlCreate extends Command {
|
||||
static description = "Create a new MySQL database within a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> mysql create"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
const { flags } = await this.parse(DatabaseMysqlCreate);
|
||||
|
||||
let { projectId } = flags;
|
||||
|
||||
if (!projectId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to create the MySQL database in:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
projectId = project.projectId;
|
||||
|
||||
const dbDetails = await inquirer.prompt([
|
||||
{
|
||||
message: "Enter the name:",
|
||||
name: "name",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Database name is required"),
|
||||
},
|
||||
{
|
||||
message: "Database name:",
|
||||
name: "databaseName",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Database name is required"),
|
||||
},
|
||||
{
|
||||
message: "Enter the database description (optional):",
|
||||
name: "description",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
message: "Database Root Password (optional):",
|
||||
name: "databaseRootPassword",
|
||||
type: "password",
|
||||
},
|
||||
{
|
||||
message: "Database password (optional):",
|
||||
name: "databasePassword",
|
||||
type: "password",
|
||||
},
|
||||
{
|
||||
default: "mysql:8",
|
||||
message: "Docker Image (default: mysql:8):",
|
||||
name: "dockerImage",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
default: "mysql",
|
||||
message: "Database User: (default: mysql):",
|
||||
name: "databaseUser",
|
||||
type: "input",
|
||||
},
|
||||
]);
|
||||
|
||||
const appName = await inquirer.prompt([
|
||||
{
|
||||
default: `${slugify(project.name)}-${dbDetails.name}`,
|
||||
message: "Enter the App name:",
|
||||
name: "appName",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "App name is required"),
|
||||
},
|
||||
]);
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mysql.create`,
|
||||
{
|
||||
json: {
|
||||
...dbDetails,
|
||||
appName: appName.appName,
|
||||
projectId: project.projectId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
this.error(chalk.red("Error creating MySQL database"));
|
||||
}
|
||||
|
||||
this.log(
|
||||
chalk.green(
|
||||
`MySQL database '${dbDetails.name}' created successfully.`,
|
||||
),
|
||||
);
|
||||
} catch (error) {
|
||||
this.error(
|
||||
// @ts-ignore
|
||||
chalk.red(`Failed to create MySQL database: ${error.message}`),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
120
src/commands/database/mysql/delete.ts
Normal file
120
src/commands/database/mysql/delete.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import { getProject, getProjects } from "../../../utils/shared.js";
|
||||
|
||||
export default class DatabaseMysqlDelete extends Command {
|
||||
static description = "Delete a MySQL database from a project.";
|
||||
|
||||
static examples = [
|
||||
"$ <%= config.bin %> mysql delete",
|
||||
"$ <%= config.bin %> mysql delete -p <projectId>",
|
||||
];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
const { flags } = await this.parse(DatabaseMysqlDelete);
|
||||
let { projectId } = flags;
|
||||
|
||||
if (!projectId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
if (projects.length === 0) {
|
||||
this.log(chalk.yellow("No projects found."));
|
||||
return;
|
||||
}
|
||||
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
choices: projects.map((project: any) => ({
|
||||
name: project.name,
|
||||
value: project.projectId,
|
||||
})),
|
||||
message: "Select a project to delete the MySQL database from:",
|
||||
name: "selectedProject",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
projectId = answers.selectedProject;
|
||||
}
|
||||
|
||||
try {
|
||||
const project = await getProject(projectId, auth, this);
|
||||
|
||||
if (!project.mysql || project.mysql.length === 0) {
|
||||
this.log(chalk.yellow("No MySQL databases found in this project."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Permitir al usuario seleccionar una aplicación
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: project.mysql.map((app: any) => ({
|
||||
name: app.name,
|
||||
value: app.mysqlId,
|
||||
})),
|
||||
message: "Select the MySQL database to delete:",
|
||||
name: "selectedApp",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const mysqlId = appAnswers.selectedApp;
|
||||
|
||||
// Confirmar eliminación
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to delete this mysql database?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.log(chalk.yellow("Application deletion cancelled."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Eliminar la aplicación seleccionada
|
||||
const deleteResponse = await axios.post(
|
||||
`${auth.url}/api/trpc/mysql.remove`,
|
||||
{
|
||||
json: {
|
||||
mysqlId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!deleteResponse.data.result.data.json) {
|
||||
this.error(chalk.red("Error deleting application"));
|
||||
}
|
||||
|
||||
this.log(chalk.green("Application deleted successfully."));
|
||||
} catch (error) {
|
||||
// @ts-expect-error - TS2339: Property 'data' does not exist on type 'AxiosError<any>'.
|
||||
this.error(chalk.red(`Failed to delete application: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
89
src/commands/database/mysql/deploy.ts
Normal file
89
src/commands/database/mysql/deploy.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { Command } from "@oclif/core";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import chalk from "chalk";
|
||||
import { getProject, getProjects } from "../../../utils/shared.js";
|
||||
import inquirer from "inquirer";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
import axios from "axios";
|
||||
|
||||
export default class DatabaseMysqlDeploy extends Command {
|
||||
static description = "Deploy an mysql to a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> app deploy"];
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to deploy the mysql in:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const projectId = project.projectId;
|
||||
|
||||
const projectSelected = await getProject(projectId, auth, this);
|
||||
|
||||
if (projectSelected.mysql.length === 0) {
|
||||
this.error(chalk.yellow("No mysql found in this project."));
|
||||
}
|
||||
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
// @ts-ignore
|
||||
choices: projectSelected.mysql.map((app) => ({
|
||||
name: app.name,
|
||||
value: app.mysqlId,
|
||||
})),
|
||||
message: "Select the mysql to deploy:",
|
||||
name: "selectedApp",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const mysqlId = appAnswers.selectedApp;
|
||||
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to deploy this mysql?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("mysql deployment cancelled."));
|
||||
}
|
||||
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mysql.deploy`,
|
||||
{
|
||||
json: {
|
||||
mysqlId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error deploying mysql"));
|
||||
}
|
||||
this.log(chalk.green("Mysql deployed successful."));
|
||||
}
|
||||
}
|
||||
89
src/commands/database/mysql/stop.ts
Normal file
89
src/commands/database/mysql/stop.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { Command } from "@oclif/core";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
import axios from "axios";
|
||||
import { getProject, getProjects } from "../../../utils/shared.js";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
|
||||
export default class DatabaseMysqlStop extends Command {
|
||||
static description = "Stop an mysql from a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> mysql stop"];
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to stop the mysql in:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const projectId = project.projectId;
|
||||
|
||||
const projectSelected = await getProject(projectId, auth, this);
|
||||
|
||||
if (projectSelected.mysql.length === 0) {
|
||||
this.error(chalk.yellow("No mysql found in this project."));
|
||||
}
|
||||
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
// @ts-ignore
|
||||
choices: projectSelected.mysql.map((app) => ({
|
||||
name: app.name,
|
||||
value: app.mysqlId,
|
||||
})),
|
||||
message: "Select the mysql to stop:",
|
||||
name: "selectedApp",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const mysqlId = appAnswers.selectedApp;
|
||||
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to stop this mysql?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("mysql stop cancelled."));
|
||||
}
|
||||
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mysql.stop`,
|
||||
{
|
||||
json: {
|
||||
mysqlId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error stopping mysql"));
|
||||
}
|
||||
this.log(chalk.green("Mysql stop successful."));
|
||||
}
|
||||
}
|
||||
130
src/commands/database/postgres/create.ts
Normal file
130
src/commands/database/postgres/create.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
import { slugify } from "../../../utils/slug.js";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import { getProjects } from "../../../utils/shared.js";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
export default class DatabasePostgresCreate extends Command {
|
||||
static description = "Create a new PostgreSQL database within a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> postgres create"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
const { flags } = await this.parse(DatabasePostgresCreate);
|
||||
|
||||
let { projectId } = flags;
|
||||
|
||||
if (!projectId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to create the PostgreSQL database in:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
projectId = project.projectId;
|
||||
|
||||
const dbDetails = await inquirer.prompt([
|
||||
{
|
||||
message: "Enter the name:",
|
||||
name: "name",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Database name is required"),
|
||||
},
|
||||
{
|
||||
message: "Database name:",
|
||||
name: "databaseName",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Database name is required"),
|
||||
},
|
||||
{
|
||||
message: "Enter the database description (optional):",
|
||||
name: "description",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
message: "Database password (optional):",
|
||||
name: "databasePassword",
|
||||
type: "password",
|
||||
},
|
||||
{
|
||||
default: "postgres:15",
|
||||
message: "Docker Image (default: postgres:15):",
|
||||
name: "dockerImage",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
default: "postgres",
|
||||
message: "Database User: (default: postgres):",
|
||||
name: "databaseUser",
|
||||
type: "input",
|
||||
},
|
||||
]);
|
||||
|
||||
const appName = await inquirer.prompt([
|
||||
{
|
||||
default: `${slugify(project.name)}-${dbDetails.name}`,
|
||||
message: "Enter the App name:",
|
||||
name: "appName",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "App name is required"),
|
||||
},
|
||||
]);
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/postgres.create`,
|
||||
{
|
||||
json: {
|
||||
...dbDetails,
|
||||
appName: appName.appName,
|
||||
projectId: project.projectId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
this.error(chalk.red("Error creating PostgreSQL database"));
|
||||
}
|
||||
|
||||
this.log(
|
||||
chalk.green(
|
||||
`PostgreSQL database '${dbDetails.name}' created successfully.`,
|
||||
),
|
||||
);
|
||||
} catch (error) {
|
||||
this.error(
|
||||
// @ts-ignore
|
||||
chalk.red(`Failed to create PostgreSQL database: ${error.message}`),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
119
src/commands/database/postgres/delete.ts
Normal file
119
src/commands/database/postgres/delete.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import { getProject, getProjects } from "../../../utils/shared.js";
|
||||
|
||||
export default class DatabasePostgresDelete extends Command {
|
||||
static description = "Delete a PostgreSQL database from a project.";
|
||||
|
||||
static examples = [
|
||||
"$ <%= config.bin %> postgres delete",
|
||||
"$ <%= config.bin %> postgres delete -p <projectId>",
|
||||
];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
const { flags } = await this.parse(DatabasePostgresDelete);
|
||||
let { projectId } = flags;
|
||||
|
||||
if (!projectId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
if (projects.length === 0) {
|
||||
this.log(chalk.yellow("No projects found."));
|
||||
return;
|
||||
}
|
||||
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
choices: projects.map((project: any) => ({
|
||||
name: project.name,
|
||||
value: project.projectId,
|
||||
})),
|
||||
message: "Select a project to delete the PostgreSQL database from:",
|
||||
name: "selectedProject",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
projectId = answers.selectedProject;
|
||||
}
|
||||
|
||||
try {
|
||||
const project = await getProject(projectId, auth, this);
|
||||
|
||||
if (!project.postgres || project.postgres.length === 0) {
|
||||
this.log(
|
||||
chalk.yellow("No PostgreSQL databases found in this project."),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: project.postgres.map((db: any) => ({
|
||||
name: db.name,
|
||||
value: db.postgresId,
|
||||
})),
|
||||
message: "Select the PostgreSQL database to delete:",
|
||||
name: "selectedApp",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const postgresId = appAnswers.selectedApp;
|
||||
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to delete this postgres database?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.log(chalk.yellow("Database deletion cancelled."));
|
||||
return;
|
||||
}
|
||||
|
||||
const deleteResponse = await axios.post(
|
||||
`${auth.url}/api/trpc/postgres.remove`,
|
||||
{
|
||||
json: {
|
||||
postgresId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!deleteResponse.data.result.data.json) {
|
||||
this.error(chalk.red("Error deleting PostgreSQL database"));
|
||||
}
|
||||
|
||||
this.log(chalk.green("PostgreSQL database deleted successfully."));
|
||||
} catch (error) {
|
||||
// @ts-expect-error - TS2339: Property 'data' does not exist on type 'AxiosError<any>'.
|
||||
this.error(chalk.red(`Failed to delete application: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
89
src/commands/database/postgres/deploy.ts
Normal file
89
src/commands/database/postgres/deploy.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { Command } from "@oclif/core";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import chalk from "chalk";
|
||||
import { getProject, getProjects } from "../../../utils/shared.js";
|
||||
import inquirer from "inquirer";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
import axios from "axios";
|
||||
|
||||
export default class DatabasePostgresDeploy extends Command {
|
||||
static description = "Deploy an postgres to a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> app deploy"];
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to deploy the postgres in:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const projectId = project.projectId;
|
||||
|
||||
const projectSelected = await getProject(projectId, auth, this);
|
||||
|
||||
if (projectSelected.postgres.length === 0) {
|
||||
this.error(chalk.yellow("No postgres found in this project."));
|
||||
}
|
||||
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
// @ts-ignore
|
||||
choices: projectSelected.postgres.map((app) => ({
|
||||
name: app.name,
|
||||
value: app.postgresId,
|
||||
})),
|
||||
message: "Select the postgres to deploy:",
|
||||
name: "selectedApp",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const postgresId = appAnswers.selectedApp;
|
||||
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to deploy this postgres?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("postgres deployment cancelled."));
|
||||
}
|
||||
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/postgres.deploy`,
|
||||
{
|
||||
json: {
|
||||
postgresId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error deploying postgres"));
|
||||
}
|
||||
this.log(chalk.green("Postgres deployed successful."));
|
||||
}
|
||||
}
|
||||
89
src/commands/database/postgres/stop.ts
Normal file
89
src/commands/database/postgres/stop.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { Command } from "@oclif/core";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
import axios from "axios";
|
||||
import { getProject, getProjects } from "../../../utils/shared.js";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
|
||||
export default class DatabasePostgresStop extends Command {
|
||||
static description = "Stop an postgres from a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> postgres stop"];
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to stop the postgres in:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const projectId = project.projectId;
|
||||
|
||||
const projectSelected = await getProject(projectId, auth, this);
|
||||
|
||||
if (projectSelected.postgres.length === 0) {
|
||||
this.error(chalk.yellow("No postgres found in this project."));
|
||||
}
|
||||
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
// @ts-ignore
|
||||
choices: projectSelected.postgres.map((app) => ({
|
||||
name: app.name,
|
||||
value: app.postgresId,
|
||||
})),
|
||||
message: "Select the postgres to stop:",
|
||||
name: "selectedApp",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const postgresId = appAnswers.selectedApp;
|
||||
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to stop this postgres?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("postgres stop cancelled."));
|
||||
}
|
||||
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/postgres.stop`,
|
||||
{
|
||||
json: {
|
||||
postgresId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error stopping postgres"));
|
||||
}
|
||||
this.log(chalk.green("Postgres stop successful."));
|
||||
}
|
||||
}
|
||||
119
src/commands/database/redis/create.ts
Normal file
119
src/commands/database/redis/create.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
import { slugify } from "../../../utils/slug.js";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import { getProjects } from "../../../utils/shared.js";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
|
||||
export default class DatabaseRedisCreate extends Command {
|
||||
static description = "Create a new Redis database within a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> redis create"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
const { flags } = await this.parse(DatabaseRedisCreate);
|
||||
|
||||
let { projectId } = flags;
|
||||
|
||||
if (!projectId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to create the Redis database in:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
projectId = project.projectId;
|
||||
|
||||
const dbDetails = await inquirer.prompt([
|
||||
{
|
||||
message: "Enter the name:",
|
||||
name: "name",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Database name is required"),
|
||||
},
|
||||
{
|
||||
message: "Enter the database description (optional):",
|
||||
name: "description",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
message: "Database password (optional):",
|
||||
name: "databasePassword",
|
||||
type: "password",
|
||||
},
|
||||
{
|
||||
default: "redis:7",
|
||||
message: "Docker Image (default: redis:7):",
|
||||
name: "dockerImage",
|
||||
type: "input",
|
||||
},
|
||||
]);
|
||||
|
||||
const appName = await inquirer.prompt([
|
||||
{
|
||||
default: `${slugify(project.name)}-${dbDetails.name}`,
|
||||
message: "Enter the App name:",
|
||||
name: "appName",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "App name is required"),
|
||||
},
|
||||
]);
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/redis.create`,
|
||||
{
|
||||
json: {
|
||||
...dbDetails,
|
||||
appName: appName.appName,
|
||||
projectId: project.projectId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
this.error(chalk.red("Error creating Redis database"));
|
||||
}
|
||||
|
||||
this.log(
|
||||
chalk.green(
|
||||
`Redis database '${dbDetails.name}' created successfully.`,
|
||||
),
|
||||
);
|
||||
} catch (error) {
|
||||
this.error(
|
||||
// @ts-ignore
|
||||
chalk.red(`Failed to create Redis database: ${error.message}`),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
120
src/commands/database/redis/delete.ts
Normal file
120
src/commands/database/redis/delete.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import { getProject, getProjects } from "../../../utils/shared.js";
|
||||
|
||||
export default class DatabaseRedisDelete extends Command {
|
||||
static description = "Delete an redis database from a project.";
|
||||
|
||||
static examples = [
|
||||
"$ <%= config.bin %> redis delete",
|
||||
"$ <%= config.bin %> redis delete -p <projectId>",
|
||||
];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
const { flags } = await this.parse(DatabaseRedisDelete);
|
||||
let { projectId } = flags;
|
||||
|
||||
if (!projectId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
if (projects.length === 0) {
|
||||
this.log(chalk.yellow("No projects found."));
|
||||
return;
|
||||
}
|
||||
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
choices: projects.map((project: any) => ({
|
||||
name: project.name,
|
||||
value: project.projectId,
|
||||
})),
|
||||
message: "Select a project to delete the redis database from:",
|
||||
name: "selectedProject",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
projectId = answers.selectedProject;
|
||||
}
|
||||
|
||||
try {
|
||||
const project = await getProject(projectId, auth, this);
|
||||
|
||||
if (!project.redis || project.redis.length === 0) {
|
||||
this.log(chalk.yellow("No redis databases found in this project."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Permitir al usuario seleccionar una aplicación
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: project.redis.map((db: any) => ({
|
||||
name: db.name,
|
||||
value: db.redisId,
|
||||
})),
|
||||
message: "Select the redis database to delete:",
|
||||
name: "selectedApp",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const redisId = appAnswers.selectedApp;
|
||||
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to delete this redis database?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.log(chalk.yellow("Database deletion cancelled."));
|
||||
return;
|
||||
}
|
||||
|
||||
const deleteResponse = await axios.post(
|
||||
`${auth.url}/api/trpc/redis.remove`,
|
||||
{
|
||||
json: {
|
||||
redisId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!deleteResponse.data.result.data.json) {
|
||||
this.error(chalk.red("Error deleting redis database"));
|
||||
}
|
||||
|
||||
this.log(chalk.green("Redis database deleted successfully."));
|
||||
} catch (error) {
|
||||
this.error(
|
||||
// @ts-expect-error - TS2339: Property 'data' does not exist on type 'AxiosError<any>'.
|
||||
chalk.red(`Failed to delete redis database: ${error.message}`),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
89
src/commands/database/redis/deploy.ts
Normal file
89
src/commands/database/redis/deploy.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { Command } from "@oclif/core";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import chalk from "chalk";
|
||||
import { getProject, getProjects } from "../../../utils/shared.js";
|
||||
import inquirer from "inquirer";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
import axios from "axios";
|
||||
|
||||
export default class DatabaseRedisDeploy extends Command {
|
||||
static description = "Deploy an redis to a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> app deploy"];
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to deploy the redis in:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const projectId = project.projectId;
|
||||
|
||||
const projectSelected = await getProject(projectId, auth, this);
|
||||
|
||||
if (projectSelected.redis.length === 0) {
|
||||
this.error(chalk.yellow("No redis found in this project."));
|
||||
}
|
||||
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
// @ts-ignore
|
||||
choices: projectSelected.redis.map((app) => ({
|
||||
name: app.name,
|
||||
value: app.redisId,
|
||||
})),
|
||||
message: "Select the redis to deploy:",
|
||||
name: "selectedApp",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const redisId = appAnswers.selectedApp;
|
||||
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to deploy this redis?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("redis deployment cancelled."));
|
||||
}
|
||||
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/redis.deploy`,
|
||||
{
|
||||
json: {
|
||||
redisId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error deploying redis"));
|
||||
}
|
||||
this.log(chalk.green("Redis deployed successful."));
|
||||
}
|
||||
}
|
||||
89
src/commands/database/redis/stop.ts
Normal file
89
src/commands/database/redis/stop.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { Command } from "@oclif/core";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
import axios from "axios";
|
||||
import { getProject, getProjects } from "../../../utils/shared.js";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
|
||||
export default class DatabaseRedisStop extends Command {
|
||||
static description = "Stop an redis from a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> redis stop"];
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to stop the redis in:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const projectId = project.projectId;
|
||||
|
||||
const projectSelected = await getProject(projectId, auth, this);
|
||||
|
||||
if (projectSelected.redis.length === 0) {
|
||||
this.error(chalk.yellow("No redis found in this project."));
|
||||
}
|
||||
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
// @ts-ignore
|
||||
choices: projectSelected.redis.map((app) => ({
|
||||
name: app.name,
|
||||
value: app.redisId,
|
||||
})),
|
||||
message: "Select the redis to stop:",
|
||||
name: "selectedApp",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const redisId = appAnswers.selectedApp;
|
||||
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to stop this redis?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("redis stop cancelled."));
|
||||
}
|
||||
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/redis.stop`,
|
||||
{
|
||||
json: {
|
||||
redisId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error stopping redis"));
|
||||
}
|
||||
this.log(chalk.green("Redis stop successful."));
|
||||
}
|
||||
}
|
||||
94
src/commands/project/create.ts
Normal file
94
src/commands/project/create.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer, { type Answers, type QuestionCollection } from "inquirer";
|
||||
|
||||
import { readAuthConfig } from "../../utils/utils.js";
|
||||
|
||||
export default class ProjectCreate extends Command {
|
||||
static override description =
|
||||
"Create a new project with an optional description.";
|
||||
|
||||
static override examples = [
|
||||
"$ <%= config.bin %> <%= command.id %> -n MyProject -d 'This is my project description'",
|
||||
"$ <%= config.bin %> <%= command.id %> -n MyProject",
|
||||
"$ <%= config.bin %> <%= command.id %>",
|
||||
];
|
||||
|
||||
static override flags = {
|
||||
description: Flags.string({
|
||||
char: "d",
|
||||
description: "Description of the project",
|
||||
required: false,
|
||||
}),
|
||||
name: Flags.string({
|
||||
char: "n",
|
||||
description: "Name of the project",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
console.log(chalk.blue.bold("\n Create a New Project \n"));
|
||||
|
||||
const { flags } = await this.parse(ProjectCreate);
|
||||
|
||||
let answers: Answers = {};
|
||||
|
||||
const questions: QuestionCollection[] = [];
|
||||
|
||||
if (!flags.name) {
|
||||
questions.push({
|
||||
message: chalk.green("Enter the project name:"),
|
||||
name: "name",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Project name is required"),
|
||||
});
|
||||
}
|
||||
|
||||
if (!flags.description) {
|
||||
questions.push({
|
||||
default: "",
|
||||
message: chalk.green("Enter the project description (optional):"),
|
||||
name: "description",
|
||||
type: "input",
|
||||
});
|
||||
}
|
||||
|
||||
if (questions.length > 0) {
|
||||
answers = await inquirer.prompt(questions);
|
||||
}
|
||||
|
||||
const name = flags.name || answers.name;
|
||||
const description = flags.description || answers.description;
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/project.createCLI`,
|
||||
{
|
||||
json: {
|
||||
description,
|
||||
name,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
this.error(chalk.red("Error`"));
|
||||
}
|
||||
|
||||
this.log(chalk.green(`Project '${name}' created successfully.`));
|
||||
} catch (error) {
|
||||
// @ts-expect-error hola
|
||||
this.error(chalk.red(`Failed to create project: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
167
src/commands/project/info.ts
Normal file
167
src/commands/project/info.ts
Normal file
@@ -0,0 +1,167 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
|
||||
import { readAuthConfig } from "../../utils/utils.js";
|
||||
import { getProject, getProjects } from "../../utils/shared.js";
|
||||
|
||||
export default class ProjectInfo extends Command {
|
||||
static description =
|
||||
"Get detailed information about a project, including the number of applications and databases.";
|
||||
|
||||
static examples = [
|
||||
"$ <%= config.bin %> project info",
|
||||
"$ <%= config.bin %> project info -p <projectId>",
|
||||
];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
const { flags } = await this.parse(ProjectInfo);
|
||||
|
||||
if (flags.projectId) {
|
||||
await this.showProjectInfo(auth, flags.projectId);
|
||||
} else {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
try {
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
if (projects.length === 0) {
|
||||
this.log(chalk.yellow("No projects found."));
|
||||
return;
|
||||
}
|
||||
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project.projectId,
|
||||
})),
|
||||
message: "Select a project to view details:",
|
||||
name: "selectedProject",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const selectedProjectId = answers.selectedProject;
|
||||
|
||||
await this.showProjectInfo(auth, selectedProjectId);
|
||||
} catch (error) {
|
||||
// @ts-expect-error hola
|
||||
this.error(chalk.red(`Failed to fetch project list: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async showProjectInfo(
|
||||
auth: { token: string; url: string },
|
||||
projectId: string,
|
||||
) {
|
||||
console.log(
|
||||
chalk.blue.bold(`\n Information for Project ID: ${projectId} \n`),
|
||||
);
|
||||
|
||||
try {
|
||||
const projectInfo = await getProject(projectId, auth, this);
|
||||
|
||||
this.log(chalk.green(`Project Name: ${projectInfo.name}`));
|
||||
this.log(
|
||||
chalk.green(
|
||||
`Description: ${projectInfo?.description || "No description"}`,
|
||||
),
|
||||
);
|
||||
this.log(
|
||||
chalk.green(
|
||||
`Number of Applications: ${projectInfo.applications.length}`,
|
||||
),
|
||||
);
|
||||
this.log(
|
||||
chalk.green(
|
||||
`Number of Compose Services: ${projectInfo.compose.length}`,
|
||||
),
|
||||
);
|
||||
this.log(
|
||||
chalk.green(
|
||||
`Number of MariaDB Databases: ${projectInfo.mariadb.length}`,
|
||||
),
|
||||
);
|
||||
this.log(
|
||||
chalk.green(`Number of MongoDB Databases: ${projectInfo.mongo.length}`),
|
||||
);
|
||||
this.log(
|
||||
chalk.green(`Number of MySQL Databases: ${projectInfo.mysql.length}`),
|
||||
);
|
||||
this.log(
|
||||
chalk.green(
|
||||
`Number of PostgreSQL Databases: ${projectInfo.postgres.length}`,
|
||||
),
|
||||
);
|
||||
this.log(
|
||||
chalk.green(`Number of Redis Databases: ${projectInfo.redis.length}`),
|
||||
);
|
||||
|
||||
if (projectInfo.applications.length > 0) {
|
||||
this.log(chalk.blue("\nApplications:"));
|
||||
projectInfo.applications.forEach((app, index: number) => {
|
||||
this.log(` ${index + 1}. ${app.name}`);
|
||||
});
|
||||
}
|
||||
|
||||
if (projectInfo.compose.length > 0) {
|
||||
this.log(chalk.blue("\nCompose Services:"));
|
||||
projectInfo.compose.forEach((service, index: number) => {
|
||||
this.log(` ${index + 1}. ${service.name}`);
|
||||
});
|
||||
}
|
||||
|
||||
if (projectInfo.mariadb.length > 0) {
|
||||
this.log(chalk.blue("\nMariaDB Databases:"));
|
||||
projectInfo.mariadb.forEach((db, index: number) => {
|
||||
this.log(` ${index + 1}. ${db.name}`);
|
||||
});
|
||||
}
|
||||
|
||||
if (projectInfo.mongo.length > 0) {
|
||||
this.log(chalk.blue("\nMongoDB Databases:"));
|
||||
projectInfo.mongo.forEach((db, index: number) => {
|
||||
this.log(` ${index + 1}. ${db.name}`);
|
||||
});
|
||||
}
|
||||
|
||||
if (projectInfo.mysql.length > 0) {
|
||||
this.log(chalk.blue("\nMySQL Databases:"));
|
||||
projectInfo.mysql.forEach((db, index: number) => {
|
||||
this.log(` ${index + 1}. ${db.name}`);
|
||||
});
|
||||
}
|
||||
|
||||
if (projectInfo.postgres.length > 0) {
|
||||
this.log(chalk.blue("\nPostgreSQL Databases:"));
|
||||
projectInfo.postgres.forEach((db, index: number) => {
|
||||
this.log(` ${index + 1}. ${db.name}`);
|
||||
});
|
||||
}
|
||||
|
||||
if (projectInfo.redis.length > 0) {
|
||||
this.log(chalk.blue("\nRedis Databases:"));
|
||||
projectInfo.redis.forEach((db, index: number) => {
|
||||
this.log(` ${index + 1}. ${db.name}`);
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
this.error(
|
||||
// @ts-expect-error
|
||||
chalk.red(`Failed to fetch project information: ${error.message}`),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
49
src/commands/project/list.ts
Normal file
49
src/commands/project/list.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { Command } from "@oclif/core";
|
||||
import chalk from "chalk";
|
||||
import Table from "cli-table3";
|
||||
|
||||
import { readAuthConfig } from "../../utils/utils.js";
|
||||
import { getProjects } from "../../utils/shared.js";
|
||||
|
||||
export default class ProjectList extends Command {
|
||||
static description = "List all projects.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> project list"];
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
try {
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
if (projects.length === 0) {
|
||||
this.log(chalk.yellow("No projects found."));
|
||||
} else {
|
||||
this.log(chalk.green("Projects:"));
|
||||
const table = new Table({
|
||||
colWidths: [10, 30, 50],
|
||||
head: [
|
||||
chalk.cyan("Index"),
|
||||
chalk.cyan("Name"),
|
||||
chalk.cyan("Description"),
|
||||
],
|
||||
});
|
||||
const index = 1;
|
||||
for (const project of projects) {
|
||||
table.push([
|
||||
chalk.white(index + 1),
|
||||
chalk.white(project.name),
|
||||
chalk.gray(project.description || "No description"),
|
||||
]);
|
||||
}
|
||||
|
||||
this.log(table.toString());
|
||||
}
|
||||
} catch (error) {
|
||||
// @ts-expect-error error is not defined
|
||||
this.error(chalk.red(`Failed to list projects: ${error?.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
72
src/commands/verify.ts
Normal file
72
src/commands/verify.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { Command } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const configPath = path.join(__dirname, "..", "..", "config.json");
|
||||
|
||||
export default class Verify extends Command {
|
||||
static description = "Verify if the saved authentication token is valid";
|
||||
|
||||
static examples = ["$ <%= config.bin %> <%= command.id %>"];
|
||||
|
||||
async run() {
|
||||
console.log(chalk.blue.bold("\nVerifying Authentication Token"));
|
||||
|
||||
if (!fs.existsSync(configPath)) {
|
||||
this.error(
|
||||
chalk.red(
|
||||
"No configuration file found. Please authenticate first using `authenticate` command.",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const configFileContent = fs.readFileSync(configPath, "utf8");
|
||||
const config = JSON.parse(configFileContent);
|
||||
const { token, url } = config;
|
||||
|
||||
if (!url || !token) {
|
||||
this.error(
|
||||
chalk.red(
|
||||
"Incomplete authentication details. Please authenticate again using `authenticate` command.",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(`\n${chalk.blue("Validating token...")}`);
|
||||
|
||||
const response = await axios.post(
|
||||
`${url}/api/trpc/auth.verifyToken`,
|
||||
{},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.data.result.data.json) {
|
||||
this.log(chalk.green("Token is valid."));
|
||||
} else {
|
||||
this.error(
|
||||
chalk.red(
|
||||
"Invalid token. Please authenticate again using `authenticate` command.",
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
this.error(
|
||||
chalk.red(
|
||||
// @ts-ignore
|
||||
`Failed to verify token: ${error.message}. Please authenticate again using 'authenticate' command.`,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
1
src/index.ts
Normal file
1
src/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export {run} from '@oclif/core'
|
||||
4
src/utils/http.ts
Normal file
4
src/utils/http.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "Dokploy CLI",
|
||||
};
|
||||
81
src/utils/shared.ts
Normal file
81
src/utils/shared.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import type { Command } from "@oclif/core";
|
||||
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
|
||||
import type { AuthConfig } from "./utils.js";
|
||||
|
||||
export type Project = {
|
||||
adminId: string;
|
||||
name: string;
|
||||
projectId?: string | undefined;
|
||||
description?: string | undefined;
|
||||
};
|
||||
|
||||
export const getProjects = async (
|
||||
auth: AuthConfig,
|
||||
command: Command,
|
||||
): Promise<Project[]> => {
|
||||
try {
|
||||
const response = await axios.get(`${auth.url}/api/trpc/project.all`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
command.error(chalk.red("Error fetching projects"));
|
||||
}
|
||||
|
||||
const projects = response.data.result.data.json;
|
||||
|
||||
if (projects.length === 0) {
|
||||
command.log(chalk.yellow("No projects found."));
|
||||
return [];
|
||||
}
|
||||
|
||||
return projects;
|
||||
} catch {
|
||||
// @ts-expect-error TODO: Fix this
|
||||
command.error(chalk.red(`Failed to fetch project list: ${error.message}`));
|
||||
}
|
||||
};
|
||||
|
||||
export const getProject = async (
|
||||
projectId: string | undefined,
|
||||
auth: AuthConfig,
|
||||
command: Command,
|
||||
) => {
|
||||
try {
|
||||
if (!projectId) {
|
||||
command.error(chalk.red("Project ID is required"));
|
||||
}
|
||||
const response = await axios.get(`${auth.url}/api/trpc/project.one`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
params: {
|
||||
input: JSON.stringify({
|
||||
json: { projectId },
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
command.error(chalk.red("Error fetching project"));
|
||||
}
|
||||
|
||||
const project = response.data.result.data.json;
|
||||
|
||||
if (!project) {
|
||||
command.error(chalk.red("Error fetching project"));
|
||||
}
|
||||
|
||||
return project;
|
||||
} catch {
|
||||
// @ts-expect-error TODO: Fix this
|
||||
command.error(chalk.red(`Failed to fetch project: ${error.message}`));
|
||||
}
|
||||
};
|
||||
14
src/utils/slug.ts
Normal file
14
src/utils/slug.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import slug from "./slugify.js";
|
||||
|
||||
export const slugify = (text: string | undefined) => {
|
||||
if (!text) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const cleanedText = text.trim().replaceAll(/[^\d\sA-Za-z]/g, "");
|
||||
return slug(cleanedText, {
|
||||
lower: true,
|
||||
strict: true,
|
||||
trim: true,
|
||||
});
|
||||
};
|
||||
3
src/utils/slugify.ts
Normal file
3
src/utils/slugify.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import slugify from "slugify";
|
||||
|
||||
export default slugify as unknown as typeof slugify.default;
|
||||
39
src/utils/utils.ts
Normal file
39
src/utils/utils.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import type { Command } from "@oclif/core";
|
||||
|
||||
import chalk from "chalk";
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const configPath = path.join(__dirname, "..", "..", "config.json");
|
||||
|
||||
export type AuthConfig = {
|
||||
token: string;
|
||||
url: string;
|
||||
};
|
||||
|
||||
export const readAuthConfig = async (command: Command): Promise<AuthConfig> => {
|
||||
if (!fs.existsSync(configPath)) {
|
||||
command.error(
|
||||
chalk.red(
|
||||
"No configuration file found. Please authenticate first using the 'authenticate' command.",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const configFileContent = fs.readFileSync(configPath, "utf8");
|
||||
const config = JSON.parse(configFileContent);
|
||||
const { token, url } = config;
|
||||
|
||||
if (!url || !token) {
|
||||
command.error(
|
||||
chalk.red(
|
||||
"Incomplete authentication details. Please authenticate again using the 'authenticate' command.",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return { token, url };
|
||||
};
|
||||
14
test/commands/app/create.test.ts
Normal file
14
test/commands/app/create.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('app:create', () => {
|
||||
it('runs app:create cmd', async () => {
|
||||
const {stdout} = await runCommand('app:create')
|
||||
expect(stdout).to.contain('hello world')
|
||||
})
|
||||
|
||||
it('runs app:create --name oclif', async () => {
|
||||
const {stdout} = await runCommand('app:create --name oclif')
|
||||
expect(stdout).to.contain('hello oclif')
|
||||
})
|
||||
})
|
||||
14
test/commands/app/delete.test.ts
Normal file
14
test/commands/app/delete.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('app:delete', () => {
|
||||
it('runs app:delete cmd', async () => {
|
||||
const {stdout} = await runCommand('app:delete')
|
||||
expect(stdout).to.contain('hello world')
|
||||
})
|
||||
|
||||
it('runs app:delete --name oclif', async () => {
|
||||
const {stdout} = await runCommand('app:delete --name oclif')
|
||||
expect(stdout).to.contain('hello oclif')
|
||||
})
|
||||
})
|
||||
14
test/commands/authenticate.test.ts
Normal file
14
test/commands/authenticate.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('authenticate', () => {
|
||||
it('runs authenticate cmd', async () => {
|
||||
const {stdout} = await runCommand('authenticate')
|
||||
expect(stdout).to.contain('hello world')
|
||||
})
|
||||
|
||||
it('runs authenticate --name oclif', async () => {
|
||||
const {stdout} = await runCommand('authenticate --name oclif')
|
||||
expect(stdout).to.contain('hello oclif')
|
||||
})
|
||||
})
|
||||
14
test/commands/check-server.test.ts
Normal file
14
test/commands/check-server.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('check-server', () => {
|
||||
it('runs check-server cmd', async () => {
|
||||
const {stdout} = await runCommand('check-server')
|
||||
expect(stdout).to.contain('hello world')
|
||||
})
|
||||
|
||||
it('runs check-server --name oclif', async () => {
|
||||
const {stdout} = await runCommand('check-server --name oclif')
|
||||
expect(stdout).to.contain('hello oclif')
|
||||
})
|
||||
})
|
||||
14
test/commands/database/create.test.ts
Normal file
14
test/commands/database/create.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('database:create', () => {
|
||||
it('runs database:create cmd', async () => {
|
||||
const {stdout} = await runCommand('database:create')
|
||||
expect(stdout).to.contain('hello world')
|
||||
})
|
||||
|
||||
it('runs database:create --name oclif', async () => {
|
||||
const {stdout} = await runCommand('database:create --name oclif')
|
||||
expect(stdout).to.contain('hello oclif')
|
||||
})
|
||||
})
|
||||
14
test/commands/database/mariadb/create.test.ts
Normal file
14
test/commands/database/mariadb/create.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('database:mariadb:create', () => {
|
||||
it('runs database:mariadb:create cmd', async () => {
|
||||
const {stdout} = await runCommand('database:mariadb:create')
|
||||
expect(stdout).to.contain('hello world')
|
||||
})
|
||||
|
||||
it('runs database:mariadb:create --name oclif', async () => {
|
||||
const {stdout} = await runCommand('database:mariadb:create --name oclif')
|
||||
expect(stdout).to.contain('hello oclif')
|
||||
})
|
||||
})
|
||||
14
test/commands/database/mariadb/delete.test.ts
Normal file
14
test/commands/database/mariadb/delete.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('database:mariadb:delete', () => {
|
||||
it('runs database:mariadb:delete cmd', async () => {
|
||||
const {stdout} = await runCommand('database:mariadb:delete')
|
||||
expect(stdout).to.contain('hello world')
|
||||
})
|
||||
|
||||
it('runs database:mariadb:delete --name oclif', async () => {
|
||||
const {stdout} = await runCommand('database:mariadb:delete --name oclif')
|
||||
expect(stdout).to.contain('hello oclif')
|
||||
})
|
||||
})
|
||||
14
test/commands/database/mongo/create.test.ts
Normal file
14
test/commands/database/mongo/create.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('database:mongo:create', () => {
|
||||
it('runs database:mongo:create cmd', async () => {
|
||||
const {stdout} = await runCommand('database:mongo:create')
|
||||
expect(stdout).to.contain('hello world')
|
||||
})
|
||||
|
||||
it('runs database:mongo:create --name oclif', async () => {
|
||||
const {stdout} = await runCommand('database:mongo:create --name oclif')
|
||||
expect(stdout).to.contain('hello oclif')
|
||||
})
|
||||
})
|
||||
14
test/commands/database/mongo/delete.test.ts
Normal file
14
test/commands/database/mongo/delete.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('database:mongo:delete', () => {
|
||||
it('runs database:mongo:delete cmd', async () => {
|
||||
const {stdout} = await runCommand('database:mongo:delete')
|
||||
expect(stdout).to.contain('hello world')
|
||||
})
|
||||
|
||||
it('runs database:mongo:delete --name oclif', async () => {
|
||||
const {stdout} = await runCommand('database:mongo:delete --name oclif')
|
||||
expect(stdout).to.contain('hello oclif')
|
||||
})
|
||||
})
|
||||
14
test/commands/database/mysql/create.test.ts
Normal file
14
test/commands/database/mysql/create.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('database:mysql:create', () => {
|
||||
it('runs database:mysql:create cmd', async () => {
|
||||
const {stdout} = await runCommand('database:mysql:create')
|
||||
expect(stdout).to.contain('hello world')
|
||||
})
|
||||
|
||||
it('runs database:mysql:create --name oclif', async () => {
|
||||
const {stdout} = await runCommand('database:mysql:create --name oclif')
|
||||
expect(stdout).to.contain('hello oclif')
|
||||
})
|
||||
})
|
||||
14
test/commands/database/mysql/delete.test.ts
Normal file
14
test/commands/database/mysql/delete.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('database:mysql:delete', () => {
|
||||
it('runs database:mysql:delete cmd', async () => {
|
||||
const {stdout} = await runCommand('database:mysql:delete')
|
||||
expect(stdout).to.contain('hello world')
|
||||
})
|
||||
|
||||
it('runs database:mysql:delete --name oclif', async () => {
|
||||
const {stdout} = await runCommand('database:mysql:delete --name oclif')
|
||||
expect(stdout).to.contain('hello oclif')
|
||||
})
|
||||
})
|
||||
14
test/commands/database/postgres/create.test.ts
Normal file
14
test/commands/database/postgres/create.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('database:postgres:create', () => {
|
||||
it('runs database:postgres:create cmd', async () => {
|
||||
const {stdout} = await runCommand('database:postgres:create')
|
||||
expect(stdout).to.contain('hello world')
|
||||
})
|
||||
|
||||
it('runs database:postgres:create --name oclif', async () => {
|
||||
const {stdout} = await runCommand('database:postgres:create --name oclif')
|
||||
expect(stdout).to.contain('hello oclif')
|
||||
})
|
||||
})
|
||||
14
test/commands/database/postgres/delete.test.ts
Normal file
14
test/commands/database/postgres/delete.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('database:postgres:delete', () => {
|
||||
it('runs database:postgres:delete cmd', async () => {
|
||||
const {stdout} = await runCommand('database:postgres:delete')
|
||||
expect(stdout).to.contain('hello world')
|
||||
})
|
||||
|
||||
it('runs database:postgres:delete --name oclif', async () => {
|
||||
const {stdout} = await runCommand('database:postgres:delete --name oclif')
|
||||
expect(stdout).to.contain('hello oclif')
|
||||
})
|
||||
})
|
||||
14
test/commands/database/redis/create.test.ts
Normal file
14
test/commands/database/redis/create.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('database:redis:create', () => {
|
||||
it('runs database:redis:create cmd', async () => {
|
||||
const {stdout} = await runCommand('database:redis:create')
|
||||
expect(stdout).to.contain('hello world')
|
||||
})
|
||||
|
||||
it('runs database:redis:create --name oclif', async () => {
|
||||
const {stdout} = await runCommand('database:redis:create --name oclif')
|
||||
expect(stdout).to.contain('hello oclif')
|
||||
})
|
||||
})
|
||||
14
test/commands/database/redis/delete.test.ts
Normal file
14
test/commands/database/redis/delete.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('database:redis:delete', () => {
|
||||
it('runs database:redis:delete cmd', async () => {
|
||||
const {stdout} = await runCommand('database:redis:delete')
|
||||
expect(stdout).to.contain('hello world')
|
||||
})
|
||||
|
||||
it('runs database:redis:delete --name oclif', async () => {
|
||||
const {stdout} = await runCommand('database:redis:delete --name oclif')
|
||||
expect(stdout).to.contain('hello oclif')
|
||||
})
|
||||
})
|
||||
9
test/commands/hello/index.test.ts
Normal file
9
test/commands/hello/index.test.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('hello', () => {
|
||||
it('runs hello', async () => {
|
||||
const {stdout} = await runCommand('hello friend --from oclif')
|
||||
expect(stdout).to.contain('hello friend from oclif!')
|
||||
})
|
||||
})
|
||||
9
test/commands/hello/world.test.ts
Normal file
9
test/commands/hello/world.test.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('hello world', () => {
|
||||
it('runs hello world cmd', async () => {
|
||||
const {stdout} = await runCommand('hello world')
|
||||
expect(stdout).to.contain('hello world!')
|
||||
})
|
||||
})
|
||||
14
test/commands/project/create.test.ts
Normal file
14
test/commands/project/create.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('project:create', () => {
|
||||
it('runs project:create cmd', async () => {
|
||||
const {stdout} = await runCommand('project:create')
|
||||
expect(stdout).to.contain('hello world')
|
||||
})
|
||||
|
||||
it('runs project:create --name oclif', async () => {
|
||||
const {stdout} = await runCommand('project:create --name oclif')
|
||||
expect(stdout).to.contain('hello oclif')
|
||||
})
|
||||
})
|
||||
14
test/commands/project/info.test.ts
Normal file
14
test/commands/project/info.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('project:info', () => {
|
||||
it('runs project:info cmd', async () => {
|
||||
const {stdout} = await runCommand('project:info')
|
||||
expect(stdout).to.contain('hello world')
|
||||
})
|
||||
|
||||
it('runs project:info --name oclif', async () => {
|
||||
const {stdout} = await runCommand('project:info --name oclif')
|
||||
expect(stdout).to.contain('hello oclif')
|
||||
})
|
||||
})
|
||||
14
test/commands/project/list.test.ts
Normal file
14
test/commands/project/list.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('project:list', () => {
|
||||
it('runs project:list cmd', async () => {
|
||||
const {stdout} = await runCommand('project:list')
|
||||
expect(stdout).to.contain('hello world')
|
||||
})
|
||||
|
||||
it('runs project:list --name oclif', async () => {
|
||||
const {stdout} = await runCommand('project:list --name oclif')
|
||||
expect(stdout).to.contain('hello oclif')
|
||||
})
|
||||
})
|
||||
14
test/commands/verify.test.ts
Normal file
14
test/commands/verify.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {runCommand} from '@oclif/test'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe('verify', () => {
|
||||
it('runs verify cmd', async () => {
|
||||
const {stdout} = await runCommand('verify')
|
||||
expect(stdout).to.contain('hello world')
|
||||
})
|
||||
|
||||
it('runs verify --name oclif', async () => {
|
||||
const {stdout} = await runCommand('verify --name oclif')
|
||||
expect(stdout).to.contain('hello oclif')
|
||||
})
|
||||
})
|
||||
9
test/tsconfig.json
Normal file
9
test/tsconfig.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../tsconfig",
|
||||
"compilerOptions": {
|
||||
"noEmit": true
|
||||
},
|
||||
"references": [
|
||||
{"path": ".."}
|
||||
]
|
||||
}
|
||||
15
tsconfig.json
Normal file
15
tsconfig.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"module": "Node16",
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"strict": true,
|
||||
"target": "es2022",
|
||||
"moduleResolution": "node16",
|
||||
},
|
||||
"include": ["./src/**/*"],
|
||||
"ts-node": {
|
||||
"esm": true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user