arcadible 0.1.38 → 0.1.40

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/bin/arc-init.js CHANGED
@@ -32,7 +32,6 @@ const spinner = require("../src/util/spinner");
32
32
  const abort = output.abort;
33
33
  const ArcError = error.ArcError;
34
34
  const findRc = rc.findRc;
35
- const join = path.join;
36
35
  const pathExists = fs.pathExists;
37
36
  const print = output.print;
38
37
  const resolve = path.resolve;
@@ -95,7 +94,8 @@ const start = function (argv) {
95
94
  // [function]
96
95
 
97
96
  const patch = function (cwd, project) {
98
- return pathExists(join(resolve(process.cwd(), cwd), project));
97
+ // project may be absolute, as action/init/tool.js resolves it.
98
+ return pathExists(resolve(process.cwd(), cwd, project));
99
99
  };
100
100
 
101
101
  // [function]
package/package.json CHANGED
@@ -75,5 +75,5 @@
75
75
  "scripts": {
76
76
  "test": "node --test \"test/**/*.test.js\""
77
77
  },
78
- "version": "0.1.38"
78
+ "version": "0.1.40"
79
79
  }
@@ -25,9 +25,11 @@ const resolvePath = path.resolve;
25
25
 
26
26
  // [function]
27
27
 
28
+ // a build's output has no limit: exec's default maxBuffer, 1 MB, would kill a
29
+ // verbose build that otherwise succeeds.
28
30
  const execBuild = function (command, { cwdPath }) {
29
31
  return new Promise((resolve, reject) => {
30
- exec(command, { cwd: cwdPath }, (err, stdout, stderr) => {
32
+ exec(command, { cwd: cwdPath, maxBuffer: Infinity }, (err, stdout, stderr) => {
31
33
  if (err) {
32
34
  const { code, signal } = err;
33
35
  reject(
@@ -2,12 +2,13 @@
2
2
 
3
3
  // [import]
4
4
 
5
+ const links = require("../../util/links");
5
6
  const project = require("../../parser/project");
6
7
 
7
8
  // [function]
8
9
 
9
10
  const openUrl = function (id) {
10
- return id ? { page: `/play/${id}` } : null;
11
+ return id ? { page: links.storePage(id) } : null;
11
12
  };
12
13
 
13
14
  // [function]
@@ -95,6 +95,23 @@ const ensureRepo = function (root) {
95
95
 
96
96
  // [function]
97
97
 
98
+ // fails when the project isn't the repository's top level: the release
99
+ // workflow builds from the root, so a project in a directory below it would
100
+ // fail on GitHub, or release the root's game.
101
+ const ensureRoot = function (root) {
102
+ return git(root, ["rev-parse", "--show-prefix"]).then((stdout) => {
103
+ const prefix = stdout.trim();
104
+ if (prefix) {
105
+ throw new ArcError(
106
+ cfgcode.PROJECT_NOT_REPO_ROOT,
107
+ phrase.projectNotRepoRoot(prefix),
108
+ );
109
+ }
110
+ });
111
+ };
112
+
113
+ // [function]
114
+
98
115
  // fails when HEAD has no release workflow, which Arcadible checks for when the
99
116
  // tag arrives (workflow_missing).
100
117
  const ensureWorkflow = function (root) {
@@ -178,6 +195,7 @@ module.exports = {
178
195
  ensureClean,
179
196
  ensureRemote,
180
197
  ensureRepo,
198
+ ensureRoot,
181
199
  ensureTagFree,
182
200
  ensureWorkflow,
183
201
  failWith,
@@ -19,6 +19,7 @@ const ensureClean = git.ensureClean;
19
19
  const ensureLockFile = pm.ensureLockFile;
20
20
  const ensureRemote = git.ensureRemote;
21
21
  const ensureRepo = git.ensureRepo;
22
+ const ensureRoot = git.ensureRoot;
22
23
  const ensureTagFree = git.ensureTagFree;
23
24
  const ensureWorkflow = git.ensureWorkflow;
24
25
  const originRepo = git.originRepo;
@@ -71,10 +72,12 @@ const ensurePublishable = function ({ handle, id, version }, handler) {
71
72
  // [function]
72
73
 
73
74
  // the project's checks: a lockfile when there's a package.json, and a clean
74
- // repository with the release workflow and a reachable origin.
75
+ // repository, whose root is the project, with the release workflow and a
76
+ // reachable origin.
75
77
  const ensureProject = function (root) {
76
78
  return ensureLockFile(root)
77
79
  .then(() => ensureRepo(root))
80
+ .then(() => ensureRoot(root))
78
81
  .then(() => ensureClean(root))
79
82
  .then(() => ensureWorkflow(root))
80
83
  .then(() => ensureRemote(root));
@@ -24,6 +24,7 @@ const CLI = {
24
24
  LOCKFILE_MISSING: "lockfile_missing",
25
25
  LOGIN_EXPIRED: "login_expired",
26
26
  LOGIN_FAILED: "login_failed",
27
+ MANIFEST_MISSING: "manifest_missing",
27
28
  NETWORK_ERROR: "network_error",
28
29
  NOT_LOGGED_IN: "not_logged_in",
29
30
  PACKAGE_FILE_TOO_LARGE: "package_file_too_large",
@@ -33,6 +34,7 @@ const CLI = {
33
34
  PACKAGE_UNCOMPRESSED_TOO_LARGE: "package_uncompressed_too_large",
34
35
  PARSE_FAILED: "parse_failed",
35
36
  PATH_NOT_FOUND: "path_not_found",
37
+ PROJECT_NOT_REPO_ROOT: "project_not_repo_root",
36
38
  SESSION_EXPIRED: "session_expired",
37
39
  TEMPLATE_MISSING: "template_missing",
38
40
  TEMPLATE_UNAVAILABLE: "template_unavailable",
@@ -43,8 +45,8 @@ const CLI = {
43
45
  };
44
46
  // a release's reasons, from the pipeline (the API's
45
47
  // db/type/release_reason.sql). The CLI shares them, so a name means the same
46
- // thing wherever it appears: GAME_UNAVAILABLE, INTERNAL, and VERSION_EXISTS
47
- // are the CLI's too.
48
+ // thing wherever it appears: GAME_UNAVAILABLE, INTERNAL, REPO_NOT_CONNECTED,
49
+ // and VERSION_EXISTS are the CLI's too.
48
50
  const RELEASE = {
49
51
  APP_NOT_INSTALLED: "app_not_installed",
50
52
  EXPIRED: "expired",
package/src/config/url.js CHANGED
@@ -13,7 +13,6 @@ const HANDLE = cfgproduct.handle;
13
13
 
14
14
  module.exports = {
15
15
  ERRORS: `${cfguri.HOST_HTTP_DEVELOPER}/references/errors`,
16
- GETTING_STARTED: `${cfguri.HOST_HTTP_DEVELOPER}/getting-started`,
17
16
  LINK: `${cfguri.HOST_HTTP_ACCOUNT}/link`,
18
17
  MANIFEST: `${cfguri.HOST_HTTP_DEVELOPER}/references/${HANDLE}-manifest`,
19
18
  };
@@ -2,11 +2,16 @@
2
2
 
3
3
  // [import]
4
4
 
5
+ const path = require("node:path");
6
+
7
+ // [import]
8
+
5
9
  const fs = require("fs-extra");
6
10
 
7
11
  // [import]
8
12
 
9
13
  const cfgcode = require("../config/code");
14
+ const cfgproduct = require("../config/product");
10
15
  const cfgworkflow = require("../config/workflow");
11
16
  const env = require("./env");
12
17
  const error = require("../util/error");
@@ -19,7 +24,16 @@ const readme = require("./readme");
19
24
  // [use]
20
25
 
21
26
  const ArcError = error.ArcError;
27
+ const dirname = path.dirname;
28
+ const isAbsolute = path.isAbsolute;
29
+ const join = path.join;
22
30
  const pathExists = fs.pathExists;
31
+ const relative = path.relative;
32
+ const sep = path.sep;
33
+
34
+ // [declare]
35
+
36
+ const MANIFEST = `${cfgproduct.handle}.toml`;
23
37
 
24
38
  // [function]
25
39
 
@@ -44,6 +58,51 @@ const configWorkflow = function (envWorkflow, manifestWorkflow) {
44
58
 
45
59
  // [function]
46
60
 
61
+ // a directory as the developer would type it: relative to where arc runs
62
+ // when it's there, below it, or above it (`..`), or else its full path.
63
+ const shown = function (dir) {
64
+ const rel = relative(process.cwd(), dir);
65
+ const above = rel.split(sep).every((part) => part === "..");
66
+ return isAbsolute(rel) || (rel.startsWith("..") && !above) ? dir : rel || ".";
67
+ };
68
+
69
+ // [function]
70
+
71
+ // the nearest directory above `dir` with a manifest, or null. It's only
72
+ // named in the error's hint: arc never reads a project it wasn't given.
73
+ const nearestAbove = function (dir) {
74
+ const parent = dirname(dir);
75
+ if (parent === dir) {
76
+ return Promise.resolve(null);
77
+ }
78
+ return pathExists(join(parent, MANIFEST)).then((exists) => {
79
+ if (exists) {
80
+ return parent;
81
+ }
82
+ return nearestAbove(parent);
83
+ });
84
+ };
85
+
86
+ // [function]
87
+
88
+ // fails when `root` has no manifest. A game's id is only ever in it, so a
89
+ // project without one can't be deployed, and the likeliest cause is running
90
+ // arc from inside a project: the hint names the project above, if any.
91
+ const ensureManifest = function (root) {
92
+ return pathExists(join(root, MANIFEST))
93
+ .then((exists) => (exists ? false : nearestAbove(root)))
94
+ .then((found) => {
95
+ if (found !== false) {
96
+ throw new ArcError(
97
+ cfgcode.MANIFEST_MISSING,
98
+ phrase.noManifest(MANIFEST, shown(root), found && shown(found)),
99
+ );
100
+ }
101
+ });
102
+ };
103
+
104
+ // [function]
105
+
47
106
  // the other sources, once arcadible.toml is read: the README's title is read
48
107
  // word for word when arcadible.toml sets the short title.
49
108
  const parseSources = function (root, manifestData) {
@@ -66,16 +125,17 @@ const parseSources = function (root, manifestData) {
66
125
 
67
126
  // [function]
68
127
 
69
- // the project at `root`, which must exist: a mistyped -C would otherwise
70
- // read as an empty project.
128
+ // the project at `root`, which must exist, with its manifest: a mistyped
129
+ // -C would otherwise read as an empty project.
71
130
  const main = function (root) {
72
131
  return pathExists(root)
73
132
  .then((exists) => {
74
133
  if (!exists) {
75
134
  throw new ArcError(cfgcode.PATH_NOT_FOUND, phrase.unableToFind(root));
76
135
  }
77
- return manifest(root);
136
+ return ensureManifest(root);
78
137
  })
138
+ .then(() => manifest(root))
79
139
  .then((manifestData) => parseSources(root, manifestData));
80
140
  };
81
141
 
package/src/phrase.js CHANGED
@@ -214,6 +214,26 @@ const gitRemoteMissing = function () {
214
214
 
215
215
  // [function]
216
216
 
217
+ const noManifest = function (file, dir, found) {
218
+ return blocks(
219
+ dir === "." ? `No ${file} in this directory.` : `No ${file} in ${dir}`,
220
+ found
221
+ ? `The project is in \`${found}\`: run arc there, or pass \`-C ${found}\`.`
222
+ : "Run arc in the project's directory, or pass -C, or start a project with `arc init`.",
223
+ );
224
+ };
225
+
226
+ // [function]
227
+
228
+ const projectNotRepoRoot = function (prefix) {
229
+ return blocks(
230
+ `arc deploy git releases the project at the repository's root, and this one is in ${prefix}`,
231
+ "Deploy it with `arc deploy`, or give it a repository of its own.",
232
+ );
233
+ };
234
+
235
+ // [function]
236
+
217
237
  const gitRepoMissing = function () {
218
238
  return blocks(
219
239
  "No Git repository found.",
@@ -771,6 +791,7 @@ module.exports = {
771
791
  loginFailed,
772
792
  noGameId,
773
793
  noLockFile,
794
+ noManifest,
774
795
  noProductionRelease,
775
796
  noTemplate,
776
797
  noVideoMetadata,
@@ -783,6 +804,7 @@ module.exports = {
783
804
  packageTooLarge,
784
805
  packageTooManyFiles,
785
806
  packageUncompressedTooLarge,
807
+ projectNotRepoRoot,
786
808
  releaseFailed,
787
809
  releasePublished,
788
810
  releaseTimedOut,