@akash-chowdhury-24/deployhub 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +176 -0
  3. package/install.ps1 +55 -0
  4. package/install.sh +99 -0
  5. package/package.json +86 -0
  6. package/src/adapters/dotnet.adapter.js +41 -0
  7. package/src/adapters/go.adapter.js +40 -0
  8. package/src/adapters/index.js +48 -0
  9. package/src/adapters/java.adapter.js +46 -0
  10. package/src/adapters/node.adapter.js +77 -0
  11. package/src/adapters/php.adapter.js +43 -0
  12. package/src/adapters/python.adapter.js +54 -0
  13. package/src/adapters/rails.adapter.js +66 -0
  14. package/src/artifact/engine.js +473 -0
  15. package/src/cli/index.js +45 -0
  16. package/src/commands/artifact.js +88 -0
  17. package/src/commands/build.js +44 -0
  18. package/src/commands/clean.js +50 -0
  19. package/src/commands/deploy.js +82 -0
  20. package/src/commands/doctor.js +630 -0
  21. package/src/commands/init.js +795 -0
  22. package/src/commands/logs.js +33 -0
  23. package/src/commands/rollback.js +50 -0
  24. package/src/commands/storage.js +116 -0
  25. package/src/commands/update.js +63 -0
  26. package/src/commands/verify.js +55 -0
  27. package/src/core/config.js +168 -0
  28. package/src/core/pipeline.js +77 -0
  29. package/src/core/stages.js +210 -0
  30. package/src/deployment/index.js +156 -0
  31. package/src/deployment/providers/azure-vm.js +7 -0
  32. package/src/deployment/providers/docker.js +30 -0
  33. package/src/deployment/providers/ec2.js +7 -0
  34. package/src/deployment/providers/gcp-vm.js +7 -0
  35. package/src/deployment/providers/kubernetes.js +30 -0
  36. package/src/deployment/providers/platforms/_shared.js +167 -0
  37. package/src/deployment/providers/platforms/aws-amplify.js +164 -0
  38. package/src/deployment/providers/platforms/azure-static-web-apps.js +68 -0
  39. package/src/deployment/providers/platforms/cloudflare-pages.js +103 -0
  40. package/src/deployment/providers/platforms/firebase-app-hosting.js +95 -0
  41. package/src/deployment/providers/platforms/firebase-hosting.js +99 -0
  42. package/src/deployment/providers/platforms/index.js +44 -0
  43. package/src/deployment/providers/platforms/netlify.js +102 -0
  44. package/src/deployment/providers/platforms/vercel.js +92 -0
  45. package/src/deployment/providers/ssh.js +365 -0
  46. package/src/detectors/angular.js +23 -0
  47. package/src/detectors/backend.detector.js +304 -0
  48. package/src/detectors/dotnet.js +18 -0
  49. package/src/detectors/frontend.detector.js +219 -0
  50. package/src/detectors/go.js +20 -0
  51. package/src/detectors/index.js +78 -0
  52. package/src/detectors/java.js +24 -0
  53. package/src/detectors/nextjs.js +23 -0
  54. package/src/detectors/node.js +28 -0
  55. package/src/detectors/php.js +17 -0
  56. package/src/detectors/python.js +22 -0
  57. package/src/detectors/react.js +29 -0
  58. package/src/detectors/vue.js +23 -0
  59. package/src/logger/index.js +44 -0
  60. package/src/notifications/email.js +53 -0
  61. package/src/notifications/index.js +34 -0
  62. package/src/notifications/slack.js +18 -0
  63. package/src/notifications/webhook.js +21 -0
  64. package/src/rollback/engine.js +102 -0
  65. package/src/storage/index.js +109 -0
  66. package/src/storage/providers/aws.js +96 -0
  67. package/src/storage/providers/azure.js +45 -0
  68. package/src/storage/providers/dropbox.js +49 -0
  69. package/src/storage/providers/ftp.js +69 -0
  70. package/src/storage/providers/gcp.js +45 -0
  71. package/src/storage/providers/gdrive.js +80 -0
  72. package/src/storage/providers/local.js +61 -0
  73. package/src/utils/author.js +141 -0
  74. package/src/utils/checksums.js +53 -0
  75. package/src/utils/firebase-config-generator.js +35 -0
  76. package/src/utils/github-actions.js +389 -0
  77. package/src/utils/init-platform.js +229 -0
  78. package/src/utils/nginx.js +34 -0
  79. package/src/utils/platform-env.js +132 -0
  80. package/src/utils/version.js +31 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Akash Chowdhury
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,176 @@
1
+ # DeployHub
2
+
3
+ Zero-configuration deployment and artifact manager for Node.js projects. When you push to GitHub, DeployHub automatically detects your project type, builds it, creates a versioned artifact, uploads to cloud storage, and optionally deploys to your server.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g @akash-chowdhury-24/deployhub
9
+ ```
10
+
11
+ Or use locally in your project:
12
+
13
+ ```bash
14
+ npm install deployhub
15
+ npx @akash-chowdhury-24/deployhub init
16
+ ```
17
+
18
+ ## Quick Start
19
+
20
+ ### 1. Initialize
21
+
22
+ ```bash
23
+ deployhub init
24
+ ```
25
+
26
+ This interactive wizard will:
27
+
28
+ - Detect your framework (React, Vue, Next.js, Node, Python, etc.)
29
+ - Configure build commands and output directory
30
+ - Set up storage providers (AWS, Google Drive, Azure, GCP, Dropbox, Local)
31
+ - Optionally configure deployment targets (SSH, Docker, EC2, Kubernetes, etc.)
32
+ - Generate `deployhub.config.json`
33
+ - Generate `.github/workflows/deployhub.yml`
34
+ - Generate `.env.example`
35
+
36
+ ### 2. Configure credentials
37
+
38
+ ```bash
39
+ cp .env.example .env
40
+ # Edit .env with your credentials
41
+
42
+ deployhub storage add aws
43
+ deployhub storage add gdrive
44
+ ```
45
+
46
+ ### 3. Run pre-flight checks
47
+
48
+ ```bash
49
+ deployhub doctor
50
+ ```
51
+
52
+ ### 4. Deploy
53
+
54
+ ```bash
55
+ deployhub build
56
+ ```
57
+
58
+ Or push to `main` — GitHub Actions runs `deployhub build` automatically.
59
+
60
+ ## Commands
61
+
62
+ | Command | Description |
63
+ |---------|-------------|
64
+ | `deployhub init` | Interactive project setup |
65
+ | `deployhub build` | Full pipeline: detect → install → test → build → artifact → storage → deploy |
66
+ | `deployhub artifact create` | Create artifact from current build |
67
+ | `deployhub artifact list` | List all artifacts |
68
+ | `deployhub artifact restore <version>` | Download and extract an artifact |
69
+ | `deployhub storage add <provider>` | Add storage provider credentials |
70
+ | `deployhub storage list` | List storage providers and connection status |
71
+ | `deployhub deploy` | Deploy latest artifact |
72
+ | `deployhub rollback [version]` | Rollback to a previous version |
73
+ | `deployhub logs` | Show logs from last deployment |
74
+ | `deployhub doctor` | Pre-flight checks |
75
+ | `deployhub verify` | Health check on configured endpoint |
76
+ | `deployhub clean` | Remove old local artifacts |
77
+ | `deployhub update` | Check for CLI updates |
78
+
79
+ ## GitHub Secrets
80
+
81
+ Add these secrets in your repository (Settings → Secrets and variables → Actions). Only add secrets for providers you selected during `init`:
82
+
83
+ | Secret | Provider |
84
+ |--------|----------|
85
+ | `AWS_ACCESS_KEY_ID` | AWS S3 |
86
+ | `AWS_SECRET_ACCESS_KEY` | AWS S3 |
87
+ | `AWS_BUCKET` | AWS S3 |
88
+ | `AWS_REGION` | AWS S3 |
89
+ | `GDRIVE_CLIENT_ID` | Google Drive |
90
+ | `GDRIVE_CLIENT_SECRET` | Google Drive |
91
+ | `GDRIVE_REFRESH_TOKEN` | Google Drive |
92
+ | `GDRIVE_FOLDER_ID` | Google Drive |
93
+ | `AZURE_CONNECTION_STRING` | Azure Blob |
94
+ | `AZURE_CONTAINER` | Azure Blob |
95
+ | `GCP_PROJECT_ID` | GCP Storage |
96
+ | `GCP_KEY_FILE` | GCP Storage |
97
+ | `GCP_BUCKET` | GCP Storage |
98
+ | `DROPBOX_ACCESS_TOKEN` | Dropbox |
99
+ | `SSH_HOST` | SSH deployment |
100
+ | `SSH_USER` | SSH deployment |
101
+ | `SSH_KEY` | SSH deployment |
102
+
103
+ ## `deployhub doctor` Output
104
+
105
+ The doctor command runs independent checks and always completes without crashing:
106
+
107
+ ```
108
+ Checking Git... ✓ Git installed, repo detected, remote set
109
+ Checking Docker... ✓ Docker running
110
+ Checking Build command... ✓ "npm run build" found in package.json
111
+ Checking AWS... ✓ Credentials valid, bucket accessible
112
+ Checking Google Drive... ✓ Connected
113
+ Checking SSH target... ✓ Can reach host
114
+ Checking Health endpoint... ✓ URL reachable (HTTP 200)
115
+ Checking Secrets... ✓ All required env vars present
116
+ Checking GitHub Actions... ✓ Workflow file exists at .github/workflows/deployhub.yml
117
+ Checking Storage write... ✓ Test upload succeeded
118
+
119
+ ✓ Ready to deploy (10/10 checks passed)
120
+ ```
121
+
122
+ If checks fail:
123
+
124
+ ```
125
+ Checking AWS... ✗ Missing: AWS_SECRET_ACCESS_KEY
126
+ Checking Health endpoint... ✗ No URL configured
127
+
128
+ 8/10 — fix the 2 issues above before deploying
129
+ ```
130
+
131
+ ## Artifact Structure
132
+
133
+ Each build creates:
134
+
135
+ ```
136
+ artifact/
137
+ {projectName}/
138
+ {YYYY-MM-DD}/
139
+ v{semver}/
140
+ artifact.zip
141
+ metadata.json
142
+ logs.txt
143
+ checksums.txt
144
+ deployment.json
145
+ release-notes.md
146
+ README.md
147
+ ```
148
+
149
+ ## Configuration
150
+
151
+ `deployhub.config.json` is generated by `init`. Credentials are **never** stored in this file — only in `.env` or GitHub Secrets.
152
+
153
+ ## Pipeline Stages
154
+
155
+ 1. **detect** — auto-detect project type
156
+ 2. **install** — install dependencies
157
+ 3. **test** — run test suite (skippable)
158
+ 4. **build** — run build command
159
+ 5. **docker** — build Docker image (skippable)
160
+ 6. **artifact** — create artifact.zip + metadata
161
+ 7. **storage** — upload to all configured providers (parallel)
162
+ 8. **deploy** — deploy to configured targets
163
+ 9. **verify** — health check after deployment
164
+ 10. **notify** — send Slack/email/webhook notifications
165
+
166
+ ## Author
167
+
168
+ **Akash Chowdhury**
169
+ 📧 akashbumbac24@gmail.com
170
+ 💼 [linkedin.com/in/akash-chowdhury-12141a222](https://www.linkedin.com/in/akash-chowdhury-12141a222/)
171
+
172
+ Built with ❤ — if DeployHub saves you time, feel free to connect on LinkedIn.
173
+
174
+ ## License
175
+
176
+ MIT
package/install.ps1 ADDED
@@ -0,0 +1,55 @@
1
+ # DeployHub install script for Windows
2
+ # Author: Akash Chowdhury — canonical source: src/utils/author.js
3
+ # Repository: https://github.com/Akash-Chowdhury-24/DeployHub
4
+
5
+ $ErrorActionPreference = "Stop"
6
+
7
+ $GitHubRepo = "Akash-Chowdhury-24/DeployHub"
8
+ $BinaryName = "deployhub.exe"
9
+
10
+ function Get-LatestVersion {
11
+ $release = Invoke-RestMethod -Uri "https://api.github.com/repos/$GitHubRepo/releases/latest"
12
+ return $release.tag_name
13
+ }
14
+
15
+ function Get-InstallDir {
16
+ $localBin = Join-Path $env:LOCALAPPDATA "Programs\DeployHub"
17
+ if (-not (Test-Path $localBin)) {
18
+ New-Item -ItemType Directory -Path $localBin -Force | Out-Null
19
+ }
20
+ return $localBin
21
+ }
22
+
23
+ function Add-ToPath {
24
+ param([string]$Dir)
25
+ $userPath = [Environment]::GetEnvironmentVariable("Path", "User")
26
+ if ($userPath -notlike "*$Dir*") {
27
+ [Environment]::SetEnvironmentVariable("Path", "$userPath;$Dir", "User")
28
+ $env:Path = "$env:Path;$Dir"
29
+ Write-Host "Added $Dir to user PATH"
30
+ }
31
+ }
32
+
33
+ try {
34
+ $version = Get-LatestVersion
35
+ $assetName = "deployhub-win.exe"
36
+ $url = "https://github.com/$GitHubRepo/releases/download/$version/$assetName"
37
+ $installDir = Get-InstallDir
38
+ $dest = Join-Path $installDir $BinaryName
39
+
40
+ Write-Host "Downloading DeployHub $version for Windows..."
41
+ Invoke-WebRequest -Uri $url -OutFile $dest -UseBasicParsing
42
+
43
+ if (-not (Test-Path $dest) -or (Get-Item $dest).Length -eq 0) {
44
+ throw "Binary download failed"
45
+ }
46
+
47
+ Add-ToPath $installDir
48
+ Write-Host "DeployHub $version installed to $dest"
49
+ & $dest --version
50
+ }
51
+ catch {
52
+ Write-Host "Binary install failed ($($_.Exception.Message)). Falling back to npm..." -ForegroundColor Yellow
53
+ npm install -g deployhub@latest
54
+ Write-Host "DeployHub installed via npm."
55
+ }
package/install.sh ADDED
@@ -0,0 +1,99 @@
1
+ #!/bin/sh
2
+ # DeployHub install script
3
+ # Author: Akash Chowdhury — canonical source: src/utils/author.js
4
+ # Repository: https://github.com/Akash-Chowdhury-24/DeployHub
5
+
6
+ set -e
7
+
8
+ GITHUB_REPO="Akash-Chowdhury-24/DeployHub"
9
+ INSTALL_DIR="/usr/local/bin"
10
+ BINARY_NAME="deployhub"
11
+
12
+ detect_platform() {
13
+ OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
14
+ ARCH="$(uname -m)"
15
+
16
+ case "$OS" in
17
+ linux)
18
+ case "$ARCH" in
19
+ x86_64|amd64) PLATFORM="linux" ;;
20
+ *) echo "Unsupported Linux architecture: $ARCH" >&2; exit 1 ;;
21
+ esac
22
+ ;;
23
+ darwin)
24
+ case "$ARCH" in
25
+ x86_64) PLATFORM="macos" ;;
26
+ arm64|aarch64) PLATFORM="macos-arm64" ;;
27
+ *) echo "Unsupported macOS architecture: $ARCH" >&2; exit 1 ;;
28
+ esac
29
+ ;;
30
+ *)
31
+ echo "Unsupported OS: $OS. Use install.ps1 on Windows." >&2
32
+ exit 1
33
+ ;;
34
+ esac
35
+ }
36
+
37
+ fetch_latest_version() {
38
+ if command -v curl >/dev/null 2>&1; then
39
+ VERSION=$(curl -fsSL "https://api.github.com/repos/${GITHUB_REPO}/releases/latest" \
40
+ | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' \
41
+ | head -n 1)
42
+ elif command -v wget >/dev/null 2>&1; then
43
+ VERSION=$(wget -qO- "https://api.github.com/repos/${GITHUB_REPO}/releases/latest" \
44
+ | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' \
45
+ | head -n 1)
46
+ else
47
+ echo "curl or wget is required to download DeployHub." >&2
48
+ exit 1
49
+ fi
50
+
51
+ if [ -z "$VERSION" ]; then
52
+ echo "Could not determine latest release version. Falling back to npm install." >&2
53
+ npm install -g deployhub@latest
54
+ echo "DeployHub installed via npm."
55
+ exit 0
56
+ fi
57
+ }
58
+
59
+ download_binary() {
60
+ ASSET="deployhub-${PLATFORM}"
61
+ URL="https://github.com/${GITHUB_REPO}/releases/download/${VERSION}/${ASSET}"
62
+ TMP="$(mktemp)"
63
+
64
+ echo "Downloading DeployHub ${VERSION} (${PLATFORM})..."
65
+ if command -v curl >/dev/null 2>&1; then
66
+ curl -fsSL "$URL" -o "$TMP"
67
+ else
68
+ wget -qO "$TMP" "$URL"
69
+ fi
70
+
71
+ if [ ! -s "$TMP" ]; then
72
+ echo "Binary download failed. Falling back to npm install." >&2
73
+ rm -f "$TMP"
74
+ npm install -g deployhub@latest
75
+ echo "DeployHub installed via npm."
76
+ exit 0
77
+ fi
78
+
79
+ if [ "$(id -u)" -eq 0 ]; then
80
+ install -m 755 "$TMP" "${INSTALL_DIR}/${BINARY_NAME}"
81
+ else
82
+ if command -v sudo >/dev/null 2>&1; then
83
+ sudo install -m 755 "$TMP" "${INSTALL_DIR}/${BINARY_NAME}"
84
+ else
85
+ mkdir -p "${HOME}/.local/bin"
86
+ install -m 755 "$TMP" "${HOME}/.local/bin/${BINARY_NAME}"
87
+ echo "Installed to ${HOME}/.local/bin/${BINARY_NAME} — ensure it is on your PATH"
88
+ fi
89
+ fi
90
+
91
+ rm -f "$TMP"
92
+ }
93
+
94
+ detect_platform
95
+ fetch_latest_version
96
+ download_binary
97
+
98
+ echo "DeployHub ${VERSION} installed successfully."
99
+ deployhub --version 2>/dev/null || true
package/package.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "@akash-chowdhury-24/deployhub",
3
+ "version": "1.0.0",
4
+ "description": "Zero-configuration deployment and artifact manager",
5
+ "type": "module",
6
+ "main": "./src/cli/index.js",
7
+ "license": "MIT",
8
+ "homepage": "https://github.com/Akash-Chowdhury-24/DeployHub#readme",
9
+ "bugs": {
10
+ "url": "https://github.com/Akash-Chowdhury-24/DeployHub/issues"
11
+ },
12
+ "keywords": [
13
+ "deploy",
14
+ "deployment",
15
+ "ci-cd",
16
+ "artifacts",
17
+ "cli",
18
+ "devops",
19
+ "automation"
20
+ ],
21
+ "files": [
22
+ "src",
23
+ "install.sh",
24
+ "install.ps1",
25
+ "README.md",
26
+ "LICENSE"
27
+ ],
28
+ "bin": {
29
+ "deployhub": "src/cli/index.js"
30
+ },
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/Akash-Chowdhury-24/DeployHub.git"
34
+ },
35
+ "scripts": {
36
+ "start": "node src/cli/index.js",
37
+ "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
38
+ "prepublishOnly": "npm test",
39
+ "build:bundle": "node scripts/build-bundle.mjs",
40
+ "build:bin": "npm run build:bundle && pkg dist/deployhub.cjs --targets node20-linux-x64,node20-macos-x64,node20-macos-arm64,node20-win-x64 --output dist/deployhub --compress GZip"
41
+ },
42
+ "pkg": {
43
+ "scripts": "dist/deployhub.cjs",
44
+ "assets": [
45
+ "node_modules/ssh2/**/*"
46
+ ],
47
+ "outputPath": "dist"
48
+ },
49
+ "dependencies": {
50
+ "commander": "^12.0.0",
51
+ "inquirer": "^9.0.0",
52
+ "execa": "^8.0.0",
53
+ "ora": "^8.0.0",
54
+ "chalk": "^5.0.0",
55
+ "archiver": "^6.0.0",
56
+ "fs-extra": "^11.0.0",
57
+ "js-yaml": "^4.0.0",
58
+ "axios": "^1.0.0",
59
+ "zod": "^3.23.0",
60
+ "@aws-sdk/client-s3": "^3.0.0",
61
+ "@aws-sdk/lib-storage": "^3.0.0",
62
+ "@azure/storage-blob": "^12.0.0",
63
+ "@google-cloud/storage": "^7.0.0",
64
+ "dropbox": "^10.0.0",
65
+ "googleapis": "^140.0.0",
66
+ "ssh2": "^1.0.0",
67
+ "node-ssh": "^13.0.0",
68
+ "semver": "^7.0.0",
69
+ "dotenv": "^16.0.0",
70
+ "basic-ftp": "^5.0.0",
71
+ "nodemailer": "^6.9.0"
72
+ },
73
+ "devDependencies": {
74
+ "jest": "^29.0.0",
75
+ "pkg": "^5.8.1",
76
+ "esbuild": "^0.21.0"
77
+ },
78
+ "engines": {
79
+ "node": ">=18.0.0"
80
+ },
81
+ "author": {
82
+ "name": "Akash Chowdhury",
83
+ "email": "akashbumbac24@gmail.com",
84
+ "url": "https://www.linkedin.com/in/akash-chowdhury-12141a222/"
85
+ }
86
+ }
@@ -0,0 +1,41 @@
1
+ import { execa } from 'execa';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+ import { createLogger } from '../logger/index.js';
5
+
6
+ function create(config, cwd) {
7
+ const log = createLogger('dotnet');
8
+
9
+ return {
10
+ detect() {
11
+ const files = fs.readdirSync(cwd);
12
+ return files.some((f) => f.endsWith('.csproj'));
13
+ },
14
+
15
+ async install() {
16
+ log.info('Restoring .NET packages...');
17
+ await execa('dotnet', ['restore'], { cwd, stdio: 'inherit' });
18
+ },
19
+
20
+ async test() {
21
+ await execa('dotnet', ['test'], { cwd, stdio: 'inherit' });
22
+ },
23
+
24
+ async build() {
25
+ log.info(`Running: ${config.buildCommand}`);
26
+ const [cmd, ...args] = config.buildCommand.split(' ');
27
+ await execa(cmd, args, { cwd, stdio: 'inherit', shell: true });
28
+ },
29
+
30
+ async docker() {
31
+ if (await fs.pathExists(path.join(cwd, 'Dockerfile'))) {
32
+ await execa('docker', ['build', '-t', `${config.project}:latest`, '.'], {
33
+ cwd,
34
+ stdio: 'inherit',
35
+ });
36
+ }
37
+ },
38
+ };
39
+ }
40
+
41
+ export default { create };
@@ -0,0 +1,40 @@
1
+ import { execa } from 'execa';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+ import { createLogger } from '../logger/index.js';
5
+
6
+ function create(config, cwd) {
7
+ const log = createLogger('go');
8
+
9
+ return {
10
+ detect() {
11
+ return fs.existsSync(path.join(cwd, 'go.mod'));
12
+ },
13
+
14
+ async install() {
15
+ log.info('Downloading Go modules...');
16
+ await execa('go', ['mod', 'download'], { cwd, stdio: 'inherit' });
17
+ },
18
+
19
+ async test() {
20
+ await execa('go', ['test', './...'], { cwd, stdio: 'inherit' });
21
+ },
22
+
23
+ async build() {
24
+ log.info(`Running: ${config.buildCommand}`);
25
+ const [cmd, ...args] = config.buildCommand.split(' ');
26
+ await execa(cmd, args, { cwd, stdio: 'inherit', shell: true });
27
+ },
28
+
29
+ async docker() {
30
+ if (await fs.pathExists(path.join(cwd, 'Dockerfile'))) {
31
+ await execa('docker', ['build', '-t', `${config.project}:latest`, '.'], {
32
+ cwd,
33
+ stdio: 'inherit',
34
+ });
35
+ }
36
+ },
37
+ };
38
+ }
39
+
40
+ export default { create };
@@ -0,0 +1,48 @@
1
+ import nodeAdapter from './node.adapter.js';
2
+ import pythonAdapter from './python.adapter.js';
3
+ import phpAdapter from './php.adapter.js';
4
+ import javaAdapter from './java.adapter.js';
5
+ import goAdapter from './go.adapter.js';
6
+ import dotnetAdapter from './dotnet.adapter.js';
7
+ import railsAdapter from './rails.adapter.js';
8
+
9
+ /** @type {Record<string, import('./node.adapter.js').default>} */
10
+ const ADAPTERS = {
11
+ react: nodeAdapter,
12
+ vue: nodeAdapter,
13
+ angular: nodeAdapter,
14
+ nextjs: nodeAdapter,
15
+ svelte: nodeAdapter,
16
+ astro: nodeAdapter,
17
+ vanilla: nodeAdapter,
18
+ node: nodeAdapter,
19
+ express: nodeAdapter,
20
+ nestjs: nodeAdapter,
21
+ fastify: nodeAdapter,
22
+ koa: nodeAdapter,
23
+ python: pythonAdapter,
24
+ fastapi: pythonAdapter,
25
+ django: pythonAdapter,
26
+ flask: pythonAdapter,
27
+ php: phpAdapter,
28
+ laravel: phpAdapter,
29
+ symfony: phpAdapter,
30
+ java: javaAdapter,
31
+ spring: javaAdapter,
32
+ go: goAdapter,
33
+ dotnet: dotnetAdapter,
34
+ rails: railsAdapter,
35
+ };
36
+
37
+ /**
38
+ * @param {string} framework
39
+ * @param {import('../core/config.js').DeployHubConfig} config
40
+ * @param {string} [cwd]
41
+ * @returns {import('./node.adapter.js').default}
42
+ */
43
+ export function getAdapter(framework, config, cwd = process.cwd()) {
44
+ const AdapterClass = ADAPTERS[framework] || nodeAdapter;
45
+ return AdapterClass.create(config, cwd);
46
+ }
47
+
48
+ export default { getAdapter };
@@ -0,0 +1,46 @@
1
+ import { execa } from 'execa';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+ import { createLogger } from '../logger/index.js';
5
+
6
+ function create(config, cwd) {
7
+ const log = createLogger('java');
8
+
9
+ return {
10
+ detect() {
11
+ return (
12
+ fs.existsSync(path.join(cwd, 'pom.xml')) ||
13
+ fs.existsSync(path.join(cwd, 'build.gradle'))
14
+ );
15
+ },
16
+
17
+ async install() {
18
+ log.info('Resolving Java dependencies...');
19
+ },
20
+
21
+ async test() {
22
+ if (fs.existsSync(path.join(cwd, 'pom.xml'))) {
23
+ await execa('mvn', ['test'], { cwd, stdio: 'inherit' });
24
+ } else {
25
+ await execa('./gradlew', ['test'], { cwd, stdio: 'inherit', shell: true });
26
+ }
27
+ },
28
+
29
+ async build() {
30
+ log.info(`Running: ${config.buildCommand}`);
31
+ const [cmd, ...args] = config.buildCommand.split(' ');
32
+ await execa(cmd, args, { cwd, stdio: 'inherit', shell: true });
33
+ },
34
+
35
+ async docker() {
36
+ if (await fs.pathExists(path.join(cwd, 'Dockerfile'))) {
37
+ await execa('docker', ['build', '-t', `${config.project}:latest`, '.'], {
38
+ cwd,
39
+ stdio: 'inherit',
40
+ });
41
+ }
42
+ },
43
+ };
44
+ }
45
+
46
+ export default { create };
@@ -0,0 +1,77 @@
1
+ import { execa } from 'execa';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+ import { createLogger } from '../logger/index.js';
5
+
6
+ /**
7
+ * @typedef {Object} LanguageAdapter
8
+ * @property {function(): boolean} detect
9
+ * @property {function(): Promise<void>} install
10
+ * @property {function(): Promise<void>} test
11
+ * @property {function(): Promise<void>} build
12
+ * @property {function(): Promise<void>} docker
13
+ */
14
+
15
+ /**
16
+ * @param {import('../core/config.js').DeployHubConfig} config
17
+ * @param {string} cwd
18
+ */
19
+ function create(config, cwd) {
20
+ const log = createLogger('node');
21
+
22
+ return {
23
+ detect() {
24
+ return fs.existsSync(path.join(cwd, 'package.json'));
25
+ },
26
+
27
+ async install() {
28
+ log.info('Installing dependencies...');
29
+ if (fs.existsSync(path.join(cwd, 'package-lock.json'))) {
30
+ await execa('npm', ['ci'], { cwd, stdio: 'inherit' });
31
+ } else {
32
+ await execa('npm', ['install'], { cwd, stdio: 'inherit' });
33
+ }
34
+ },
35
+
36
+ async test() {
37
+ const pkg = await fs.readJson(path.join(cwd, 'package.json'));
38
+ if (!pkg.scripts?.test) {
39
+ log.warn('No test script found, skipping');
40
+ return;
41
+ }
42
+ log.info('Running tests...');
43
+ await execa('npm', ['test'], { cwd, stdio: 'inherit' });
44
+ },
45
+
46
+ async build() {
47
+ const buildCommand =
48
+ config.buildCommand ||
49
+ (config.projectType === 'both' ? config.frontend?.buildCommand : null) ||
50
+ (config.projectType === 'backend' ? config.backend?.buildCommand : null);
51
+
52
+ if (!buildCommand) {
53
+ log.info('No build command configured, skipping');
54
+ return;
55
+ }
56
+
57
+ log.info(`Running build: ${buildCommand}`);
58
+ const [cmd, ...args] = buildCommand.split(' ');
59
+ await execa(cmd, args, { cwd, stdio: 'inherit', shell: true });
60
+ },
61
+
62
+ async docker() {
63
+ if (!(await fs.pathExists(path.join(cwd, 'Dockerfile')))) {
64
+ log.warn('No Dockerfile found, skipping docker build');
65
+ return;
66
+ }
67
+ log.info('Building Docker image...');
68
+ const imageName = `${config.project}:latest`;
69
+ await execa('docker', ['build', '-t', imageName, '.'], {
70
+ cwd,
71
+ stdio: 'inherit',
72
+ });
73
+ },
74
+ };
75
+ }
76
+
77
+ export default { create };