Skip to content

bug: bridge.groovy throws MissingPropertyException — top-level def config vars invisible to cmd_* methods #1098

Description

@milamberspace

What's broken

Every bridge.groovy subcommand fails at runtime with groovy.lang.MissingPropertyException: No such property: TRACKER_URL for class: bridge. The bridge's configuration variables (TRACKER_URL, API_TOKEN, AUTH_SCHEME, ENV) are declared as top-level def locals, so the cmd_* methods and the httpGet/httpPost helpers cannot see them.

Which layer

tools/jira/bridge.groovy lines 40–44:

def ENV = System.getenv()
def TRACKER_URL  = ENV['ISSUE_TRACKER_URL'] ?: ''
def PROJECT_KEY  = ENV['ISSUE_TRACKER_PROJECT'] ?: ''
def API_TOKEN    = ENV['JIRA_API_TOKEN'] ?: ''
def AUTH_SCHEME  = ENV['JIRA_AUTH_SCHEME'] ?: 'Basic'

How to reproduce

ISSUE_TRACKER_URL=https://issues.apache.org/jira \
  groovy tools/jira/bridge.groovy search 'project = FOO'

Result:

Caught: groovy.lang.MissingPropertyException: No such property: TRACKER_URL for class: bridge
	at bridge.cmd_search(bridge.groovy:182)
	at bridge.run(bridge.groovy:372)

The same failure hits every read and write subcommand. It also surfaces in CI: tools/jira/tests/test_bridge_write.py fails (prek run --all-files), because the test harness shells out to the real bridge.

Expected vs actual

  • Expected: the bridge resolves its configuration from the environment and runs the requested subcommand.
  • Actual: it throws MissingPropertyException before any HTTP call.

Root cause: in a Groovy script, a bare top-level def x = … is a local variable of the generated run() method, not an entry in the script binding — so it is invisible inside methods compiled onto the script class. TRACKER_URL is merely the first such variable referenced (when building the request URL); API_TOKEN and AUTH_SCHEME fail the same way once that one is fixed. The top-level if (!TRACKER_URL) guard passes because it runs inside run(), which masks the problem until a cmd_* method is entered.

Fix: annotate the script-level config variables with @groovy.transform.Field (via import groovy.transform.Field) so they become fields visible to every method.

Surface area (optional)

  • PROJECT_KEY is affected by the same scoping issue but is currently dead code (defined, never read), so it has no runtime impact today — promoting it to @Field alongside the others keeps things consistent.
  • The other Groovy tool, tools/dashboard-generator/reference.groovy, is not affected: it defines no methods (linear script + closures, which do capture the script scope) and reads no environment variables.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions