@xano/cli 1.0.2-beta.5 → 1.0.2-beta.6
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/README.md +87 -0
- package/dist/base-command.d.ts +21 -1
- package/dist/base-command.js +92 -6
- package/dist/commands/branch/create/index.d.ts +0 -1
- package/dist/commands/branch/create/index.js +1 -38
- package/dist/commands/branch/delete/index.d.ts +0 -1
- package/dist/commands/branch/delete/index.js +1 -39
- package/dist/commands/branch/edit/index.d.ts +0 -1
- package/dist/commands/branch/edit/index.js +1 -39
- package/dist/commands/branch/get/index.d.ts +0 -1
- package/dist/commands/branch/get/index.js +1 -39
- package/dist/commands/branch/list/index.d.ts +0 -1
- package/dist/commands/branch/list/index.js +1 -39
- package/dist/commands/branch/set_live/index.d.ts +0 -1
- package/dist/commands/branch/set_live/index.js +1 -39
- package/dist/commands/function/create/index.d.ts +0 -1
- package/dist/commands/function/create/index.js +1 -38
- package/dist/commands/function/edit/index.d.ts +0 -1
- package/dist/commands/function/edit/index.js +1 -37
- package/dist/commands/function/get/index.d.ts +0 -1
- package/dist/commands/function/get/index.js +1 -38
- package/dist/commands/function/list/index.d.ts +0 -1
- package/dist/commands/function/list/index.js +1 -39
- package/dist/commands/platform/get/index.d.ts +0 -1
- package/dist/commands/platform/get/index.js +1 -33
- package/dist/commands/platform/list/index.d.ts +0 -1
- package/dist/commands/platform/list/index.js +1 -33
- package/dist/commands/profile/use/index.d.ts +33 -0
- package/dist/commands/profile/use/index.js +179 -0
- package/dist/commands/release/create/index.d.ts +0 -1
- package/dist/commands/release/create/index.js +1 -33
- package/dist/commands/release/delete/index.d.ts +0 -1
- package/dist/commands/release/delete/index.js +1 -33
- package/dist/commands/release/deploy/index.js +1 -12
- package/dist/commands/release/edit/index.d.ts +0 -1
- package/dist/commands/release/edit/index.js +1 -33
- package/dist/commands/release/export/index.d.ts +0 -1
- package/dist/commands/release/export/index.js +1 -31
- package/dist/commands/release/get/index.d.ts +0 -1
- package/dist/commands/release/get/index.js +1 -33
- package/dist/commands/release/import/index.d.ts +0 -1
- package/dist/commands/release/import/index.js +1 -32
- package/dist/commands/release/list/index.d.ts +0 -1
- package/dist/commands/release/list/index.js +1 -32
- package/dist/commands/release/pull/index.d.ts +0 -1
- package/dist/commands/release/pull/index.js +2 -38
- package/dist/commands/release/push/index.d.ts +0 -1
- package/dist/commands/release/push/index.js +1 -37
- package/dist/commands/static_host/build/create/index.d.ts +0 -1
- package/dist/commands/static_host/build/create/index.js +1 -39
- package/dist/commands/static_host/build/get/index.d.ts +0 -1
- package/dist/commands/static_host/build/get/index.js +1 -39
- package/dist/commands/static_host/build/list/index.d.ts +0 -1
- package/dist/commands/static_host/build/list/index.js +1 -39
- package/dist/commands/static_host/list/index.d.ts +0 -1
- package/dist/commands/static_host/list/index.js +1 -39
- package/dist/commands/tenant/backup/create/index.d.ts +0 -1
- package/dist/commands/tenant/backup/create/index.js +1 -33
- package/dist/commands/tenant/backup/delete/index.d.ts +0 -1
- package/dist/commands/tenant/backup/delete/index.js +1 -32
- package/dist/commands/tenant/backup/export/index.d.ts +0 -1
- package/dist/commands/tenant/backup/export/index.js +1 -31
- package/dist/commands/tenant/backup/import/index.d.ts +0 -1
- package/dist/commands/tenant/backup/import/index.js +1 -32
- package/dist/commands/tenant/backup/list/index.d.ts +0 -1
- package/dist/commands/tenant/backup/list/index.js +1 -33
- package/dist/commands/tenant/backup/restore/index.d.ts +0 -1
- package/dist/commands/tenant/backup/restore/index.js +1 -32
- package/dist/commands/tenant/cluster/create/index.d.ts +0 -1
- package/dist/commands/tenant/cluster/create/index.js +1 -31
- package/dist/commands/tenant/cluster/delete/index.d.ts +0 -1
- package/dist/commands/tenant/cluster/delete/index.js +1 -33
- package/dist/commands/tenant/cluster/edit/index.d.ts +0 -1
- package/dist/commands/tenant/cluster/edit/index.js +1 -33
- package/dist/commands/tenant/cluster/get/index.d.ts +0 -1
- package/dist/commands/tenant/cluster/get/index.js +1 -32
- package/dist/commands/tenant/cluster/license/get/index.d.ts +0 -1
- package/dist/commands/tenant/cluster/license/get/index.js +1 -31
- package/dist/commands/tenant/cluster/license/set/index.d.ts +0 -1
- package/dist/commands/tenant/cluster/license/set/index.js +1 -31
- package/dist/commands/tenant/cluster/list/index.d.ts +0 -1
- package/dist/commands/tenant/cluster/list/index.js +1 -32
- package/dist/commands/tenant/create/index.d.ts +0 -1
- package/dist/commands/tenant/create/index.js +1 -30
- package/dist/commands/tenant/delete/index.d.ts +0 -1
- package/dist/commands/tenant/delete/index.js +1 -33
- package/dist/commands/tenant/deploy_platform/index.d.ts +0 -1
- package/dist/commands/tenant/deploy_platform/index.js +1 -31
- package/dist/commands/tenant/deploy_release/index.d.ts +0 -1
- package/dist/commands/tenant/deploy_release/index.js +1 -32
- package/dist/commands/tenant/edit/index.d.ts +0 -1
- package/dist/commands/tenant/edit/index.js +1 -33
- package/dist/commands/tenant/env/delete/index.d.ts +0 -1
- package/dist/commands/tenant/env/delete/index.js +1 -32
- package/dist/commands/tenant/env/get/index.d.ts +0 -1
- package/dist/commands/tenant/env/get/index.js +1 -32
- package/dist/commands/tenant/env/get_all/index.d.ts +0 -1
- package/dist/commands/tenant/env/get_all/index.js +1 -30
- package/dist/commands/tenant/env/list/index.d.ts +0 -1
- package/dist/commands/tenant/env/list/index.js +1 -32
- package/dist/commands/tenant/env/set/index.d.ts +0 -1
- package/dist/commands/tenant/env/set/index.js +1 -32
- package/dist/commands/tenant/env/set_all/index.d.ts +0 -1
- package/dist/commands/tenant/env/set_all/index.js +1 -30
- package/dist/commands/tenant/get/index.d.ts +0 -1
- package/dist/commands/tenant/get/index.js +1 -32
- package/dist/commands/tenant/impersonate/index.d.ts +0 -1
- package/dist/commands/tenant/impersonate/index.js +1 -32
- package/dist/commands/tenant/license/get/index.d.ts +0 -1
- package/dist/commands/tenant/license/get/index.js +1 -31
- package/dist/commands/tenant/license/set/index.d.ts +0 -1
- package/dist/commands/tenant/license/set/index.js +1 -31
- package/dist/commands/tenant/list/index.d.ts +0 -1
- package/dist/commands/tenant/list/index.js +1 -32
- package/dist/commands/tenant/pull/index.d.ts +0 -1
- package/dist/commands/tenant/pull/index.js +1 -37
- package/dist/commands/tenant/unit_test/list/index.js +1 -12
- package/dist/commands/tenant/unit_test/run/index.js +1 -12
- package/dist/commands/tenant/unit_test/run_all/index.js +1 -12
- package/dist/commands/tenant/workflow_test/list/index.js +1 -12
- package/dist/commands/tenant/workflow_test/run/index.js +1 -12
- package/dist/commands/tenant/workflow_test/run_all/index.js +1 -12
- package/dist/commands/unit_test/list/index.d.ts +0 -1
- package/dist/commands/unit_test/list/index.js +1 -33
- package/dist/commands/unit_test/run/index.d.ts +0 -1
- package/dist/commands/unit_test/run/index.js +1 -33
- package/dist/commands/unit_test/run_all/index.d.ts +0 -1
- package/dist/commands/unit_test/run_all/index.js +1 -32
- package/dist/commands/workflow_test/delete/index.d.ts +0 -1
- package/dist/commands/workflow_test/delete/index.js +1 -33
- package/dist/commands/workflow_test/get/index.d.ts +0 -1
- package/dist/commands/workflow_test/get/index.js +1 -33
- package/dist/commands/workflow_test/list/index.d.ts +0 -1
- package/dist/commands/workflow_test/list/index.js +1 -33
- package/dist/commands/workflow_test/run/index.d.ts +0 -1
- package/dist/commands/workflow_test/run/index.js +1 -33
- package/dist/commands/workflow_test/run_all/index.d.ts +0 -1
- package/dist/commands/workflow_test/run_all/index.js +1 -32
- package/dist/commands/workspace/create/index.d.ts +0 -1
- package/dist/commands/workspace/create/index.js +1 -39
- package/dist/commands/workspace/delete/index.d.ts +0 -1
- package/dist/commands/workspace/delete/index.js +1 -39
- package/dist/commands/workspace/edit/index.d.ts +0 -1
- package/dist/commands/workspace/edit/index.js +1 -38
- package/dist/commands/workspace/get/index.d.ts +0 -1
- package/dist/commands/workspace/get/index.js +1 -38
- package/dist/commands/workspace/list/index.d.ts +0 -1
- package/dist/commands/workspace/list/index.js +1 -38
- package/dist/commands/workspace/pull/index.d.ts +0 -1
- package/dist/commands/workspace/pull/index.js +1 -37
- package/dist/utils/local-config.d.ts +43 -0
- package/dist/utils/local-config.js +88 -0
- package/oclif.manifest.json +2399 -2312
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -52,6 +52,11 @@ xano auth --insecure # Skip TLS verification (self-signe
|
|
|
52
52
|
|
|
53
53
|
Profiles store your Xano credentials and default workspace settings.
|
|
54
54
|
|
|
55
|
+
> **Juggling multiple workspaces?** Pin a project to a specific profile with a
|
|
56
|
+
> project-local `profile.yaml` so commands can't accidentally target the wrong
|
|
57
|
+
> workspace when you forget `-p`. See
|
|
58
|
+
> [Project-local profile](#project-local-profile-profileyaml).
|
|
59
|
+
|
|
55
60
|
```bash
|
|
56
61
|
# Create a profile interactively
|
|
57
62
|
xano profile wizard
|
|
@@ -89,6 +94,11 @@ xano profile workspace
|
|
|
89
94
|
xano profile workspace set
|
|
90
95
|
xano profile workspace set -p production
|
|
91
96
|
|
|
97
|
+
# Pin a profile for the current project (writes ./profile.yaml)
|
|
98
|
+
xano profile use staging
|
|
99
|
+
xano profile use staging -w 110 # pin and override the workspace
|
|
100
|
+
xano profile use staging --gitignore # also add profile.yaml to .gitignore
|
|
101
|
+
|
|
92
102
|
# Delete a profile
|
|
93
103
|
xano profile delete myprofile
|
|
94
104
|
xano profile delete myprofile --force
|
|
@@ -575,6 +585,83 @@ profiles:
|
|
|
575
585
|
default: default
|
|
576
586
|
```
|
|
577
587
|
|
|
588
|
+
### Project-local profile (`profile.yaml`)
|
|
589
|
+
|
|
590
|
+
To avoid accidentally targeting the wrong workspace, pin a project to a profile
|
|
591
|
+
by adding a `profile.yaml` file at the project root. The CLI searches the
|
|
592
|
+
current directory and walks up parent directories (like `.git`) to find it.
|
|
593
|
+
|
|
594
|
+
`profile.yaml` contains **no secrets** — it references a profile by name; the
|
|
595
|
+
access token always comes from `~/.xano/credentials.yaml`. An `access_token`
|
|
596
|
+
key is rejected.
|
|
597
|
+
|
|
598
|
+
```yaml
|
|
599
|
+
# ./profile.yaml
|
|
600
|
+
profile: staging # which credentials.yaml profile to use
|
|
601
|
+
workspace: 110 # optional override
|
|
602
|
+
instance_origin: https://your-instance.xano.io # optional override
|
|
603
|
+
account_origin: https://app.xano.com # optional override
|
|
604
|
+
branch: main # optional override
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
When a `profile.yaml` is in effect, every command prints the active target,
|
|
608
|
+
e.g. `Using profile 'staging' (workspace 110) · profile.yaml` (suppressed for
|
|
609
|
+
`--output json`).
|
|
610
|
+
|
|
611
|
+
Generate one with `xano profile use`. It writes a self-documenting
|
|
612
|
+
`profile.yaml` (every overridable field is included as a commented example, so
|
|
613
|
+
you can edit it without consulting the docs) and offers to add it to
|
|
614
|
+
`.gitignore` — skipping that prompt when it is already ignored:
|
|
615
|
+
|
|
616
|
+
```bash
|
|
617
|
+
xano profile use staging -w 110 # writes ./profile.yaml; prompts to .gitignore
|
|
618
|
+
xano profile use staging --no-gitignore
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
The generated file looks like:
|
|
622
|
+
|
|
623
|
+
```yaml
|
|
624
|
+
# Xano project-local profile — pins this project to a profile in ~/.xano/credentials.yaml.
|
|
625
|
+
# No secrets here: the access token always comes from credentials.yaml.
|
|
626
|
+
# Precedence: an explicit -p/--profile or XANO_PROFILE overrides this file entirely.
|
|
627
|
+
|
|
628
|
+
# Profile to use (a profile name from ~/.xano/credentials.yaml):
|
|
629
|
+
profile: staging
|
|
630
|
+
|
|
631
|
+
# Optional per-project overrides — uncomment and edit any you need:
|
|
632
|
+
workspace: 110
|
|
633
|
+
# instance_origin: https://your-instance.xano.io
|
|
634
|
+
# account_origin: https://app.xano.com
|
|
635
|
+
# branch: main
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
**Profile selection precedence:**
|
|
639
|
+
|
|
640
|
+
1. `-p/--profile` flag
|
|
641
|
+
2. `XANO_PROFILE` environment variable
|
|
642
|
+
3. `profile.yaml` (`profile:` field, plus field overrides)
|
|
643
|
+
4. Default profile from the credentials file
|
|
644
|
+
|
|
645
|
+
An explicit `-p/--profile` or `XANO_PROFILE` ignores `profile.yaml` entirely.
|
|
646
|
+
|
|
647
|
+
#### `xano profile use <name>`
|
|
648
|
+
|
|
649
|
+
Pin a profile for the current project by writing a local `profile.yaml`.
|
|
650
|
+
|
|
651
|
+
```bash
|
|
652
|
+
xano profile use staging # pin profile 'staging' for this project
|
|
653
|
+
xano profile use staging -w 110 # pin and override the workspace
|
|
654
|
+
xano profile use staging --gitignore # also add profile.yaml to .gitignore
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
| Flag | Description |
|
|
658
|
+
|------|-------------|
|
|
659
|
+
| `-w, --workspace` | Override workspace for this project |
|
|
660
|
+
| `-b, --branch` | Override branch for this project |
|
|
661
|
+
| `-i, --instance_origin` | Override instance origin |
|
|
662
|
+
| `-a, --account_origin` | Override account origin |
|
|
663
|
+
| `--gitignore` / `--no-gitignore` | Add (or skip adding) `profile.yaml` to `.gitignore` without prompting |
|
|
664
|
+
|
|
578
665
|
### Self-Signed Certificates
|
|
579
666
|
|
|
580
667
|
For environments using self-signed TLS certificates, use the `--insecure` (`-k`) flag to skip certificate verification:
|
package/dist/base-command.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
|
+
import { type LocalProfileConfig } from './utils/local-config.js';
|
|
2
3
|
export interface ProfileConfig {
|
|
3
4
|
access_token: string;
|
|
4
5
|
account_origin?: string;
|
|
@@ -30,6 +31,12 @@ export interface SandboxTenant {
|
|
|
30
31
|
* Checks (in order): explicit configPath arg, XANO_CONFIG env var, ~/.xano/credentials.yaml
|
|
31
32
|
*/
|
|
32
33
|
export declare function resolveCredentialsPath(configPath?: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* Detect whether an explicit profile was requested via -p/--profile or the
|
|
36
|
+
* XANO_PROFILE env var. Used at init() time, before flags are parsed, to decide
|
|
37
|
+
* whether the project-local profile.yaml should be ignored (explicit wins).
|
|
38
|
+
*/
|
|
39
|
+
export declare function argvHasProfileFlag(argv: string[], env: NodeJS.ProcessEnv): boolean;
|
|
33
40
|
export default abstract class BaseCommand extends Command {
|
|
34
41
|
static baseFlags: {
|
|
35
42
|
config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -41,8 +48,19 @@ export default abstract class BaseCommand extends Command {
|
|
|
41
48
|
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
42
49
|
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
43
50
|
};
|
|
51
|
+
protected localProfile: null | {
|
|
52
|
+
config: LocalProfileConfig;
|
|
53
|
+
path: string;
|
|
54
|
+
};
|
|
44
55
|
protected updateNotice: string | null;
|
|
45
56
|
init(): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Find and parse the nearest project-local profile.yaml, unless an explicit
|
|
59
|
+
* -p/XANO_PROFILE was given (in which case the local file is ignored).
|
|
60
|
+
*/
|
|
61
|
+
private loadLocalProfile;
|
|
62
|
+
/** Print the one-line target banner when a local profile.yaml is in effect. */
|
|
63
|
+
private maybePrintLocalProfileBanner;
|
|
46
64
|
finally(_: Error | undefined): Promise<void>;
|
|
47
65
|
private isJsonOutput;
|
|
48
66
|
/**
|
|
@@ -65,7 +83,9 @@ export default abstract class BaseCommand extends Command {
|
|
|
65
83
|
*/
|
|
66
84
|
protected getOrCreateSandbox(profile: ProfileConfig, verbose: boolean): Promise<SandboxTenant>;
|
|
67
85
|
/**
|
|
68
|
-
* Resolve profile from flags
|
|
86
|
+
* Resolve the profile from flags and any project-local profile.yaml,
|
|
87
|
+
* validating instance_origin and access_token exist.
|
|
88
|
+
* Precedence: -p/XANO_PROFILE > profile.yaml > credentials default.
|
|
69
89
|
*/
|
|
70
90
|
protected resolveProfile(flags: {
|
|
71
91
|
profile?: string;
|
package/dist/base-command.js
CHANGED
|
@@ -4,6 +4,7 @@ import * as fs from 'node:fs';
|
|
|
4
4
|
import * as os from 'node:os';
|
|
5
5
|
import * as path from 'node:path';
|
|
6
6
|
import { checkForUpdate } from './update-check.js';
|
|
7
|
+
import { applyLocalOverrides, findLocalProfilePath, formatLocalProfileBanner, parseLocalProfile, resolveProfileSelection, } from './utils/local-config.js';
|
|
7
8
|
export function buildUserAgent(version) {
|
|
8
9
|
return `xano-cli/${version} (${process.platform}; ${process.arch}) node/${process.version}`;
|
|
9
10
|
}
|
|
@@ -18,6 +19,27 @@ export function resolveCredentialsPath(configPath) {
|
|
|
18
19
|
}
|
|
19
20
|
return path.join(os.homedir(), '.xano', 'credentials.yaml');
|
|
20
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Detect whether an explicit profile was requested via -p/--profile or the
|
|
24
|
+
* XANO_PROFILE env var. Used at init() time, before flags are parsed, to decide
|
|
25
|
+
* whether the project-local profile.yaml should be ignored (explicit wins).
|
|
26
|
+
*/
|
|
27
|
+
export function argvHasProfileFlag(argv, env) {
|
|
28
|
+
// XANO_PROFILE is checked directly (not via oclif's flag env binding) because
|
|
29
|
+
// this runs in init(), before flags are parsed and available on the command.
|
|
30
|
+
if (env.XANO_PROFILE) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
// Scan the raw argv so we catch any token form the user might type
|
|
34
|
+
// (`-p prod`, `--profile prod`, `--profile=prod`, `-p=prod`) regardless of
|
|
35
|
+
// how oclif ultimately parses it.
|
|
36
|
+
for (const arg of argv) {
|
|
37
|
+
if (arg === '-p' || arg === '--profile' || arg.startsWith('--profile=') || arg.startsWith('-p=')) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
21
43
|
export default class BaseCommand extends Command {
|
|
22
44
|
static baseFlags = {
|
|
23
45
|
config: Flags.string({
|
|
@@ -42,13 +64,62 @@ export default class BaseCommand extends Command {
|
|
|
42
64
|
};
|
|
43
65
|
// Override the flags property to include baseFlags
|
|
44
66
|
static flags = BaseCommand.baseFlags;
|
|
67
|
+
// Resolved project-local profile.yaml, set once in init() before run().
|
|
68
|
+
// Null when none was found or when an explicit -p/XANO_PROFILE overrides it.
|
|
69
|
+
localProfile = null;
|
|
45
70
|
updateNotice = null;
|
|
46
71
|
async init() {
|
|
47
72
|
await super.init();
|
|
73
|
+
this.localProfile = this.loadLocalProfile();
|
|
48
74
|
this.applyInsecureFromProfile();
|
|
75
|
+
this.maybePrintLocalProfileBanner();
|
|
49
76
|
const forceUpdateCheck = process.env.XANO_FORCE_UPDATE_CHECK === '1';
|
|
50
77
|
this.updateNotice = checkForUpdate(this.config.version, forceUpdateCheck);
|
|
51
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Find and parse the nearest project-local profile.yaml, unless an explicit
|
|
81
|
+
* -p/XANO_PROFILE was given (in which case the local file is ignored).
|
|
82
|
+
*/
|
|
83
|
+
loadLocalProfile() {
|
|
84
|
+
if (argvHasProfileFlag(process.argv, process.env)) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
// Walks up to the filesystem root (git-style). parseLocalProfile returns
|
|
88
|
+
// null for a profile.yaml with no recognized keys, so an unrelated file
|
|
89
|
+
// belonging to another tool is ignored rather than hijacked.
|
|
90
|
+
const filePath = findLocalProfilePath(process.cwd());
|
|
91
|
+
if (!filePath) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
let config;
|
|
95
|
+
try {
|
|
96
|
+
config = parseLocalProfile(fs.readFileSync(filePath, 'utf8'));
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
this.error(`${filePath}: ${error.message}`);
|
|
100
|
+
}
|
|
101
|
+
if (!config) {
|
|
102
|
+
this.warn(`Ignoring ${filePath}: no recognized profile keys found.`);
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
return { config, path: filePath };
|
|
106
|
+
}
|
|
107
|
+
/** Print the one-line target banner when a local profile.yaml is in effect. */
|
|
108
|
+
maybePrintLocalProfileBanner() {
|
|
109
|
+
if (!this.localProfile || this.isJsonOutput()) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
// Credential-management commands (the `profile` topic) operate on the
|
|
113
|
+
// credentials store directly and intentionally ignore the project-local
|
|
114
|
+
// pin, so the banner would be misleading for them.
|
|
115
|
+
if (this.id?.startsWith('profile')) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const { config, path: filePath } = this.localProfile;
|
|
119
|
+
const profileName = config.profile ?? this.getDefaultProfile();
|
|
120
|
+
const relativePath = path.relative(process.cwd(), filePath) || path.basename(filePath);
|
|
121
|
+
this.log(formatLocalProfileBanner(profileName, config.workspace, relativePath));
|
|
122
|
+
}
|
|
52
123
|
async finally(_) {
|
|
53
124
|
if (this.updateNotice && !this.isJsonOutput()) {
|
|
54
125
|
this.log(this.updateNotice);
|
|
@@ -73,7 +144,7 @@ export default class BaseCommand extends Command {
|
|
|
73
144
|
*/
|
|
74
145
|
applyInsecureFromProfile() {
|
|
75
146
|
try {
|
|
76
|
-
const profileName = this.flags?.profile || this.getDefaultProfile();
|
|
147
|
+
const profileName = this.flags?.profile || this.localProfile?.config.profile || this.getDefaultProfile();
|
|
77
148
|
const credentials = this.loadCredentialsFile();
|
|
78
149
|
if (!credentials)
|
|
79
150
|
return;
|
|
@@ -151,15 +222,30 @@ export default class BaseCommand extends Command {
|
|
|
151
222
|
return (await response.json());
|
|
152
223
|
}
|
|
153
224
|
/**
|
|
154
|
-
* Resolve profile from flags
|
|
225
|
+
* Resolve the profile from flags and any project-local profile.yaml,
|
|
226
|
+
* validating instance_origin and access_token exist.
|
|
227
|
+
* Precedence: -p/XANO_PROFILE > profile.yaml > credentials default.
|
|
155
228
|
*/
|
|
156
229
|
resolveProfile(flags) {
|
|
157
|
-
const profileName = flags.profile || this.getDefaultProfile();
|
|
158
230
|
const credentials = this.loadCredentialsFile();
|
|
159
|
-
|
|
160
|
-
this.
|
|
231
|
+
const { applyLocal, profileName } = resolveProfileSelection({
|
|
232
|
+
defaultProfile: this.getDefaultProfile(),
|
|
233
|
+
explicitProfile: flags.profile,
|
|
234
|
+
hasLocal: Boolean(this.localProfile),
|
|
235
|
+
localProfileName: this.localProfile?.config.profile,
|
|
236
|
+
});
|
|
237
|
+
if (!credentials) {
|
|
238
|
+
this.error(`Credentials file not found at ${this.getCredentialsPath()}.\n` +
|
|
239
|
+
`Create a profile using 'xano profile create'`);
|
|
240
|
+
}
|
|
241
|
+
if (!(profileName in credentials.profiles)) {
|
|
242
|
+
const available = Object.keys(credentials.profiles).join(', ') || '(none)';
|
|
243
|
+
this.error(`Profile '${profileName}' not found. Available profiles: ${available}`);
|
|
244
|
+
}
|
|
245
|
+
let profile = credentials.profiles[profileName];
|
|
246
|
+
if (applyLocal && this.localProfile) {
|
|
247
|
+
profile = applyLocalOverrides(profile, this.localProfile.config);
|
|
161
248
|
}
|
|
162
|
-
const profile = credentials.profiles[profileName];
|
|
163
249
|
if (!profile.instance_origin) {
|
|
164
250
|
this.error(`Profile '${profileName}' is missing instance_origin`);
|
|
165
251
|
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { Args, Flags } from '@oclif/core';
|
|
2
|
-
import * as yaml from 'js-yaml';
|
|
3
|
-
import * as fs from 'node:fs';
|
|
4
2
|
import BaseCommand from '../../../base-command.js';
|
|
5
3
|
export default class BranchCreate extends BaseCommand {
|
|
6
4
|
static description = 'Create a new branch by cloning from an existing branch';
|
|
@@ -62,23 +60,7 @@ Created branch: feature-auth
|
|
|
62
60
|
};
|
|
63
61
|
async run() {
|
|
64
62
|
const { args, flags } = await this.parse(BranchCreate);
|
|
65
|
-
|
|
66
|
-
const profileName = flags.profile || this.getDefaultProfile();
|
|
67
|
-
// Load credentials
|
|
68
|
-
const credentials = this.loadCredentials();
|
|
69
|
-
// Get the profile configuration
|
|
70
|
-
if (!(profileName in credentials.profiles)) {
|
|
71
|
-
this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
|
|
72
|
-
`Create a profile using 'xano profile create'`);
|
|
73
|
-
}
|
|
74
|
-
const profile = credentials.profiles[profileName];
|
|
75
|
-
// Validate required fields
|
|
76
|
-
if (!profile.instance_origin) {
|
|
77
|
-
this.error(`Profile '${profileName}' is missing instance_origin`);
|
|
78
|
-
}
|
|
79
|
-
if (!profile.access_token) {
|
|
80
|
-
this.error(`Profile '${profileName}' is missing access_token`);
|
|
81
|
-
}
|
|
63
|
+
const { profile } = this.resolveProfile(flags);
|
|
82
64
|
// Get workspace ID from flag or profile
|
|
83
65
|
const workspaceId = flags.workspace || profile.workspace;
|
|
84
66
|
if (!workspaceId) {
|
|
@@ -143,23 +125,4 @@ Created branch: feature-auth
|
|
|
143
125
|
}
|
|
144
126
|
}
|
|
145
127
|
}
|
|
146
|
-
loadCredentials() {
|
|
147
|
-
const credentialsPath = this.getCredentialsPath();
|
|
148
|
-
// Check if credentials file exists
|
|
149
|
-
if (!fs.existsSync(credentialsPath)) {
|
|
150
|
-
this.error(`Credentials file not found at ${credentialsPath}\n` + `Create a profile using 'xano profile create'`);
|
|
151
|
-
}
|
|
152
|
-
// Read credentials file
|
|
153
|
-
try {
|
|
154
|
-
const fileContent = fs.readFileSync(credentialsPath, 'utf8');
|
|
155
|
-
const parsed = yaml.load(fileContent);
|
|
156
|
-
if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
|
|
157
|
-
this.error('Credentials file has invalid format.');
|
|
158
|
-
}
|
|
159
|
-
return parsed;
|
|
160
|
-
}
|
|
161
|
-
catch (error) {
|
|
162
|
-
this.error(`Failed to parse credentials file: ${error}`);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
128
|
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { Args, Flags } from '@oclif/core';
|
|
2
|
-
import * as yaml from 'js-yaml';
|
|
3
|
-
import * as fs from 'node:fs';
|
|
4
2
|
import BaseCommand from '../../../base-command.js';
|
|
5
3
|
export default class BranchDelete extends BaseCommand {
|
|
6
4
|
static args = {
|
|
@@ -48,23 +46,7 @@ Deleted branch: dev
|
|
|
48
46
|
};
|
|
49
47
|
async run() {
|
|
50
48
|
const { args, flags } = await this.parse(BranchDelete);
|
|
51
|
-
|
|
52
|
-
const profileName = flags.profile || this.getDefaultProfile();
|
|
53
|
-
// Load credentials
|
|
54
|
-
const credentials = this.loadCredentials();
|
|
55
|
-
// Get the profile configuration
|
|
56
|
-
if (!(profileName in credentials.profiles)) {
|
|
57
|
-
this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
|
|
58
|
-
`Create a profile using 'xano profile create'`);
|
|
59
|
-
}
|
|
60
|
-
const profile = credentials.profiles[profileName];
|
|
61
|
-
// Validate required fields
|
|
62
|
-
if (!profile.instance_origin) {
|
|
63
|
-
this.error(`Profile '${profileName}' is missing instance_origin`);
|
|
64
|
-
}
|
|
65
|
-
if (!profile.access_token) {
|
|
66
|
-
this.error(`Profile '${profileName}' is missing access_token`);
|
|
67
|
-
}
|
|
49
|
+
const { profile } = this.resolveProfile(flags);
|
|
68
50
|
// Get workspace ID from flag or profile
|
|
69
51
|
const workspaceId = flags.workspace || profile.workspace;
|
|
70
52
|
if (!workspaceId) {
|
|
@@ -130,24 +112,4 @@ Deleted branch: dev
|
|
|
130
112
|
});
|
|
131
113
|
});
|
|
132
114
|
}
|
|
133
|
-
loadCredentials() {
|
|
134
|
-
const credentialsPath = this.getCredentialsPath();
|
|
135
|
-
// Check if credentials file exists
|
|
136
|
-
if (!fs.existsSync(credentialsPath)) {
|
|
137
|
-
this.error(`Credentials file not found at ${credentialsPath}\n` +
|
|
138
|
-
`Create a profile using 'xano profile create'`);
|
|
139
|
-
}
|
|
140
|
-
// Read credentials file
|
|
141
|
-
try {
|
|
142
|
-
const fileContent = fs.readFileSync(credentialsPath, 'utf8');
|
|
143
|
-
const parsed = yaml.load(fileContent);
|
|
144
|
-
if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
|
|
145
|
-
this.error('Credentials file has invalid format.');
|
|
146
|
-
}
|
|
147
|
-
return parsed;
|
|
148
|
-
}
|
|
149
|
-
catch (error) {
|
|
150
|
-
this.error(`Failed to parse credentials file: ${error}`);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
115
|
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { Args, Flags } from '@oclif/core';
|
|
2
|
-
import * as yaml from 'js-yaml';
|
|
3
|
-
import * as fs from 'node:fs';
|
|
4
2
|
import BaseCommand from '../../../base-command.js';
|
|
5
3
|
export default class BranchEdit extends BaseCommand {
|
|
6
4
|
static args = {
|
|
@@ -58,23 +56,7 @@ Updated branch: feature-authentication
|
|
|
58
56
|
};
|
|
59
57
|
async run() {
|
|
60
58
|
const { args, flags } = await this.parse(BranchEdit);
|
|
61
|
-
|
|
62
|
-
const profileName = flags.profile || this.getDefaultProfile();
|
|
63
|
-
// Load credentials
|
|
64
|
-
const credentials = this.loadCredentials();
|
|
65
|
-
// Get the profile configuration
|
|
66
|
-
if (!(profileName in credentials.profiles)) {
|
|
67
|
-
this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
|
|
68
|
-
`Create a profile using 'xano profile create'`);
|
|
69
|
-
}
|
|
70
|
-
const profile = credentials.profiles[profileName];
|
|
71
|
-
// Validate required fields
|
|
72
|
-
if (!profile.instance_origin) {
|
|
73
|
-
this.error(`Profile '${profileName}' is missing instance_origin`);
|
|
74
|
-
}
|
|
75
|
-
if (!profile.access_token) {
|
|
76
|
-
this.error(`Profile '${profileName}' is missing access_token`);
|
|
77
|
-
}
|
|
59
|
+
const { profile } = this.resolveProfile(flags);
|
|
78
60
|
// Get workspace ID from flag or profile
|
|
79
61
|
const workspaceId = flags.workspace || profile.workspace;
|
|
80
62
|
if (!workspaceId) {
|
|
@@ -140,24 +122,4 @@ Updated branch: feature-authentication
|
|
|
140
122
|
}
|
|
141
123
|
}
|
|
142
124
|
}
|
|
143
|
-
loadCredentials() {
|
|
144
|
-
const credentialsPath = this.getCredentialsPath();
|
|
145
|
-
// Check if credentials file exists
|
|
146
|
-
if (!fs.existsSync(credentialsPath)) {
|
|
147
|
-
this.error(`Credentials file not found at ${credentialsPath}\n` +
|
|
148
|
-
`Create a profile using 'xano profile create'`);
|
|
149
|
-
}
|
|
150
|
-
// Read credentials file
|
|
151
|
-
try {
|
|
152
|
-
const fileContent = fs.readFileSync(credentialsPath, 'utf8');
|
|
153
|
-
const parsed = yaml.load(fileContent);
|
|
154
|
-
if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
|
|
155
|
-
this.error('Credentials file has invalid format.');
|
|
156
|
-
}
|
|
157
|
-
return parsed;
|
|
158
|
-
}
|
|
159
|
-
catch (error) {
|
|
160
|
-
this.error(`Failed to parse credentials file: ${error}`);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
125
|
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { Args, Flags } from '@oclif/core';
|
|
2
|
-
import * as yaml from 'js-yaml';
|
|
3
|
-
import * as fs from 'node:fs';
|
|
4
2
|
import BaseCommand from '../../../base-command.js';
|
|
5
3
|
export default class BranchGet extends BaseCommand {
|
|
6
4
|
static args = {
|
|
@@ -45,23 +43,7 @@ Branch: dev
|
|
|
45
43
|
};
|
|
46
44
|
async run() {
|
|
47
45
|
const { args, flags } = await this.parse(BranchGet);
|
|
48
|
-
|
|
49
|
-
const profileName = flags.profile || this.getDefaultProfile();
|
|
50
|
-
// Load credentials
|
|
51
|
-
const credentials = this.loadCredentials();
|
|
52
|
-
// Get the profile configuration
|
|
53
|
-
if (!(profileName in credentials.profiles)) {
|
|
54
|
-
this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
|
|
55
|
-
`Create a profile using 'xano profile create'`);
|
|
56
|
-
}
|
|
57
|
-
const profile = credentials.profiles[profileName];
|
|
58
|
-
// Validate required fields
|
|
59
|
-
if (!profile.instance_origin) {
|
|
60
|
-
this.error(`Profile '${profileName}' is missing instance_origin`);
|
|
61
|
-
}
|
|
62
|
-
if (!profile.access_token) {
|
|
63
|
-
this.error(`Profile '${profileName}' is missing access_token`);
|
|
64
|
-
}
|
|
46
|
+
const { profile } = this.resolveProfile(flags);
|
|
65
47
|
// Get workspace ID from flag or profile
|
|
66
48
|
const workspaceId = flags.workspace || profile.workspace;
|
|
67
49
|
if (!workspaceId) {
|
|
@@ -109,24 +91,4 @@ Branch: dev
|
|
|
109
91
|
}
|
|
110
92
|
}
|
|
111
93
|
}
|
|
112
|
-
loadCredentials() {
|
|
113
|
-
const credentialsPath = this.getCredentialsPath();
|
|
114
|
-
// Check if credentials file exists
|
|
115
|
-
if (!fs.existsSync(credentialsPath)) {
|
|
116
|
-
this.error(`Credentials file not found at ${credentialsPath}\n` +
|
|
117
|
-
`Create a profile using 'xano profile create'`);
|
|
118
|
-
}
|
|
119
|
-
// Read credentials file
|
|
120
|
-
try {
|
|
121
|
-
const fileContent = fs.readFileSync(credentialsPath, 'utf8');
|
|
122
|
-
const parsed = yaml.load(fileContent);
|
|
123
|
-
if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
|
|
124
|
-
this.error('Credentials file has invalid format.');
|
|
125
|
-
}
|
|
126
|
-
return parsed;
|
|
127
|
-
}
|
|
128
|
-
catch (error) {
|
|
129
|
-
this.error(`Failed to parse credentials file: ${error}`);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
94
|
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
|
-
import * as yaml from 'js-yaml';
|
|
3
|
-
import * as fs from 'node:fs';
|
|
4
2
|
import BaseCommand from '../../../base-command.js';
|
|
5
3
|
export function filterBackups(branches, includeBackups) {
|
|
6
4
|
return includeBackups ? branches : branches.filter((b) => !b.backup);
|
|
@@ -58,23 +56,7 @@ Available branches:
|
|
|
58
56
|
};
|
|
59
57
|
async run() {
|
|
60
58
|
const { flags } = await this.parse(BranchList);
|
|
61
|
-
|
|
62
|
-
const profileName = flags.profile || this.getDefaultProfile();
|
|
63
|
-
// Load credentials
|
|
64
|
-
const credentials = this.loadCredentials();
|
|
65
|
-
// Get the profile configuration
|
|
66
|
-
if (!(profileName in credentials.profiles)) {
|
|
67
|
-
this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
|
|
68
|
-
`Create a profile using 'xano profile create'`);
|
|
69
|
-
}
|
|
70
|
-
const profile = credentials.profiles[profileName];
|
|
71
|
-
// Validate required fields
|
|
72
|
-
if (!profile.instance_origin) {
|
|
73
|
-
this.error(`Profile '${profileName}' is missing instance_origin`);
|
|
74
|
-
}
|
|
75
|
-
if (!profile.access_token) {
|
|
76
|
-
this.error(`Profile '${profileName}' is missing access_token`);
|
|
77
|
-
}
|
|
59
|
+
const { profile } = this.resolveProfile(flags);
|
|
78
60
|
// Get workspace ID from flag or profile
|
|
79
61
|
const workspaceId = flags.workspace || profile.workspace;
|
|
80
62
|
if (!workspaceId) {
|
|
@@ -126,24 +108,4 @@ Available branches:
|
|
|
126
108
|
}
|
|
127
109
|
}
|
|
128
110
|
}
|
|
129
|
-
loadCredentials() {
|
|
130
|
-
const credentialsPath = this.getCredentialsPath();
|
|
131
|
-
// Check if credentials file exists
|
|
132
|
-
if (!fs.existsSync(credentialsPath)) {
|
|
133
|
-
this.error(`Credentials file not found at ${credentialsPath}\n` +
|
|
134
|
-
`Create a profile using 'xano profile create'`);
|
|
135
|
-
}
|
|
136
|
-
// Read credentials file
|
|
137
|
-
try {
|
|
138
|
-
const fileContent = fs.readFileSync(credentialsPath, 'utf8');
|
|
139
|
-
const parsed = yaml.load(fileContent);
|
|
140
|
-
if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
|
|
141
|
-
this.error('Credentials file has invalid format.');
|
|
142
|
-
}
|
|
143
|
-
return parsed;
|
|
144
|
-
}
|
|
145
|
-
catch (error) {
|
|
146
|
-
this.error(`Failed to parse credentials file: ${error}`);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
111
|
}
|