@andrian.yablonskyy/thub-agent 1.0.21 → 1.0.22

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/cli.js +37 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andrian.yablonskyy/thub-agent",
3
- "version": "1.0.21",
3
+ "version": "1.0.22",
4
4
  "description": "TestHub Agent CLI — the single entry point CI/CD and developers use to submit and follow test jobs",
5
5
  "bin": {
6
6
  "thub": "./src/cli.js"
package/src/cli.js CHANGED
@@ -54,6 +54,33 @@ function client(){
54
54
  return new ApiClient({ baseUrl: url, token, userAgent: `thub-agent/${version}` });
55
55
  }
56
56
 
57
+ // `--image`: an http(s) URL is a firmware file to download; anything else
58
+ // is taken as a Docker image reference, which only an SW job can run. Caught
59
+ // here so `--type hw --image alpine` explains itself instead of failing
60
+ // the Coordinator's schema check.
61
+ function firmwareFromImage(opts){
62
+ if (/^https?:\/\//i.test(opts.image)){
63
+ return { url: opts.image, ...(opts.sha256 ? { sha256: opts.sha256 } : {}) };
64
+ }
65
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(opts.image)){
66
+ throw usageError(`--image ${opts.image}: only http(s) URLs can be downloaded as firmware`);
67
+ }
68
+ if (opts.type !== 'sw'){
69
+ throw usageError(
70
+ `--image ${opts.image} looks like a Docker image, which only an SW job can run (--type sw). ` +
71
+ 'An HW job flashes a firmware file: pass its http(s) URL.'
72
+ );
73
+ }
74
+ if (opts.sha256){
75
+ throw usageError('--sha256 applies to a firmware URL only; pin a Docker image by digest instead (image@sha256:...)');
76
+ }
77
+ return { image: opts.image };
78
+ }
79
+
80
+ function usageError(message){
81
+ return Object.assign(new Error(message), { status: EXIT_CODES.USAGE });
82
+ }
83
+
57
84
  function fail(err){
58
85
  console.error(`Error: ${err.message}`);
59
86
  process.exit(err.status && Number.isInteger(err.status) && err.status < 100 ? err.status : EXIT_CODES.USAGE);
@@ -80,8 +107,13 @@ program
80
107
  'Free-text job owner, shown on the Client and the dashboard to tell whose job is whose ' +
81
108
  '— purely a label, not an identity. Overrides THUB_USER / config file.'
82
109
  )
83
- .requiredOption('--image <url>', 'Firmware/build image URL (Artifactory or a Docker registry blob) fetched by the Client')
84
- .option('--sha256 <hex>', 'Expected sha256 of --image; the Client verifies it before flashing/running')
110
+ .requiredOption(
111
+ '--image <url|docker-image>',
112
+ 'What the DUT runs: a firmware file URL (http/https, e.g. Artifactory) the Client downloads — HW and SW jobs — ' +
113
+ 'or, for --type sw only, a Docker image to run as the DUT (e.g. alpine, alpine:3.20, registry.lab:5000/emu:1), ' +
114
+ 'pulled from the Client\'s registry or Docker Hub; the Client must allow it (sw.allowJobImages)'
115
+ )
116
+ .option('--sha256 <hex>', 'Expected sha256 of a firmware --image URL; the Client verifies it before flashing/running')
85
117
  .requiredOption('--tests <url>', 'Test package URL in Artifactory')
86
118
  .option('--suite <name>', 'Test suite name', 'default')
87
119
  .option('--arg <value>', 'Extra argument passed through to run-tests.sh on the Client (repeatable)', collectRepeatable, [])
@@ -105,7 +137,8 @@ program
105
137
  )
106
138
  .action(async (opts) => {
107
139
  try {
108
- const c = client(),
140
+ const firmware = firmwareFromImage(opts),
141
+ c = client(),
109
142
  labels = [...(opts.board ? [`board:${opts.board}`] : []), ...opts.label],
110
143
  meta = Object.fromEntries(opts.meta.map((kv) => kv.split(/=(.*)/s).slice(0, 2))),
111
144
  group = resolveGroup({ group: opts.group }),
@@ -113,7 +146,7 @@ program
113
146
 
114
147
  spec = {
115
148
  target: { type: opts.type, labels, ...(group ? { group } : {}), ...(opts.client ? { client: opts.client } : {}) },
116
- firmware: { url: opts.image, ...(opts.sha256 ? { sha256: opts.sha256 } : {}) },
149
+ firmware,
117
150
  tests: { url: opts.tests, suite: opts.suite, args: opts.arg },
118
151
  timeoutSec: parseDurationSec(opts.timeout),
119
152
  ...(opts.priority !== undefined ? { priority: opts.priority } : {}),