@faable/faable 1.7.0 → 1.8.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.
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { join, dirname } from 'path';
|
|
3
|
+
import { log } from '../../../log.js';
|
|
4
|
+
import { cmd } from '../../../lib/cmd.js';
|
|
5
|
+
|
|
6
|
+
// Installing can be slow on cold CI runners (no npm cache).
|
|
7
|
+
const INSTALL_TIMEOUT = 15 * 60 * 1000; // 15 minute timeout
|
|
8
|
+
const defaultRun = (command, cwd) => cmd(command, { cwd, timeout: INSTALL_TIMEOUT, enableOutput: true });
|
|
9
|
+
const defaultHasTool = async (name) => {
|
|
10
|
+
try {
|
|
11
|
+
await cmd(`command -v ${name}`);
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Dependencies may live in the workdir or be hoisted to a parent directory
|
|
20
|
+
* (monorepos). Walk upwards checking each level, stopping at the repo root
|
|
21
|
+
* (first directory containing `.git`) or the filesystem root.
|
|
22
|
+
*/
|
|
23
|
+
const has_node_modules = (workdir, exists) => {
|
|
24
|
+
let dir = workdir;
|
|
25
|
+
while (true) {
|
|
26
|
+
if (exists(join(dir, "node_modules")))
|
|
27
|
+
return true;
|
|
28
|
+
if (exists(join(dir, ".git")))
|
|
29
|
+
return false;
|
|
30
|
+
const parent = dirname(dir);
|
|
31
|
+
if (parent === dir)
|
|
32
|
+
return false;
|
|
33
|
+
dir = parent;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Install dependencies when `node_modules` is missing, so `faable deploy`
|
|
38
|
+
* works without a prior `npm ci` step — the generated GitHub Actions workflow
|
|
39
|
+
* is language-agnostic and no longer installs anything itself. The build
|
|
40
|
+
* (`npm run build`) and the image (`COPY . .` ships node_modules) both need
|
|
41
|
+
* dependencies present on the host.
|
|
42
|
+
*
|
|
43
|
+
* The install command honors the project's lockfile; yarn/pnpm fall back to
|
|
44
|
+
* `npm install` when the tool is missing, which may resolve slightly
|
|
45
|
+
* different versions.
|
|
46
|
+
*/
|
|
47
|
+
const ensure_dependencies = async (workdir, deps = {}) => {
|
|
48
|
+
const { run = defaultRun, hasTool = defaultHasTool, exists = existsSync } = deps;
|
|
49
|
+
if (has_node_modules(workdir, exists))
|
|
50
|
+
return;
|
|
51
|
+
const has = (file) => exists(join(workdir, file));
|
|
52
|
+
let install = "npm install --no-audit --no-fund";
|
|
53
|
+
if (has("package-lock.json") || has("npm-shrinkwrap.json")) {
|
|
54
|
+
install = "npm ci";
|
|
55
|
+
}
|
|
56
|
+
else if (has("yarn.lock")) {
|
|
57
|
+
if (await hasTool("yarn")) {
|
|
58
|
+
install = "yarn install --frozen-lockfile";
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
log.warn("yarn.lock found but yarn is not installed — using npm install");
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else if (has("pnpm-lock.yaml")) {
|
|
65
|
+
if (await hasTool("pnpm")) {
|
|
66
|
+
install = "pnpm install --frozen-lockfile";
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
log.warn("pnpm-lock.yaml found but pnpm is not installed — using npm install");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
log.info(`📦 node_modules missing — installing dependencies [${install}]`);
|
|
73
|
+
await run(install, workdir);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export { ensure_dependencies };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { build_docker } from './build_docker.js';
|
|
2
2
|
import { analyze_package } from './analyze_package.js';
|
|
3
3
|
import { build_project } from './build_project.js';
|
|
4
|
+
import { ensure_dependencies } from './ensure_dependencies.js';
|
|
4
5
|
import { inject_serve } from './inject_serve.js';
|
|
5
6
|
import * as R from 'ramda';
|
|
6
7
|
import { log } from '../../../log.js';
|
|
@@ -18,8 +19,11 @@ const build_node = async (app, options) => {
|
|
|
18
19
|
// Environment variables
|
|
19
20
|
const env = R.fromPairs(env_vars.map((e) => [e.name, e.value]));
|
|
20
21
|
log.info(`Building with env variables ${Object.keys(env).join(",")}`);
|
|
22
|
+
// The workflow no longer runs `npm ci` — install here when needed, before
|
|
23
|
+
// the build and before `COPY . .` packages node_modules into the image.
|
|
24
|
+
await ensure_dependencies(workdir);
|
|
21
25
|
// Do build
|
|
22
|
-
await build_project({ build_script, env });
|
|
26
|
+
await build_project({ build_script, env, cwd: workdir });
|
|
23
27
|
// Frameworks without a bundled static server (CRA/Vue/Angular) need `serve`
|
|
24
28
|
// installed into node_modules before packaging, so it ships in the image.
|
|
25
29
|
if (needs_serve) {
|