@akash-chowdhury-24/deployhub 2.0.30 → 2.0.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/package.json +1 -1
- package/src/artifact/engine.js +111 -83
- package/src/commands/doctor.js +230 -36
- package/src/core/config.js +10 -0
- package/src/core/environments.js +21 -6
- package/src/deployment/deployment-env.js +91 -25
- package/src/deployment/init-helpers.js +3 -1
- package/src/deployment/init-prompts.js +100 -6
- package/src/deployment/providers/docker.js +108 -5
- package/src/deployment/providers/kubernetes.js +3 -0
- package/src/deployment/providers/ssh.js +44 -92
- package/src/deployment/ssh-connection.js +149 -0
- package/src/detectors/frontend.detector.js +1 -1
- package/src/utils/credential-inventory.js +10 -0
- package/src/utils/docker-image-deploy.js +4 -0
- package/src/utils/docker-image.js +3 -3
- package/src/utils/docker-remote-mode.js +33 -0
- package/src/utils/docker-remote.js +214 -0
- package/src/utils/dockerfile.js +28 -9
- package/src/utils/github-actions.js +28 -6
- package/src/utils/php-fpm.js +3 -1
package/src/utils/dockerfile.js
CHANGED
|
@@ -76,6 +76,8 @@ function defaultBuildOutput(framework, projectType) {
|
|
|
76
76
|
* @param {string} projectType
|
|
77
77
|
*/
|
|
78
78
|
function defaultPort(framework, projectType) {
|
|
79
|
+
// Next.js is a Node server, not nginx static — even when projectType is frontend.
|
|
80
|
+
if (framework === 'nextjs') return 3000;
|
|
79
81
|
if (
|
|
80
82
|
projectType === 'frontend' ||
|
|
81
83
|
['react', 'vue', 'angular', 'svelte', 'astro', 'vanilla'].includes(framework)
|
|
@@ -244,9 +246,21 @@ export function generateDockerfile(config) {
|
|
|
244
246
|
* @param {{ buildCommand: string|null, buildOutput: string, port: number }} settings
|
|
245
247
|
*/
|
|
246
248
|
function generateFrontendStaticDockerfile(settings) {
|
|
247
|
-
const buildCmd = settings.buildCommand
|
|
249
|
+
const buildCmd = settings.buildCommand;
|
|
248
250
|
const output = settings.buildOutput || 'dist';
|
|
249
251
|
|
|
252
|
+
// Vanilla / prebuilt static trees have no compile step. Do not invent
|
|
253
|
+
// `npm run build` — that fails when package.json has no build script.
|
|
254
|
+
if (!buildCmd || String(buildCmd).trim() === '') {
|
|
255
|
+
const src = output === '.' ? '.' : output;
|
|
256
|
+
return `${GENERATED_HEADER}
|
|
257
|
+
FROM nginx:alpine
|
|
258
|
+
COPY ${src} /usr/share/nginx/html
|
|
259
|
+
EXPOSE 80
|
|
260
|
+
CMD ["nginx", "-g", "daemon off;"]
|
|
261
|
+
`;
|
|
262
|
+
}
|
|
263
|
+
|
|
250
264
|
return `${GENERATED_HEADER}
|
|
251
265
|
FROM node:20-alpine AS build
|
|
252
266
|
WORKDIR /app
|
|
@@ -281,6 +295,7 @@ FROM node:20-alpine AS build
|
|
|
281
295
|
WORKDIR /app
|
|
282
296
|
COPY --from=deps /app/node_modules ./node_modules
|
|
283
297
|
COPY . .
|
|
298
|
+
RUN mkdir -p public
|
|
284
299
|
RUN ${buildCmd}
|
|
285
300
|
|
|
286
301
|
FROM node:20-alpine AS runner
|
|
@@ -453,9 +468,8 @@ function generatePythonDockerfile(settings) {
|
|
|
453
468
|
return `${GENERATED_HEADER}
|
|
454
469
|
FROM python:3.11-slim
|
|
455
470
|
WORKDIR /app
|
|
456
|
-
COPY requirements.txt* ./
|
|
457
|
-
RUN if [ -f requirements.txt ]; then pip install --no-cache-dir -r requirements.txt; fi
|
|
458
471
|
COPY . .
|
|
472
|
+
RUN if [ -f requirements.txt ]; then pip install --no-cache-dir -r requirements.txt; fi
|
|
459
473
|
EXPOSE ${port}
|
|
460
474
|
CMD ${JSON.stringify(startParts)}
|
|
461
475
|
`;
|
|
@@ -485,7 +499,7 @@ function generateLaravelDockerfile(settings) {
|
|
|
485
499
|
return `${GENERATED_HEADER}
|
|
486
500
|
FROM composer:2 AS vendor
|
|
487
501
|
WORKDIR /app
|
|
488
|
-
COPY composer.json
|
|
502
|
+
COPY composer.json ./
|
|
489
503
|
RUN composer install --no-dev --optimize-autoloader --no-interaction --ignore-platform-reqs --no-scripts
|
|
490
504
|
|
|
491
505
|
FROM php:${phpVersion}-cli-alpine
|
|
@@ -519,7 +533,7 @@ function generateSymfonyDockerfile(settings) {
|
|
|
519
533
|
return `${GENERATED_HEADER}
|
|
520
534
|
FROM composer:2 AS vendor
|
|
521
535
|
WORKDIR /app
|
|
522
|
-
COPY composer.json
|
|
536
|
+
COPY composer.json ./
|
|
523
537
|
RUN composer install --no-dev --optimize-autoloader --no-interaction --ignore-platform-reqs --no-scripts
|
|
524
538
|
|
|
525
539
|
FROM php:${phpVersion}-cli-alpine
|
|
@@ -600,7 +614,7 @@ function generateGoDockerfile(settings) {
|
|
|
600
614
|
return `${GENERATED_HEADER}
|
|
601
615
|
FROM golang:1.22-alpine AS build
|
|
602
616
|
WORKDIR /app
|
|
603
|
-
COPY go.mod
|
|
617
|
+
COPY go.mod ./
|
|
604
618
|
RUN go mod download
|
|
605
619
|
COPY . .
|
|
606
620
|
RUN mkdir -p /app/bin && ${buildCmd}
|
|
@@ -622,6 +636,11 @@ function generateDotnetDockerfile(settings) {
|
|
|
622
636
|
const buildCmd = settings.buildCommand || 'dotnet publish -c Release -o publish';
|
|
623
637
|
const port = settings.port || 5000;
|
|
624
638
|
const output = settings.buildOutput || 'publish';
|
|
639
|
+
const startParts = [
|
|
640
|
+
'sh',
|
|
641
|
+
'-c',
|
|
642
|
+
'dll=$(ls *.dll 2>/dev/null | head -n1); exec dotnet "$dll"',
|
|
643
|
+
];
|
|
625
644
|
|
|
626
645
|
return `${GENERATED_HEADER}
|
|
627
646
|
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
|
@@ -636,7 +655,7 @@ WORKDIR /app
|
|
|
636
655
|
COPY --from=build /src/${output} .
|
|
637
656
|
EXPOSE ${port}
|
|
638
657
|
ENV ASPNETCORE_URLS=http://+:${port}
|
|
639
|
-
CMD
|
|
658
|
+
CMD ${JSON.stringify(startParts)}
|
|
640
659
|
`;
|
|
641
660
|
}
|
|
642
661
|
|
|
@@ -654,7 +673,7 @@ function generateRailsDockerfile(settings) {
|
|
|
654
673
|
FROM ruby:3.2-slim AS build
|
|
655
674
|
WORKDIR /app
|
|
656
675
|
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev && rm -rf /var/lib/apt/lists/*
|
|
657
|
-
COPY Gemfile
|
|
676
|
+
COPY Gemfile ./
|
|
658
677
|
RUN bundle config set --local without 'development test' && bundle install
|
|
659
678
|
COPY . .
|
|
660
679
|
RUN bundle exec rake assets:precompile || true
|
|
@@ -683,7 +702,7 @@ function generateRubyDockerfile(settings) {
|
|
|
683
702
|
FROM ruby:3.2-slim
|
|
684
703
|
WORKDIR /app
|
|
685
704
|
RUN apt-get update -qq && apt-get install -y build-essential && rm -rf /var/lib/apt/lists/*
|
|
686
|
-
COPY Gemfile
|
|
705
|
+
COPY Gemfile ./
|
|
687
706
|
RUN bundle config set --local without 'development test' && bundle install
|
|
688
707
|
COPY . .
|
|
689
708
|
EXPOSE ${port}
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
getEnvTrigger,
|
|
22
22
|
getEnabledEnvironmentNames,
|
|
23
23
|
isEnvEnabled,
|
|
24
|
+
getEnvSettings,
|
|
24
25
|
} from '../core/environments.js';
|
|
25
26
|
import { resolvePhpVersion } from './php-version.js';
|
|
26
27
|
|
|
@@ -540,7 +541,11 @@ export function buildWorkflowEnvEntries(
|
|
|
540
541
|
|
|
541
542
|
const method = getEnvMethod(env);
|
|
542
543
|
if (!method) continue;
|
|
543
|
-
const unprefixedKeys = getDeploymentWorkflowSecretKeys(
|
|
544
|
+
const unprefixedKeys = getDeploymentWorkflowSecretKeys(
|
|
545
|
+
method,
|
|
546
|
+
config,
|
|
547
|
+
getEnvSettings(env)
|
|
548
|
+
);
|
|
544
549
|
for (const key of unprefixedKeys) {
|
|
545
550
|
const secretName = envUsesPrefixedSecrets(envName, cfg)
|
|
546
551
|
? prefixSecretKey(envName, key)
|
|
@@ -863,12 +868,10 @@ ${rollbackRun}
|
|
|
863
868
|
* @param {import('../core/config.js').DeployHubConfig} [config]
|
|
864
869
|
* @returns {string}
|
|
865
870
|
*/
|
|
866
|
-
function
|
|
867
|
-
if (!config) return 'npm install';
|
|
868
|
-
|
|
871
|
+
function getBackendInstallDepsCommand(config) {
|
|
869
872
|
const framework =
|
|
870
|
-
config
|
|
871
|
-
const language = config
|
|
873
|
+
config?.backend?.framework || config?.framework || 'express';
|
|
874
|
+
const language = config?.backend?.language || config?.language;
|
|
872
875
|
|
|
873
876
|
if (language === 'python' || ['fastapi', 'django', 'flask', 'python'].includes(framework)) {
|
|
874
877
|
return 'pip install -r requirements.txt';
|
|
@@ -891,6 +894,25 @@ function getInstallDepsCommand(config) {
|
|
|
891
894
|
return 'npm install';
|
|
892
895
|
}
|
|
893
896
|
|
|
897
|
+
/**
|
|
898
|
+
* @param {import('../core/config.js').DeployHubConfig} [config]
|
|
899
|
+
* @returns {string}
|
|
900
|
+
*/
|
|
901
|
+
function getInstallDepsCommand(config) {
|
|
902
|
+
if (!config) return 'npm install';
|
|
903
|
+
|
|
904
|
+
const projectType = config.projectType || 'frontend';
|
|
905
|
+
if (projectType === 'frontend') return 'npm install';
|
|
906
|
+
|
|
907
|
+
const backendCmd = getBackendInstallDepsCommand(config);
|
|
908
|
+
// Fullstack: frontend is always Node in this CLI. Backend install alone
|
|
909
|
+
// (composer/pip/…) leaves the SPA without node_modules and `npm run build` dies.
|
|
910
|
+
if (projectType === 'both' && backendCmd !== 'npm install') {
|
|
911
|
+
return `npm install && ${backendCmd}`;
|
|
912
|
+
}
|
|
913
|
+
return backendCmd;
|
|
914
|
+
}
|
|
915
|
+
|
|
894
916
|
/**
|
|
895
917
|
* Write deployhub.yml and deployhub-rollback.yml from the same secret/env helpers.
|
|
896
918
|
*
|
package/src/utils/php-fpm.js
CHANGED
|
@@ -20,8 +20,10 @@ export function preferredPhpFpmUnitName(phpVersion) {
|
|
|
20
20
|
* @returns {string}
|
|
21
21
|
*/
|
|
22
22
|
export function buildPhpFpmUnitListCommand() {
|
|
23
|
+
// sudo -n: unprivileged SSH users cannot talk to systemd's private bus
|
|
24
|
+
// (Failed to connect to bus) inside containers and some hardened hosts.
|
|
23
25
|
return (
|
|
24
|
-
`systemctl list-unit-files --type=service --no-legend ` +
|
|
26
|
+
`sudo -n systemctl list-unit-files --type=service --no-legend ` +
|
|
25
27
|
`'php*-fpm.service' 'php-fpm.service' 2>/dev/null ` +
|
|
26
28
|
`| awk '{print $1}' | sed 's/\\.service$//' | sort -u`
|
|
27
29
|
);
|