fix: use .[][].name in jq for wrapped JSON response #31
@@ -46,7 +46,7 @@ _mcpctl() {
|
|||||||
# If completing the --project value
|
# If completing the --project value
|
||||||
if [[ "$prev" == "--project" ]]; then
|
if [[ "$prev" == "--project" ]]; then
|
||||||
local names
|
local names
|
||||||
names=$(mcpctl get projects -o json 2>/dev/null | jq -r '.[].name' 2>/dev/null)
|
names=$(mcpctl get projects -o json 2>/dev/null | jq -r '.[][].name' 2>/dev/null)
|
||||||
COMPREPLY=($(compgen -W "$names" -- "$cur"))
|
COMPREPLY=($(compgen -W "$names" -- "$cur"))
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
@@ -55,7 +55,7 @@ _mcpctl() {
|
|||||||
_mcpctl_resource_names() {
|
_mcpctl_resource_names() {
|
||||||
local rt="$1"
|
local rt="$1"
|
||||||
if [[ -n "$rt" ]]; then
|
if [[ -n "$rt" ]]; then
|
||||||
mcpctl get "$rt" -o json 2>/dev/null | jq -r '.[].name' 2>/dev/null
|
mcpctl get "$rt" -o json 2>/dev/null | jq -r '.[][].name' 2>/dev/null
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,12 +72,12 @@ function __mcpctl_resource_names
|
|||||||
if test -z "$resource"
|
if test -z "$resource"
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
mcpctl get $resource -o json 2>/dev/null | jq -r '.[].name' 2>/dev/null
|
mcpctl get $resource -o json 2>/dev/null | jq -r '.[][].name' 2>/dev/null
|
||||||
end
|
end
|
||||||
|
|
||||||
# Fetch project names for --project value
|
# Fetch project names for --project value
|
||||||
function __mcpctl_project_names
|
function __mcpctl_project_names
|
||||||
mcpctl get projects -o json 2>/dev/null | jq -r '.[].name' 2>/dev/null
|
mcpctl get projects -o json 2>/dev/null | jq -r '.[][].name' 2>/dev/null
|
||||||
end
|
end
|
||||||
|
|
||||||
# --project value completion
|
# --project value completion
|
||||||
|
|||||||
17
pr.sh
17
pr.sh
@@ -1,11 +1,18 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Usage: source .env && bash pr.sh "PR title" "PR body"
|
# Usage: bash pr.sh "PR title" "PR body"
|
||||||
# Requires GITEA_TOKEN in environment
|
# Loads GITEA_TOKEN from .env automatically
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
GITEA_URL="http://10.0.0.194:3012"
|
# Load .env if GITEA_TOKEN not already exported
|
||||||
REPO="michal/mcpctl"
|
if [ -z "${GITEA_TOKEN:-}" ] && [ -f .env ]; then
|
||||||
|
set -a
|
||||||
|
source .env
|
||||||
|
set +a
|
||||||
|
fi
|
||||||
|
|
||||||
|
GITEA_URL="${GITEA_URL:-http://10.0.0.194:3012}"
|
||||||
|
REPO="${GITEA_OWNER:-michal}/mcpctl"
|
||||||
|
|
||||||
TITLE="${1:?Usage: pr.sh <title> [body]}"
|
TITLE="${1:?Usage: pr.sh <title> [body]}"
|
||||||
BODY="${2:-}"
|
BODY="${2:-}"
|
||||||
@@ -18,7 +25,7 @@ if [ "$HEAD" = "$BASE" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "${GITEA_TOKEN:-}" ]; then
|
if [ -z "${GITEA_TOKEN:-}" ]; then
|
||||||
echo "Error: GITEA_TOKEN not set. Run: source .env" >&2
|
echo "Error: GITEA_TOKEN not set and .env not found" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -72,16 +72,19 @@ describe('fish completions', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('resource name functions use jq (not regex) to avoid matching nested name fields', () => {
|
it('resource name functions use jq .[][].name to unwrap wrapped JSON and avoid nested matches', () => {
|
||||||
// Regex like "name":\s*"..." on JSON matches nested server names inside project objects.
|
// API returns { "resources": [...] } not [...], so .[].name fails silently.
|
||||||
// Must use jq -r '.[].name' to extract only top-level names.
|
// Must use .[][].name to unwrap the outer object then iterate the array.
|
||||||
|
// Also must not use string match regex which matches nested name fields.
|
||||||
const resourceNamesFn = fishFile.match(/function __mcpctl_resource_names[\s\S]*?^end/m)?.[0] ?? '';
|
const resourceNamesFn = fishFile.match(/function __mcpctl_resource_names[\s\S]*?^end/m)?.[0] ?? '';
|
||||||
const projectNamesFn = fishFile.match(/function __mcpctl_project_names[\s\S]*?^end/m)?.[0] ?? '';
|
const projectNamesFn = fishFile.match(/function __mcpctl_project_names[\s\S]*?^end/m)?.[0] ?? '';
|
||||||
|
|
||||||
expect(resourceNamesFn, '__mcpctl_resource_names must use jq').toContain("jq -r '.[].name'");
|
expect(resourceNamesFn, '__mcpctl_resource_names must use jq .[][].name').toContain("jq -r '.[][].name'");
|
||||||
expect(resourceNamesFn, '__mcpctl_resource_names must not use string match on name').not.toMatch(/string match.*"name"/);
|
expect(resourceNamesFn, '__mcpctl_resource_names must not use string match on name').not.toMatch(/string match.*"name"/);
|
||||||
|
// Guard against .[].name (single bracket) which fails on wrapped JSON
|
||||||
|
expect(resourceNamesFn, '__mcpctl_resource_names must not use .[].name (needs .[][].name)').not.toMatch(/jq.*'\.\[\]\.name'/);
|
||||||
|
|
||||||
expect(projectNamesFn, '__mcpctl_project_names must use jq').toContain("jq -r '.[].name'");
|
expect(projectNamesFn, '__mcpctl_project_names must use jq .[][].name').toContain("jq -r '.[][].name'");
|
||||||
expect(projectNamesFn, '__mcpctl_project_names must not use string match on name').not.toMatch(/string match.*"name"/);
|
expect(projectNamesFn, '__mcpctl_project_names must not use string match on name').not.toMatch(/string match.*"name"/);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -126,9 +129,11 @@ describe('bash completions', () => {
|
|||||||
expect(bashFile).toContain('--project');
|
expect(bashFile).toContain('--project');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('resource name function uses jq (not grep regex) to avoid matching nested name fields', () => {
|
it('resource name function uses jq .[][].name to unwrap wrapped JSON and avoid nested matches', () => {
|
||||||
const fnMatch = bashFile.match(/_mcpctl_resource_names\(\)[\s\S]*?\n\s*\}/)?.[0] ?? '';
|
const fnMatch = bashFile.match(/_mcpctl_resource_names\(\)[\s\S]*?\n\s*\}/)?.[0] ?? '';
|
||||||
expect(fnMatch, '_mcpctl_resource_names must use jq').toContain("jq -r '.[].name'");
|
expect(fnMatch, '_mcpctl_resource_names must use jq .[][].name').toContain("jq -r '.[][].name'");
|
||||||
expect(fnMatch, '_mcpctl_resource_names must not use grep on name').not.toMatch(/grep.*"name"/);
|
expect(fnMatch, '_mcpctl_resource_names must not use grep on name').not.toMatch(/grep.*"name"/);
|
||||||
|
// Guard against .[].name (single bracket) which fails on wrapped JSON
|
||||||
|
expect(fnMatch, '_mcpctl_resource_names must not use .[].name (needs .[][].name)').not.toMatch(/jq.*'\.\[\]\.name'/);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user