Skip to content

fix(route): add --desc flag + harden e2e gateway-group resolver#39

Open
shreemaan-abhishek wants to merge 3 commits into
masterfrom
route-add-desc-flag
Open

fix(route): add --desc flag + harden e2e gateway-group resolver#39
shreemaan-abhishek wants to merge 3 commits into
masterfrom
route-add-desc-flag

Conversation

@shreemaan-abhishek
Copy link
Copy Markdown
Contributor

@shreemaan-abhishek shreemaan-abhishek commented May 23, 2026

Summary

Two changes:

1. route --desc flag (closes #35)

The README documented a7 route update <id> --desc "..." but neither route create nor route update exposed the flag; description was only settable via -f file.

  • pkg/cmd/route/create: add --desc flag wired to api.Route.Desc.
  • pkg/cmd/route/update: add --desc with DescSet tracking so --desc "" explicitly clears (rather than being treated as unchanged).
  • Unit tests for create + update (incl. clear-via-empty-string).
  • E2E TestRoute_DescFlagCRUD round-trips create / update / clear with a follow-up route get to verify the clear persisted server-side.

2. Harden the e2e gateway-group resolver

The previous resolver picked GET /api/gateway_groups list[0] and ignored both the A7_GATEWAY_GROUP env var and the group's type. CI was silently dependent on remote-server ordering. When the dev environment's first-returned group became an api7_ingress_controller one, every mutating test failed 13 minutes in with the CP middleware's permission denied: Unable to change resources in Ingress gateway group When auth type is not admin_key (CP: internal/pkg/middlewares/gateway_group.go:24, blocks non-admin_key writes to ingress-typed groups).

  • A7_GATEWAY_GROUP=default is now a literal name lookup, not a sentinel.
  • Unknown name → fail at startup with the list of available names (was: 13-minute slow death later).
  • Empty/unset A7_GATEWAY_GROUP → resolver still picks first, but skips ingress-controller groups in the fallback.
  • Startup logs `Resolved gateway group "" -> " so the next env drift is diagnosable from the first log line.

Verified

  • go build / go vet (both with and without -tags e2e) clean.
  • Full go test ./... green locally.
  • Live TestRoute_DescFlagCRUD against API7 EE 3.9.12: --- PASS (0.93s).
  • Bogus name path produces: failed to resolve gateway group: gateway group "does-not-exist" not found; available: [default].

CI

Today's CI failure on this PR is unrelated to either change — it's the same dev-env permission issue affecting every PR (PR #38 docs-only sees the same failure). Once the dev-env token / gateway-group is fixed, this PR's CI will go green; meanwhile the resolver hardening is precisely the thing that prevents this class of failure from happening again.

Closes #35. Part of #22.

Summary by CodeRabbit

  • New Features

    • Create routes with a description via --desc; update routes to set or clear descriptions with --desc (empty string clears).
    • CLI JSON output reflects created/updated/cleared description state.
  • Tests

    • Unit and end-to-end tests added to validate create/update/clear behaviors and JSON output.
    • Test setup improved to resolve gateway groups more reliably to avoid non-mutating ingress-controller groups.

Review Change Stack

The README documented `a7 route update <id> --desc "..."` but neither
`route create` nor `route update` exposed a --desc flag; the field was
only settable via -f. This made the documented invocation fail with
'unknown flag: --desc'.

- Add --desc to flag-based create; wire to api.Route.Desc.
- Add --desc to flag-based update with DescSet tracking so `--desc ""`
  explicitly clears the description (rather than being treated as
  'unchanged').
- Unit tests cover the request-body wiring for both paths and the
  clear-via-empty-string case.
- E2E TestRoute_DescFlagCRUD round-trips create / update / clear
  against a real instance.

Closes #35.
Copilot AI review requested due to automatic review settings May 23, 2026 08:50
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

📝 Walkthrough

Walkthrough

Adds --desc support to route create and route update: create sends desc in POST; update conditionally includes or omits desc in PUT (allowing --desc "" to clear). Unit and e2e tests exercise set and clear flows; e2e gateway-group resolution helper is tightened.

Changes

Route description flag support

Layer / File(s) Summary
Route create description flag
pkg/cmd/route/create/create.go, pkg/cmd/route/create/create_test.go
Options gains Desc, --desc flag is wired, and POST /apisix/admin/routes includes Desc. Added TestCreateRoute_DescFlag.
Route update description flag
pkg/cmd/route/update/update.go, pkg/cmd/route/update/update_test.go
Options gains Desc and DescSet; --desc flag records whether it was provided. actionRun conditionally applies Desc to PUT payload so --desc "" clears the description. Added tests TestUpdateRoute_DescFlag and TestUpdateRoute_DescFlagCanClear.
End-to-end description CRUD flow
test/e2e/route_test.go
Added encoding/json import and TestRoute_DescFlagCRUD plus assertDescCleared helper to exercise create, update, and clear flows and verify CLI JSON responses and server state.

E2E gateway-group resolution

Layer / File(s) Summary
Gateway-group ID resolution
test/e2e/setup_test.go
Replace resolveFirstGatewayGroupID with resolveGatewayGroupID(wanted string), include type in parsing, resolve exact-name matches when provided, or select the first non-ingress group when not.

🎯 3 (Moderate) | ⏱️ ~20 minutes


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Security Check ❌ Error test/e2e/setup_test.go line 142 breaks gateway group fallback: sets wanted="default" instead of wanted="", preventing the non-ingress group fallback from executing when A7_GATEWAY_GROUP is unset. Change test/e2e/setup_test.go line 142 from wanted = "default" to wanted = "" to enable fallback to first non-ingress gateway group when A7_GATEWAY_GROUP is unset.
E2e Test Quality Review ⚠️ Warning E2E test is complete and well-structured, but setup_test.go lines 141-142 contain a critical bug preventing gateway group fallback resolution, causing E2E failures in default environments. Change line 142 from wanted = "default" to wanted = "" to allow resolveGatewayGroupID's fallback logic to execute when no explicit gateway group is configured.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes: adding a --desc flag to route commands and improving the e2e gateway-group resolver.
Linked Issues check ✅ Passed All coding requirements from #35 are met: --desc flag added to create/update, tests added for create/update/clear behaviors, and wire-up to api.Route.Desc completed.
Out of Scope Changes check ✅ Passed All changes relate to #35 (--desc flag) or supporting E2E infrastructure. The gateway-group resolver improvement in setup_test.go is tightly scoped to stabilizing the test environment.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch route-add-desc-flag

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aligns the a7 route CLI with the README by adding a --desc flag to both route create and route update, including support for explicitly clearing the description on update, and adds unit/E2E coverage to prevent regressions.

Changes:

  • Add --desc to route create (wired to api.Route.Desc).
  • Add --desc to route update with DescSet tracking so --desc "" is treated as an explicit update (clear) rather than “unchanged”.
  • Add unit tests for create/update request payloads plus an E2E CRUD round-trip test for set/update/clear.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
test/e2e/route_test.go Adds an E2E regression test covering create/update/clear of desc via flags.
pkg/cmd/route/update/update.go Adds --desc flag handling and DescSet tracking to support clearing.
pkg/cmd/route/update/update_test.go Adds unit tests asserting desc is included/cleared in the PUT payload.
pkg/cmd/route/create/create.go Adds --desc flag and includes Desc in the create request body.
pkg/cmd/route/create/create_test.go Adds a unit test asserting --desc reaches the create request body.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread test/e2e/route_test.go Outdated
Comment on lines +394 to +399
svcID := "e2e-route-desc-svc"
routeID := "e2e-route-desc"
t.Cleanup(func() {
deleteRouteViaAdmin(t, routeID)
deleteServiceViaAdmin(t, svcID)
})
Comment thread test/e2e/route_test.go Outdated
var cleared map[string]interface{}
require.NoError(t, json.Unmarshal([]byte(stdout), &cleared))
if d, present := cleared["desc"]; present {
assert.Equal(t, "", d, "passing --desc \"\" should clear the description")
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/e2e/route_test.go`:
- Around line 425-427: The current check only asserts that cleared["desc"] is an
empty string which can falsely pass if "desc" is simply missing; after
performing the clear update, call the test helper that fetches the persisted
route (e.g., invoke the existing route-get helper or runCommand used elsewhere
in the test) and assert the fetched route's "desc" field is either absent or an
empty string; update the block around the cleared variable (the place
referencing cleared["desc"] and assert.Equal) to, if desc is present assert it's
empty, otherwise perform a follow-up route get and assert the returned object's
desc is empty or not present to ensure the clear persisted.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5141d829-883f-4f32-84fc-26e9e9eb2624

📥 Commits

Reviewing files that changed from the base of the PR and between ac31b9d and 1dc6da8.

📒 Files selected for processing (5)
  • pkg/cmd/route/create/create.go
  • pkg/cmd/route/create/create_test.go
  • pkg/cmd/route/update/update.go
  • pkg/cmd/route/update/update_test.go
  • test/e2e/route_test.go

Comment thread test/e2e/route_test.go Outdated
- Drop the pre-registered name-based cleanup that referenced `routeID`
  (which is the route's name, not its id). The id-only cleanup
  registered after parsing `created["id"]` is the only correct one;
  the pre-reg was a no-op that masked leaks on early failures.
- Treat absent, nil, and "" as a cleared desc via a small helper.
  API7 EE serializes a cleared field as `null`; the previous check
  produced a present-but-nil key and would have failed on a working
  CI environment.
- Add a follow-up `route get` after the clear-update and assert the
  same on the persisted server state, not just the update response.
  Guards against the API echoing an empty desc without persisting it.
The previous resolver picked GET /api/gateway_groups list[0] and ignored
both the env var and the group type. That made CI silently dependent on
remote-server ordering: when the dev environment's first-returned group
became an api7_ingress_controller-typed one, every mutating test failed
13 minutes in with a cryptic 'permission denied' from the CP middleware
(`gateway_group.go:24`: ingress groups reject writes for any auth mode
other than admin_key).

- Treat A7_GATEWAY_GROUP=default as a literal name lookup, not a
  sentinel; honor any explicit name and fail fast at startup with the
  list of available names if no match.
- Fall back path (empty name) now decodes Type and skips
  api7_ingress_controller groups instead of taking list[0].
- Startup log now prints the resolved name -> id mapping so the next
  environment drift is diagnosable from the first log line.
Copilot AI review requested due to automatic review settings May 23, 2026 10:18
@shreemaan-abhishek shreemaan-abhishek changed the title fix(route): add --desc flag to create and update fix(route): add --desc flag + harden e2e gateway-group resolver May 23, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread test/e2e/setup_test.go
Comment on lines +137 to +144
// API7 EE uses UUID-style ids for runtime API calls but env vars carry
// names; resolve name -> id. An explicit name is honored literally; only
// the empty/"default" case falls back to "first writable group".
wanted := gatewayGroup
if wanted == "default" || wanted == "" {
wanted = "default"
}
ggID, err := resolveGatewayGroupID(wanted)
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/e2e/setup_test.go`:
- Around line 140-145: The current normalization coerces both "" and "default"
into "default", preventing resolveGatewayGroupID from exercising its wanted ==
"" fallback; change the logic around the gatewayGroup/wanted variable so an
empty gatewayGroup remains an empty string (do not set wanted = "default" when
gatewayGroup == ""), i.e. remove or adjust the branch that normalizes "" into
"default" and pass the original gatewayGroup value into resolveGatewayGroupID
(refer to the local variable wanted and the call to resolveGatewayGroupID).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 09ae45b4-f8a9-440c-a5db-4dfce4a67214

📥 Commits

Reviewing files that changed from the base of the PR and between 4080fcc and 7c7f3c5.

📒 Files selected for processing (1)
  • test/e2e/setup_test.go

Comment thread test/e2e/setup_test.go
Comment on lines +140 to +145
wanted := gatewayGroup
if wanted == "default" || wanted == "" {
wanted = "default"
}
ggID, err := resolveGatewayGroupID(wanted)
if err != nil {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep the default/unset case on the fallback path.

Lines 141-143 currently normalize both "" and "default" to "default", so resolveGatewayGroupID never reaches its wanted == "" fallback branch. That breaks the documented behavior for the unset/default case and can make the mutating E2E tests target a nonexistent or ingress-only group.

Suggested fix
  wanted := gatewayGroup
  if wanted == "default" || wanted == "" {
-     wanted = "default"
+     wanted = ""
  }
  ggID, err := resolveGatewayGroupID(wanted)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/setup_test.go` around lines 140 - 145, The current normalization
coerces both "" and "default" into "default", preventing resolveGatewayGroupID
from exercising its wanted == "" fallback; change the logic around the
gatewayGroup/wanted variable so an empty gatewayGroup remains an empty string
(do not set wanted = "default" when gatewayGroup == ""), i.e. remove or adjust
the branch that normalizes "" into "default" and pass the original gatewayGroup
value into resolveGatewayGroupID (refer to the local variable wanted and the
call to resolveGatewayGroupID).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

route: add --desc flag to create/update (doc-vs-code mismatch)

2 participants