Skip to content

Add enableValidation option as partial workaround for paginated REST APIs#260

Open
Arbuzov wants to merge 1 commit into
jenkinsci:mainfrom
Arbuzov:feature/enable-validation
Open

Add enableValidation option as partial workaround for paginated REST APIs#260
Arbuzov wants to merge 1 commit into
jenkinsci:mainfrom
Arbuzov:feature/enable-validation

Conversation

@Arbuzov
Copy link
Copy Markdown
Contributor

@Arbuzov Arbuzov commented May 17, 2026

Summary

  • Adds an advanced Enable Value Validation checkbox (default true) to RestListParameterDefinition. Unchecked → the build form renders a free-text <input> backed by a <datalist> of the fetched values instead of the strict select2 dropdown, and isValid() short-circuits true for any non-null submitted value.
  • Exposed as a @DataBoundSetter, so the Pipeline DSL also accepts RESTList(..., enableValidation: false).
  • Four new tests cover the default, the isValid() bypass, the createValue() path, and the DescribableModel pipeline binding.

This is a deliberately small workaround for a real footgun: when the REST endpoint returns a paginated response and the value the user wants is not on the first page, today they have no way to launch the build. They asked for a way to "just type it in." With validation off, they can.

Motivation — partial fix for pagination gaps

This does not make the plugin follow Link headers or continuation tokens. It is the cheapest possible escape hatch so that paginated endpoints remain usable until proper pagination support lands:

Both issues remain open; I think this PR is worth landing on its own, and a follow-up can wire up actual pagination handling.

Build fix bundled in (separate concern)

The pom.xml change is unrelated to the feature itself but lives in the same commit because without it the feature would silently appear to do nothing on some environments. Under maven-compiler-plugin 3.14, target/classes/META-INF/annotations/ is wiped during the test phases even with the existing <compilerArgument>-proc:none</compilerArgument> override. The packaged hpi then ships without the hudson.Extension annotation-indexer index, ExtensionList.lookupSingleton(RestListParameterGlobalConfig.class) fails inside the static initializer of RestListParameterDefinition, and XStream's RobustReflectionConverter swallows the resulting ExceptionInInitializerError while deserializing job configs — silently dropping every RestListParameterDefinition from every job. The user sees no errors anywhere, just empty parameters at build time and "Invalid parameter type RESTList" from the Pipeline DSL.

The fix:

  1. Replace <compilerArgument>-proc:none</compilerArgument> with the native <proc>none</proc> plus <useIncrementalCompilation>false</useIncrementalCompilation> on default-testCompile.
  2. Belt-and-braces: an antrun stash/restore around the test phases (process-classesprepare-package) so the index lands in the jar even if any future plugin in the lifecycle empties the directory again.

Happy to split this into a separate PR if maintainers prefer.

Test plan

  • Unit tests added: enableValidationDefaultsToTrue, isValidAcceptsArbitraryValueWhenValidationDisabled, createValueAcceptsArbitraryWhenValidationDisabled, pipelineDslAcceptsEnableValidationFalse.
  • Manually verified on Jenkins 2.541.3 as a freestyle job with enableValidation=true: bogus value via buildWithParameters?TAG=foo returns HTTP 500 (rejected); valid github tag returns 201 and the build runs with the value.
  • Manually verified the same on the freestyle job with enableValidation=false: free-text value is accepted, build logs show TAG=freely-typed-page2-value.
  • Manually verified on a declarative pipeline (pipeline { parameters { RESTList(..., enableValidation: false) } }): identical behaviour.
  • Manually verified cross-pipeline: a caller pipeline does build job: 'downstream', parameters: [string(name: 'TAG', value: 'crosspipe-page2-value')] — Jenkins converts the string to a RestListParameterValue, validation short-circuits because the downstream has enableValidation=false, and the downstream build runs with the value.
  • Verified the packaged .hpi contains META-INF/annotations/hudson.Extension so the singleton lookup succeeds and XStream loads the parameter.

🤖 Generated with Claude Code

…APIs

Adds an advanced "Enable Value Validation" checkbox (default true) to the
RestListParameterDefinition. When unchecked, the build form renders a free-text
input backed by a datalist of the fetched values instead of the strict select2
dropdown, and isValid() short-circuits true for any non-null submitted value.
This lets users pick a known value or type one that the REST endpoint did not
surface in its first page — a partial workaround for paginated APIs that return
only a slice of the available options.

The option is exposed as a DataBoundSetter so the Pipeline DSL accepts it
(RESTList(..., enableValidation: false)), and four new tests cover the default,
the bypass on isValid, the createValue path, and the DescribableModel pipeline
binding.

This only addresses the symptom. The plugin still does not follow link-headers
or continuation tokens, so the underlying gaps tracked in jenkinsci#61 (paged JSON /
link-header pagination) and jenkinsci#86 (continuation tokens) remain open.

The pom.xml change is a separate concern but lands in the same commit because
without it every job's RestListParameterDefinition silently disappears after
a clean rebuild on maven-compiler-plugin 3.14:
target/classes/META-INF/annotations/ is emptied during the test phases even
with <proc>none</proc> + <useIncrementalCompilation>false</useIncrementalCompilation>
on default-testCompile, so the packaged hpi ships without the @extension
annotation-indexer index. With the index missing, ExtensionList.lookupSingleton
fails inside RestListParameterDefinition.<clinit> and XStream's
RobustReflectionConverter swallows the resulting ExceptionInInitializerError
while loading job configs, silently dropping the parameter. An antrun
stash/restore around the test phases keeps the index in the jar.

Tested on a Jenkins 2.541.3 sandbox as both a freestyle project and a
declarative pipeline, including a caller pipeline invoking a downstream RLP
pipeline with a free-text value via build job parameters.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Arbuzov Arbuzov requested a review from a team as a code owner May 17, 2026 16:18
@mymarche
Copy link
Copy Markdown
Contributor

mymarche commented May 19, 2026

Semantic question about enableValidation and allowEmptyValue interaction

In isValid() the checks run in this order:

  1. null guard → return false
  2. allowEmptyValue && "" check → return true
  3. !enableValidation check (new) → return true

When enableValidation=false, an empty string "" is accepted even if allowEmptyValue=false. This is consistent with "any non-null value is valid", but a user who explicitly unchecks "Enable Value Validation" while leaving "Allow Empty Value" unchecked might expect empty submissions to still be rejected.

Two possible resolutions:

  • Keep as-is — document in the help-enableValidation.html that enableValidation=false implies allowEmptyValue=true regardless of the checkbox.
  • Swap the order — move the !enableValidation check to right after the null guard, so allowEmptyValue is still respected when validation is disabled, and both checkboxes compose independently.

Do you have a preference?

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.

2 participants