@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) {
@@ -22,7 +22,6 @@ jobs:
22
22
  steps:
23
23
  - uses: actions/checkout@v6
24
24
  - uses: actions/setup-node@v6
25
- - run: npm ci
26
25
  - run: npx @faable/faable@latest deploy
27
26
  `;
28
27
  const DEPLOY_DOCS_URL = "https://faable.com/docs/deploy/github-actions";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faable/faable",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "main": "dist/index.js",
5
5
  "license": "MIT",
6
6
  "author": "Marc Pomar <marc@faable.com>",