@xano/cli 0.0.95 → 1.0.1

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 (236) hide show
  1. package/README.md +133 -66
  2. package/dist/base-command.d.ts +41 -1
  3. package/dist/base-command.js +92 -3
  4. package/dist/commands/auth/index.d.ts +1 -0
  5. package/dist/commands/auth/index.js +16 -11
  6. package/dist/commands/branch/create/index.d.ts +4 -1
  7. package/dist/commands/branch/create/index.js +22 -21
  8. package/dist/commands/branch/delete/index.d.ts +1 -0
  9. package/dist/commands/branch/delete/index.js +1 -4
  10. package/dist/commands/branch/edit/index.d.ts +1 -0
  11. package/dist/commands/branch/edit/index.js +1 -4
  12. package/dist/commands/branch/get/index.d.ts +1 -0
  13. package/dist/commands/branch/get/index.js +1 -4
  14. package/dist/commands/branch/list/index.d.ts +2 -6
  15. package/dist/commands/branch/list/index.js +13 -17
  16. package/dist/commands/branch/set_live/index.d.ts +1 -0
  17. package/dist/commands/branch/set_live/index.js +1 -4
  18. package/dist/commands/function/create/index.d.ts +1 -0
  19. package/dist/commands/function/create/index.js +1 -2
  20. package/dist/commands/function/edit/index.d.ts +1 -0
  21. package/dist/commands/function/edit/index.js +1 -2
  22. package/dist/commands/function/get/index.d.ts +1 -0
  23. package/dist/commands/function/get/index.js +1 -4
  24. package/dist/commands/function/list/index.d.ts +1 -0
  25. package/dist/commands/function/list/index.js +1 -4
  26. package/dist/commands/platform/get/index.d.ts +1 -0
  27. package/dist/commands/platform/get/index.js +1 -4
  28. package/dist/commands/platform/list/index.d.ts +1 -0
  29. package/dist/commands/platform/list/index.js +1 -4
  30. package/dist/commands/profile/create/index.d.ts +1 -0
  31. package/dist/commands/profile/create/index.js +12 -6
  32. package/dist/commands/profile/delete/index.d.ts +1 -0
  33. package/dist/commands/profile/delete/index.js +8 -4
  34. package/dist/commands/profile/edit/index.d.ts +1 -0
  35. package/dist/commands/profile/edit/index.js +3 -6
  36. package/dist/commands/profile/get/index.d.ts +3 -0
  37. package/dist/commands/profile/get/index.js +12 -5
  38. package/dist/commands/profile/list/index.d.ts +1 -0
  39. package/dist/commands/profile/list/index.js +8 -4
  40. package/dist/commands/profile/me/index.d.ts +1 -0
  41. package/dist/commands/profile/me/index.js +22 -6
  42. package/dist/commands/profile/set/index.d.ts +3 -0
  43. package/dist/commands/profile/set/index.js +12 -6
  44. package/dist/commands/profile/token/index.d.ts +3 -0
  45. package/dist/commands/profile/token/index.js +12 -5
  46. package/dist/commands/profile/wizard/index.d.ts +1 -0
  47. package/dist/commands/profile/wizard/index.js +16 -12
  48. package/dist/commands/profile/workspace/index.d.ts +3 -0
  49. package/dist/commands/profile/workspace/index.js +12 -5
  50. package/dist/commands/profile/workspace/set/index.d.ts +1 -0
  51. package/dist/commands/profile/workspace/set/index.js +2 -4
  52. package/dist/commands/release/create/index.d.ts +4 -1
  53. package/dist/commands/release/create/index.js +12 -14
  54. package/dist/commands/release/delete/index.d.ts +1 -0
  55. package/dist/commands/release/delete/index.js +1 -4
  56. package/dist/commands/release/deploy/index.d.ts +20 -0
  57. package/dist/commands/release/deploy/index.js +137 -0
  58. package/dist/commands/release/edit/index.d.ts +1 -0
  59. package/dist/commands/release/edit/index.js +1 -4
  60. package/dist/commands/release/export/index.d.ts +1 -0
  61. package/dist/commands/release/export/index.js +1 -3
  62. package/dist/commands/release/get/index.d.ts +1 -0
  63. package/dist/commands/release/get/index.js +1 -4
  64. package/dist/commands/release/import/index.d.ts +1 -0
  65. package/dist/commands/release/import/index.js +1 -3
  66. package/dist/commands/release/list/index.d.ts +1 -0
  67. package/dist/commands/release/list/index.js +1 -4
  68. package/dist/commands/release/pull/index.d.ts +2 -3
  69. package/dist/commands/release/pull/index.js +19 -18
  70. package/dist/commands/release/push/index.d.ts +2 -3
  71. package/dist/commands/release/push/index.js +19 -22
  72. package/dist/commands/sandbox/delete/index.d.ts +13 -0
  73. package/dist/commands/sandbox/delete/index.js +71 -0
  74. package/dist/commands/sandbox/env/delete/index.d.ts +15 -0
  75. package/dist/commands/sandbox/env/delete/index.js +89 -0
  76. package/dist/commands/sandbox/env/get/index.d.ts +13 -0
  77. package/dist/commands/sandbox/env/get/index.js +65 -0
  78. package/dist/commands/sandbox/env/get_all/index.d.ts +14 -0
  79. package/dist/commands/sandbox/env/get_all/index.js +78 -0
  80. package/dist/commands/sandbox/env/list/index.d.ts +12 -0
  81. package/dist/commands/sandbox/env/list/index.js +67 -0
  82. package/dist/commands/sandbox/env/set/index.d.ts +14 -0
  83. package/dist/commands/sandbox/env/set/index.js +74 -0
  84. package/dist/commands/sandbox/env/set_all/index.d.ts +14 -0
  85. package/dist/commands/sandbox/env/set_all/index.js +86 -0
  86. package/dist/commands/sandbox/get/index.d.ts +12 -0
  87. package/dist/commands/sandbox/get/index.js +63 -0
  88. package/dist/commands/sandbox/impersonate/index.d.ts +5 -0
  89. package/dist/commands/sandbox/impersonate/index.js +5 -0
  90. package/dist/commands/sandbox/license/get/index.d.ts +14 -0
  91. package/dist/commands/sandbox/license/get/index.js +78 -0
  92. package/dist/commands/sandbox/license/set/index.d.ts +15 -0
  93. package/dist/commands/sandbox/license/set/index.js +95 -0
  94. package/dist/commands/sandbox/pull/index.d.ts +16 -0
  95. package/dist/commands/sandbox/pull/index.js +185 -0
  96. package/dist/commands/sandbox/push/index.d.ts +26 -0
  97. package/dist/commands/sandbox/push/index.js +196 -0
  98. package/dist/commands/sandbox/reset/index.d.ts +13 -0
  99. package/dist/commands/sandbox/reset/index.js +71 -0
  100. package/dist/commands/sandbox/review/index.d.ts +14 -0
  101. package/dist/commands/sandbox/review/index.js +94 -0
  102. package/dist/commands/sandbox/unit_test/list/index.d.ts +14 -0
  103. package/dist/commands/sandbox/unit_test/list/index.js +91 -0
  104. package/dist/commands/sandbox/unit_test/run/index.d.ts +15 -0
  105. package/dist/commands/sandbox/unit_test/run/index.js +79 -0
  106. package/dist/commands/sandbox/unit_test/run_all/index.d.ts +14 -0
  107. package/dist/commands/sandbox/unit_test/run_all/index.js +171 -0
  108. package/dist/commands/sandbox/workflow_test/list/index.d.ts +13 -0
  109. package/dist/commands/sandbox/workflow_test/list/index.js +84 -0
  110. package/dist/commands/sandbox/workflow_test/run/index.d.ts +18 -0
  111. package/dist/commands/sandbox/workflow_test/run/index.js +77 -0
  112. package/dist/commands/sandbox/workflow_test/run_all/index.d.ts +13 -0
  113. package/dist/commands/sandbox/workflow_test/run_all/index.js +157 -0
  114. package/dist/commands/static_host/build/create/index.d.ts +1 -0
  115. package/dist/commands/static_host/build/create/index.js +1 -3
  116. package/dist/commands/static_host/build/get/index.d.ts +1 -0
  117. package/dist/commands/static_host/build/get/index.js +1 -4
  118. package/dist/commands/static_host/build/list/index.d.ts +1 -0
  119. package/dist/commands/static_host/build/list/index.js +1 -4
  120. package/dist/commands/static_host/list/index.d.ts +1 -0
  121. package/dist/commands/static_host/list/index.js +1 -4
  122. package/dist/commands/tenant/backup/create/index.d.ts +1 -0
  123. package/dist/commands/tenant/backup/create/index.js +1 -4
  124. package/dist/commands/tenant/backup/delete/index.d.ts +1 -0
  125. package/dist/commands/tenant/backup/delete/index.js +1 -4
  126. package/dist/commands/tenant/backup/export/index.d.ts +1 -0
  127. package/dist/commands/tenant/backup/export/index.js +1 -3
  128. package/dist/commands/tenant/backup/import/index.d.ts +1 -0
  129. package/dist/commands/tenant/backup/import/index.js +1 -3
  130. package/dist/commands/tenant/backup/list/index.d.ts +1 -0
  131. package/dist/commands/tenant/backup/list/index.js +1 -4
  132. package/dist/commands/tenant/backup/restore/index.d.ts +1 -0
  133. package/dist/commands/tenant/backup/restore/index.js +1 -4
  134. package/dist/commands/tenant/cluster/create/index.d.ts +1 -0
  135. package/dist/commands/tenant/cluster/create/index.js +1 -3
  136. package/dist/commands/tenant/cluster/delete/index.d.ts +1 -0
  137. package/dist/commands/tenant/cluster/delete/index.js +1 -4
  138. package/dist/commands/tenant/cluster/edit/index.d.ts +1 -0
  139. package/dist/commands/tenant/cluster/edit/index.js +1 -4
  140. package/dist/commands/tenant/cluster/get/index.d.ts +1 -0
  141. package/dist/commands/tenant/cluster/get/index.js +1 -4
  142. package/dist/commands/tenant/cluster/license/get/index.d.ts +1 -0
  143. package/dist/commands/tenant/cluster/license/get/index.js +1 -3
  144. package/dist/commands/tenant/cluster/license/set/index.d.ts +1 -0
  145. package/dist/commands/tenant/cluster/license/set/index.js +1 -3
  146. package/dist/commands/tenant/cluster/list/index.d.ts +1 -0
  147. package/dist/commands/tenant/cluster/list/index.js +1 -4
  148. package/dist/commands/tenant/create/index.d.ts +1 -1
  149. package/dist/commands/tenant/create/index.js +1 -8
  150. package/dist/commands/tenant/delete/index.d.ts +1 -0
  151. package/dist/commands/tenant/delete/index.js +1 -4
  152. package/dist/commands/tenant/deploy_platform/index.d.ts +1 -0
  153. package/dist/commands/tenant/deploy_platform/index.js +1 -3
  154. package/dist/commands/tenant/deploy_release/index.d.ts +1 -0
  155. package/dist/commands/tenant/deploy_release/index.js +1 -4
  156. package/dist/commands/tenant/edit/index.d.ts +1 -0
  157. package/dist/commands/tenant/edit/index.js +1 -4
  158. package/dist/commands/tenant/env/delete/index.d.ts +1 -0
  159. package/dist/commands/tenant/env/delete/index.js +1 -4
  160. package/dist/commands/tenant/env/get/index.d.ts +1 -0
  161. package/dist/commands/tenant/env/get/index.js +1 -4
  162. package/dist/commands/tenant/env/get_all/index.d.ts +1 -0
  163. package/dist/commands/tenant/env/get_all/index.js +1 -3
  164. package/dist/commands/tenant/env/list/index.d.ts +1 -0
  165. package/dist/commands/tenant/env/list/index.js +1 -4
  166. package/dist/commands/tenant/env/set/index.d.ts +1 -0
  167. package/dist/commands/tenant/env/set/index.js +1 -4
  168. package/dist/commands/tenant/env/set_all/index.d.ts +1 -0
  169. package/dist/commands/tenant/env/set_all/index.js +1 -3
  170. package/dist/commands/tenant/get/index.d.ts +1 -0
  171. package/dist/commands/tenant/get/index.js +3 -6
  172. package/dist/commands/tenant/impersonate/index.d.ts +1 -0
  173. package/dist/commands/tenant/impersonate/index.js +1 -4
  174. package/dist/commands/tenant/license/get/index.d.ts +1 -0
  175. package/dist/commands/tenant/license/get/index.js +1 -3
  176. package/dist/commands/tenant/license/set/index.d.ts +1 -0
  177. package/dist/commands/tenant/license/set/index.js +1 -3
  178. package/dist/commands/tenant/list/index.d.ts +1 -0
  179. package/dist/commands/tenant/list/index.js +3 -6
  180. package/dist/commands/tenant/pull/index.d.ts +2 -3
  181. package/dist/commands/tenant/pull/index.js +20 -21
  182. package/dist/commands/tenant/push/index.d.ts +2 -22
  183. package/dist/commands/tenant/push/index.js +7 -259
  184. package/dist/commands/tenant/unit_test/list/index.d.ts +16 -0
  185. package/dist/commands/tenant/unit_test/list/index.js +115 -0
  186. package/dist/commands/tenant/unit_test/run/index.d.ts +17 -0
  187. package/dist/commands/tenant/unit_test/run/index.js +103 -0
  188. package/dist/commands/tenant/unit_test/run_all/index.d.ts +16 -0
  189. package/dist/commands/tenant/unit_test/run_all/index.js +190 -0
  190. package/dist/commands/tenant/workflow_test/list/index.d.ts +15 -0
  191. package/dist/commands/tenant/workflow_test/list/index.js +108 -0
  192. package/dist/commands/tenant/workflow_test/run/index.d.ts +20 -0
  193. package/dist/commands/tenant/workflow_test/run/index.js +101 -0
  194. package/dist/commands/tenant/workflow_test/run_all/index.d.ts +15 -0
  195. package/dist/commands/tenant/workflow_test/run_all/index.js +176 -0
  196. package/dist/commands/unit_test/list/index.d.ts +1 -0
  197. package/dist/commands/unit_test/list/index.js +1 -4
  198. package/dist/commands/unit_test/run/index.d.ts +1 -0
  199. package/dist/commands/unit_test/run/index.js +1 -4
  200. package/dist/commands/unit_test/run_all/index.d.ts +1 -0
  201. package/dist/commands/unit_test/run_all/index.js +1 -4
  202. package/dist/commands/update/index.d.ts +1 -0
  203. package/dist/commands/workflow_test/delete/index.d.ts +1 -0
  204. package/dist/commands/workflow_test/delete/index.js +1 -4
  205. package/dist/commands/workflow_test/get/index.d.ts +1 -0
  206. package/dist/commands/workflow_test/get/index.js +1 -4
  207. package/dist/commands/workflow_test/list/index.d.ts +1 -0
  208. package/dist/commands/workflow_test/list/index.js +1 -4
  209. package/dist/commands/workflow_test/run/index.d.ts +1 -0
  210. package/dist/commands/workflow_test/run/index.js +1 -4
  211. package/dist/commands/workflow_test/run_all/index.d.ts +1 -0
  212. package/dist/commands/workflow_test/run_all/index.js +1 -4
  213. package/dist/commands/workspace/create/index.d.ts +1 -0
  214. package/dist/commands/workspace/create/index.js +1 -4
  215. package/dist/commands/workspace/delete/index.d.ts +2 -6
  216. package/dist/commands/workspace/delete/index.js +17 -16
  217. package/dist/commands/workspace/edit/index.d.ts +3 -6
  218. package/dist/commands/workspace/edit/index.js +31 -25
  219. package/dist/commands/workspace/get/index.d.ts +2 -6
  220. package/dist/commands/workspace/get/index.js +23 -25
  221. package/dist/commands/workspace/git/pull/index.d.ts +2 -3
  222. package/dist/commands/workspace/git/pull/index.js +18 -17
  223. package/dist/commands/workspace/list/index.d.ts +2 -0
  224. package/dist/commands/workspace/list/index.js +15 -11
  225. package/dist/commands/workspace/pull/index.d.ts +2 -3
  226. package/dist/commands/workspace/pull/index.js +21 -24
  227. package/dist/commands/workspace/push/index.d.ts +7 -16
  228. package/dist/commands/workspace/push/index.js +85 -674
  229. package/dist/help.d.ts +2 -1
  230. package/dist/help.js +39 -1
  231. package/dist/utils/multidoc-push.d.ts +63 -0
  232. package/dist/utils/multidoc-push.js +690 -0
  233. package/dist/utils/reference-checker.d.ts +57 -0
  234. package/dist/utils/reference-checker.js +232 -0
  235. package/oclif.manifest.json +5562 -2228
  236. package/package.json +19 -3
@@ -0,0 +1,190 @@
1
+ import { Flags } from '@oclif/core';
2
+ import BaseCommand from '../../../../base-command.js';
3
+ export default class TenantUnitTestRunAll extends BaseCommand {
4
+ static description = 'Run all unit tests for a tenant';
5
+ static examples = [
6
+ `$ xano tenant unit-test run-all -t my-tenant
7
+ Running 5 unit tests...
8
+
9
+ PASS my-test [function: math]
10
+ FAIL data-validation [function: validate]
11
+ Error: assertion failed
12
+
13
+ Results: 4 passed, 1 failed
14
+ `,
15
+ `$ xano tenant unit-test run-all -t my-tenant -o json`,
16
+ ];
17
+ static flags = {
18
+ ...BaseCommand.baseFlags,
19
+ branch: Flags.string({
20
+ char: 'b',
21
+ description: 'Filter by branch name',
22
+ required: false,
23
+ }),
24
+ 'obj-type': Flags.string({
25
+ description: 'Filter by object type',
26
+ options: ['function', 'query', 'middleware'],
27
+ required: false,
28
+ }),
29
+ output: Flags.string({
30
+ char: 'o',
31
+ default: 'summary',
32
+ description: 'Output format',
33
+ options: ['summary', 'json'],
34
+ required: false,
35
+ }),
36
+ tenant: Flags.string({
37
+ char: 't',
38
+ description: 'Tenant name',
39
+ required: true,
40
+ }),
41
+ workspace: Flags.string({
42
+ char: 'w',
43
+ description: 'Workspace ID (uses profile workspace if not provided)',
44
+ required: false,
45
+ }),
46
+ };
47
+ async run() {
48
+ const { flags } = await this.parse(TenantUnitTestRunAll);
49
+ const profileName = flags.profile || this.getDefaultProfile();
50
+ const credentials = this.loadCredentialsFile();
51
+ if (!credentials || !(profileName in credentials.profiles)) {
52
+ this.error(`Profile '${profileName}' not found.\nCreate a profile using 'xano profile create'`);
53
+ }
54
+ const profile = credentials.profiles[profileName];
55
+ if (!profile.instance_origin) {
56
+ this.error(`Profile '${profileName}' is missing instance_origin`);
57
+ }
58
+ if (!profile.access_token) {
59
+ this.error(`Profile '${profileName}' is missing access_token`);
60
+ }
61
+ const workspaceId = flags.workspace || profile.workspace;
62
+ if (!workspaceId) {
63
+ this.error('No workspace ID provided. Use --workspace flag or set one in your profile.');
64
+ }
65
+ const tenantName = encodeURIComponent(flags.tenant);
66
+ const baseUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/tenant/${tenantName}/unit_test`;
67
+ try {
68
+ const listParams = new URLSearchParams();
69
+ listParams.set('per_page', '10000');
70
+ if (flags.branch)
71
+ listParams.set('branch', flags.branch);
72
+ if (flags['obj-type'])
73
+ listParams.set('obj_type', flags['obj-type']);
74
+ const listResponse = await this.verboseFetch(`${baseUrl}?${listParams}`, {
75
+ headers: {
76
+ accept: 'application/json',
77
+ Authorization: `Bearer ${profile.access_token}`,
78
+ },
79
+ method: 'GET',
80
+ }, flags.verbose, profile.access_token);
81
+ if (!listResponse.ok) {
82
+ const errorText = await listResponse.text();
83
+ this.error(`Failed to list unit tests: ${listResponse.status}: ${listResponse.statusText}\n${errorText}`);
84
+ }
85
+ const data = (await listResponse.json());
86
+ let tests;
87
+ if (Array.isArray(data)) {
88
+ tests = data;
89
+ }
90
+ else if (data && typeof data === 'object' && 'items' in data && Array.isArray(data.items)) {
91
+ tests = data.items;
92
+ }
93
+ else {
94
+ this.error('Unexpected API response format');
95
+ }
96
+ if (tests.length === 0) {
97
+ this.log('No unit tests found');
98
+ return;
99
+ }
100
+ if (flags.output === 'summary') {
101
+ this.log(`Running ${tests.length} unit test${tests.length === 1 ? '' : 's'}...\n`);
102
+ }
103
+ const results = [];
104
+ for (const test of tests) {
105
+ const runUrl = `${baseUrl}/${test.id}/run`;
106
+ try {
107
+ const runResponse = await this.verboseFetch(runUrl, {
108
+ headers: {
109
+ accept: 'application/json',
110
+ Authorization: `Bearer ${profile.access_token}`,
111
+ 'Content-Type': 'application/json',
112
+ },
113
+ method: 'POST',
114
+ }, flags.verbose, profile.access_token);
115
+ if (!runResponse.ok) {
116
+ const errorText = await runResponse.text();
117
+ results.push({
118
+ message: `API error ${runResponse.status}: ${errorText}`,
119
+ name: test.name,
120
+ obj_name: test.obj_name,
121
+ obj_type: test.obj_type,
122
+ status: 'fail',
123
+ });
124
+ if (flags.output === 'summary') {
125
+ this.log(`FAIL ${test.name} [${test.obj_type}: ${test.obj_name}]`);
126
+ this.log(` Error: API error ${runResponse.status}`);
127
+ }
128
+ continue;
129
+ }
130
+ const runResult = (await runResponse.json());
131
+ const passed = runResult.status === 'ok';
132
+ const failedExpects = runResult.results?.filter((r) => r.status === 'fail') ?? [];
133
+ results.push({
134
+ message: failedExpects[0]?.message,
135
+ name: test.name,
136
+ obj_name: test.obj_name,
137
+ obj_type: test.obj_type,
138
+ status: passed ? 'pass' : 'fail',
139
+ });
140
+ if (flags.output === 'summary') {
141
+ if (passed) {
142
+ this.log(`PASS ${test.name} [${test.obj_type}: ${test.obj_name}]`);
143
+ }
144
+ else {
145
+ this.log(`FAIL ${test.name} [${test.obj_type}: ${test.obj_name}]`);
146
+ for (const expect of failedExpects) {
147
+ if (expect.message) {
148
+ this.log(` Error: ${expect.message}`);
149
+ }
150
+ }
151
+ }
152
+ }
153
+ }
154
+ catch (error) {
155
+ const message = error instanceof Error ? error.message : String(error);
156
+ results.push({
157
+ message,
158
+ name: test.name,
159
+ obj_name: test.obj_name,
160
+ obj_type: test.obj_type,
161
+ status: 'fail',
162
+ });
163
+ if (flags.output === 'summary') {
164
+ this.log(`FAIL ${test.name} [${test.obj_type}: ${test.obj_name}]`);
165
+ this.log(` Error: ${message}`);
166
+ }
167
+ }
168
+ }
169
+ const passed = results.filter((r) => r.status === 'pass').length;
170
+ const failed = results.filter((r) => r.status === 'fail').length;
171
+ if (flags.output === 'json') {
172
+ this.log(JSON.stringify({ failed, passed, results }, null, 2));
173
+ }
174
+ else {
175
+ this.log(`\nResults: ${passed} passed, ${failed} failed`);
176
+ }
177
+ if (failed > 0) {
178
+ process.exitCode = 1;
179
+ }
180
+ }
181
+ catch (error) {
182
+ if (error instanceof Error) {
183
+ this.error(`Failed to run unit tests: ${error.message}`);
184
+ }
185
+ else {
186
+ this.error(`Failed to run unit tests: ${String(error)}`);
187
+ }
188
+ }
189
+ }
190
+ }
@@ -0,0 +1,15 @@
1
+ import BaseCommand from '../../../../base-command.js';
2
+ export default class TenantWorkflowTestList extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ branch: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
+ tenant: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
+ workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
+ };
14
+ run(): Promise<void>;
15
+ }
@@ -0,0 +1,108 @@
1
+ import { Flags } from '@oclif/core';
2
+ import BaseCommand from '../../../../base-command.js';
3
+ export default class TenantWorkflowTestList extends BaseCommand {
4
+ static description = 'List workflow tests for a tenant';
5
+ static examples = [
6
+ `$ xano tenant workflow-test list -t my-tenant
7
+ Workflow tests for tenant my-tenant:
8
+ - my-test (ID: 1)
9
+ `,
10
+ `$ xano tenant workflow-test list -t my-tenant -w 5 -o json`,
11
+ ];
12
+ static flags = {
13
+ ...BaseCommand.baseFlags,
14
+ branch: Flags.string({
15
+ char: 'b',
16
+ description: 'Filter by branch name',
17
+ required: false,
18
+ }),
19
+ output: Flags.string({
20
+ char: 'o',
21
+ default: 'summary',
22
+ description: 'Output format',
23
+ options: ['summary', 'json'],
24
+ required: false,
25
+ }),
26
+ tenant: Flags.string({
27
+ char: 't',
28
+ description: 'Tenant name',
29
+ required: true,
30
+ }),
31
+ workspace: Flags.string({
32
+ char: 'w',
33
+ description: 'Workspace ID (uses profile workspace if not provided)',
34
+ required: false,
35
+ }),
36
+ };
37
+ async run() {
38
+ const { flags } = await this.parse(TenantWorkflowTestList);
39
+ const profileName = flags.profile || this.getDefaultProfile();
40
+ const credentials = this.loadCredentialsFile();
41
+ if (!credentials || !(profileName in credentials.profiles)) {
42
+ this.error(`Profile '${profileName}' not found.\nCreate a profile using 'xano profile create'`);
43
+ }
44
+ const profile = credentials.profiles[profileName];
45
+ if (!profile.instance_origin) {
46
+ this.error(`Profile '${profileName}' is missing instance_origin`);
47
+ }
48
+ if (!profile.access_token) {
49
+ this.error(`Profile '${profileName}' is missing access_token`);
50
+ }
51
+ const workspaceId = flags.workspace || profile.workspace;
52
+ if (!workspaceId) {
53
+ this.error('No workspace ID provided. Use --workspace flag or set one in your profile.');
54
+ }
55
+ const tenantName = encodeURIComponent(flags.tenant);
56
+ const params = new URLSearchParams();
57
+ params.set('per_page', '10000');
58
+ if (flags.branch)
59
+ params.set('branch', flags.branch);
60
+ const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/tenant/${tenantName}/workflow_test?${params}`;
61
+ try {
62
+ const response = await this.verboseFetch(apiUrl, {
63
+ headers: {
64
+ accept: 'application/json',
65
+ Authorization: `Bearer ${profile.access_token}`,
66
+ },
67
+ method: 'GET',
68
+ }, flags.verbose, profile.access_token);
69
+ if (!response.ok) {
70
+ const errorText = await response.text();
71
+ this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
72
+ }
73
+ const data = (await response.json());
74
+ let tests;
75
+ if (Array.isArray(data)) {
76
+ tests = data;
77
+ }
78
+ else if (data && typeof data === 'object' && 'items' in data && Array.isArray(data.items)) {
79
+ tests = data.items;
80
+ }
81
+ else {
82
+ this.error('Unexpected API response format');
83
+ }
84
+ if (flags.output === 'json') {
85
+ this.log(JSON.stringify(tests, null, 2));
86
+ }
87
+ else {
88
+ if (tests.length === 0) {
89
+ this.log('No workflow tests found');
90
+ }
91
+ else {
92
+ this.log(`Workflow tests for tenant ${flags.tenant}:`);
93
+ for (const test of tests) {
94
+ this.log(` - ${test.name} (ID: ${test.id})`);
95
+ }
96
+ }
97
+ }
98
+ }
99
+ catch (error) {
100
+ if (error instanceof Error) {
101
+ this.error(`Failed to list workflow tests: ${error.message}`);
102
+ }
103
+ else {
104
+ this.error(`Failed to list workflow tests: ${String(error)}`);
105
+ }
106
+ }
107
+ }
108
+ }
@@ -0,0 +1,20 @@
1
+ import BaseCommand from '../../../../base-command.js';
2
+ export default class TenantWorkflowTestRun extends BaseCommand {
3
+ static args: {
4
+ workflow_test_id: import("@oclif/core/interfaces").Arg<number, {
5
+ max?: number;
6
+ min?: number;
7
+ }>;
8
+ };
9
+ static description: string;
10
+ static examples: string[];
11
+ static flags: {
12
+ output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
13
+ tenant: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
14
+ workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
+ config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
16
+ profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
17
+ verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
18
+ };
19
+ run(): Promise<void>;
20
+ }
@@ -0,0 +1,101 @@
1
+ import { Args, Flags } from '@oclif/core';
2
+ import BaseCommand from '../../../../base-command.js';
3
+ export default class TenantWorkflowTestRun extends BaseCommand {
4
+ static args = {
5
+ workflow_test_id: Args.integer({
6
+ description: 'ID of the workflow test to run',
7
+ required: true,
8
+ }),
9
+ };
10
+ static description = 'Run a workflow test for a tenant';
11
+ static examples = [
12
+ `$ xano tenant workflow-test run 42 -t my-tenant
13
+ Running workflow test 42...
14
+ Result: PASS (0.25s)
15
+ `,
16
+ `$ xano tenant workflow-test run 42 -t my-tenant -o json`,
17
+ ];
18
+ static flags = {
19
+ ...BaseCommand.baseFlags,
20
+ output: Flags.string({
21
+ char: 'o',
22
+ default: 'summary',
23
+ description: 'Output format',
24
+ options: ['summary', 'json'],
25
+ required: false,
26
+ }),
27
+ tenant: Flags.string({
28
+ char: 't',
29
+ description: 'Tenant name',
30
+ required: true,
31
+ }),
32
+ workspace: Flags.string({
33
+ char: 'w',
34
+ description: 'Workspace ID (uses profile workspace if not provided)',
35
+ required: false,
36
+ }),
37
+ };
38
+ async run() {
39
+ const { args, flags } = await this.parse(TenantWorkflowTestRun);
40
+ const profileName = flags.profile || this.getDefaultProfile();
41
+ const credentials = this.loadCredentialsFile();
42
+ if (!credentials || !(profileName in credentials.profiles)) {
43
+ this.error(`Profile '${profileName}' not found.\nCreate a profile using 'xano profile create'`);
44
+ }
45
+ const profile = credentials.profiles[profileName];
46
+ if (!profile.instance_origin) {
47
+ this.error(`Profile '${profileName}' is missing instance_origin`);
48
+ }
49
+ if (!profile.access_token) {
50
+ this.error(`Profile '${profileName}' is missing access_token`);
51
+ }
52
+ const workspaceId = flags.workspace || profile.workspace;
53
+ if (!workspaceId) {
54
+ this.error('No workspace ID provided. Use --workspace flag or set one in your profile.');
55
+ }
56
+ const tenantName = encodeURIComponent(flags.tenant);
57
+ const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/tenant/${tenantName}/workflow_test/${args.workflow_test_id}/run`;
58
+ try {
59
+ if (flags.output === 'summary') {
60
+ this.log(`Running workflow test ${args.workflow_test_id}...`);
61
+ }
62
+ const response = await this.verboseFetch(apiUrl, {
63
+ headers: {
64
+ accept: 'application/json',
65
+ Authorization: `Bearer ${profile.access_token}`,
66
+ 'Content-Type': 'application/json',
67
+ },
68
+ method: 'POST',
69
+ }, flags.verbose, profile.access_token);
70
+ if (!response.ok) {
71
+ const errorText = await response.text();
72
+ this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
73
+ }
74
+ const result = (await response.json());
75
+ if (flags.output === 'json') {
76
+ this.log(JSON.stringify(result, null, 2));
77
+ }
78
+ else {
79
+ const timing = result.timing ? ` (${result.timing}s)` : '';
80
+ if (result.status === 'ok') {
81
+ this.log(`Result: PASS${timing}`);
82
+ }
83
+ else {
84
+ this.log(`Result: FAIL${timing}`);
85
+ if (result.message) {
86
+ this.log(` Error: ${result.message}`);
87
+ }
88
+ this.exit(1);
89
+ }
90
+ }
91
+ }
92
+ catch (error) {
93
+ if (error instanceof Error) {
94
+ this.error(`Failed to run workflow test: ${error.message}`);
95
+ }
96
+ else {
97
+ this.error(`Failed to run workflow test: ${String(error)}`);
98
+ }
99
+ }
100
+ }
101
+ }
@@ -0,0 +1,15 @@
1
+ import BaseCommand from '../../../../base-command.js';
2
+ export default class TenantWorkflowTestRunAll extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ branch: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
+ tenant: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
+ workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
+ };
14
+ run(): Promise<void>;
15
+ }
@@ -0,0 +1,176 @@
1
+ import { Flags } from '@oclif/core';
2
+ import BaseCommand from '../../../../base-command.js';
3
+ export default class TenantWorkflowTestRunAll extends BaseCommand {
4
+ static description = 'Run all workflow tests for a tenant';
5
+ static examples = [
6
+ `$ xano tenant workflow-test run-all -t my-tenant
7
+ Running 3 workflow tests...
8
+
9
+ PASS my-test (0.25s)
10
+ FAIL data-check (0.10s)
11
+ Error: assertion failed
12
+
13
+ Results: 2 passed, 1 failed
14
+ `,
15
+ `$ xano tenant workflow-test run-all -t my-tenant -o json`,
16
+ ];
17
+ static flags = {
18
+ ...BaseCommand.baseFlags,
19
+ branch: Flags.string({
20
+ char: 'b',
21
+ description: 'Filter by branch name',
22
+ required: false,
23
+ }),
24
+ output: Flags.string({
25
+ char: 'o',
26
+ default: 'summary',
27
+ description: 'Output format',
28
+ options: ['summary', 'json'],
29
+ required: false,
30
+ }),
31
+ tenant: Flags.string({
32
+ char: 't',
33
+ description: 'Tenant name',
34
+ required: true,
35
+ }),
36
+ workspace: Flags.string({
37
+ char: 'w',
38
+ description: 'Workspace ID (uses profile workspace if not provided)',
39
+ required: false,
40
+ }),
41
+ };
42
+ async run() {
43
+ const { flags } = await this.parse(TenantWorkflowTestRunAll);
44
+ const profileName = flags.profile || this.getDefaultProfile();
45
+ const credentials = this.loadCredentialsFile();
46
+ if (!credentials || !(profileName in credentials.profiles)) {
47
+ this.error(`Profile '${profileName}' not found.\nCreate a profile using 'xano profile create'`);
48
+ }
49
+ const profile = credentials.profiles[profileName];
50
+ if (!profile.instance_origin) {
51
+ this.error(`Profile '${profileName}' is missing instance_origin`);
52
+ }
53
+ if (!profile.access_token) {
54
+ this.error(`Profile '${profileName}' is missing access_token`);
55
+ }
56
+ const workspaceId = flags.workspace || profile.workspace;
57
+ if (!workspaceId) {
58
+ this.error('No workspace ID provided. Use --workspace flag or set one in your profile.');
59
+ }
60
+ const tenantName = encodeURIComponent(flags.tenant);
61
+ const baseUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/tenant/${tenantName}/workflow_test`;
62
+ try {
63
+ const listParams = new URLSearchParams();
64
+ listParams.set('per_page', '10000');
65
+ if (flags.branch)
66
+ listParams.set('branch', flags.branch);
67
+ const listResponse = await this.verboseFetch(`${baseUrl}?${listParams}`, {
68
+ headers: {
69
+ accept: 'application/json',
70
+ Authorization: `Bearer ${profile.access_token}`,
71
+ },
72
+ method: 'GET',
73
+ }, flags.verbose, profile.access_token);
74
+ if (!listResponse.ok) {
75
+ const errorText = await listResponse.text();
76
+ this.error(`Failed to list workflow tests: ${listResponse.status}: ${listResponse.statusText}\n${errorText}`);
77
+ }
78
+ const data = (await listResponse.json());
79
+ let tests;
80
+ if (Array.isArray(data)) {
81
+ tests = data;
82
+ }
83
+ else if (data && typeof data === 'object' && 'items' in data && Array.isArray(data.items)) {
84
+ tests = data.items;
85
+ }
86
+ else {
87
+ this.error('Unexpected API response format');
88
+ }
89
+ if (tests.length === 0) {
90
+ this.log('No workflow tests found');
91
+ return;
92
+ }
93
+ if (flags.output === 'summary') {
94
+ this.log(`Running ${tests.length} workflow test${tests.length === 1 ? '' : 's'}...\n`);
95
+ }
96
+ const results = [];
97
+ for (const test of tests) {
98
+ const runUrl = `${baseUrl}/${test.id}/run`;
99
+ try {
100
+ const runResponse = await this.verboseFetch(runUrl, {
101
+ headers: {
102
+ accept: 'application/json',
103
+ Authorization: `Bearer ${profile.access_token}`,
104
+ 'Content-Type': 'application/json',
105
+ },
106
+ method: 'POST',
107
+ }, flags.verbose, profile.access_token);
108
+ if (!runResponse.ok) {
109
+ const errorText = await runResponse.text();
110
+ results.push({
111
+ message: `API error ${runResponse.status}: ${errorText}`,
112
+ name: test.name,
113
+ status: 'fail',
114
+ });
115
+ if (flags.output === 'summary') {
116
+ this.log(`FAIL ${test.name}`);
117
+ this.log(` Error: API error ${runResponse.status}`);
118
+ }
119
+ continue;
120
+ }
121
+ const runResult = (await runResponse.json());
122
+ const passed = runResult.status === 'ok';
123
+ results.push({
124
+ message: runResult.message,
125
+ name: test.name,
126
+ status: passed ? 'pass' : 'fail',
127
+ timing: runResult.timing,
128
+ });
129
+ if (flags.output === 'summary') {
130
+ const timing = runResult.timing ? ` (${runResult.timing}s)` : '';
131
+ if (passed) {
132
+ this.log(`PASS ${test.name}${timing}`);
133
+ }
134
+ else {
135
+ this.log(`FAIL ${test.name}${timing}`);
136
+ if (runResult.message) {
137
+ this.log(` Error: ${runResult.message}`);
138
+ }
139
+ }
140
+ }
141
+ }
142
+ catch (error) {
143
+ const message = error instanceof Error ? error.message : String(error);
144
+ results.push({
145
+ message,
146
+ name: test.name,
147
+ status: 'fail',
148
+ });
149
+ if (flags.output === 'summary') {
150
+ this.log(`FAIL ${test.name}`);
151
+ this.log(` Error: ${message}`);
152
+ }
153
+ }
154
+ }
155
+ const passed = results.filter((r) => r.status === 'pass').length;
156
+ const failed = results.filter((r) => r.status === 'fail').length;
157
+ if (flags.output === 'json') {
158
+ this.log(JSON.stringify({ failed, passed, results }, null, 2));
159
+ }
160
+ else {
161
+ this.log(`\nResults: ${passed} passed, ${failed} failed`);
162
+ }
163
+ if (failed > 0) {
164
+ process.exitCode = 1;
165
+ }
166
+ }
167
+ catch (error) {
168
+ if (error instanceof Error) {
169
+ this.error(`Failed to run workflow tests: ${error.message}`);
170
+ }
171
+ else {
172
+ this.error(`Failed to run workflow tests: ${String(error)}`);
173
+ }
174
+ }
175
+ }
176
+ }
@@ -7,6 +7,7 @@ export default class UnitTestList extends BaseCommand {
7
7
  'obj-type': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
8
  output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
9
  workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
11
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
12
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
13
  };
@@ -1,8 +1,6 @@
1
1
  import { Flags } from '@oclif/core';
2
2
  import * as yaml from 'js-yaml';
3
3
  import * as fs from 'node:fs';
4
- import * as os from 'node:os';
5
- import * as path from 'node:path';
6
4
  import BaseCommand from '../../../base-command.js';
7
5
  export default class UnitTestList extends BaseCommand {
8
6
  static description = 'List all unit tests in a workspace';
@@ -116,8 +114,7 @@ Unit tests in workspace 5:
116
114
  }
117
115
  }
118
116
  loadCredentials() {
119
- const configDir = path.join(os.homedir(), '.xano');
120
- const credentialsPath = path.join(configDir, 'credentials.yaml');
117
+ const credentialsPath = this.getCredentialsPath();
121
118
  if (!fs.existsSync(credentialsPath)) {
122
119
  this.error(`Credentials file not found at ${credentialsPath}\n` +
123
120
  `Create a profile using 'xano profile create'`);
@@ -8,6 +8,7 @@ export default class UnitTestRun extends BaseCommand {
8
8
  static flags: {
9
9
  output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
10
  workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
12
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
13
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
14
  };