Class JobRequestAction
- All Implemented Interfaces:
Action,ModelObject
/job/<name>/batch-control/ (attached by
JobRequestActionFactory). Renders the request form — reason, approver set and the
job's parameter definitions exactly like the core build page — and submits it to
RunRequestService.create(hudson.model.Job<?, ?>, java.util.List<hudson.model.ParameterValue>, java.lang.String, java.lang.String).
The sidebar link is only visible when run control is on, the job requires approval and the
user holds BatchControl/Request. Without BatchControl/Request the action is
absent altogether (getUrlName() returns null, SPEC item 2, S-07): the
form exposes the eligible approver user-id list, which is not for plain Item/Read
holders, so /job/<name>/batch-control/ and every URL beneath it answer 404.
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidD-66: the check of the dialog view (dialog.jelly, rendered without a layout): the permission ofgetViewPermissions(), on the job.org.kohsuke.stapler.HttpResponsePOSTmarkReviewed(D-58b (3)): the deliberate review of this job after changes made under a permission window.voiddoSubmit(org.kohsuke.stapler.StaplerRequest2 req, org.kohsuke.stapler.StaplerResponse2 rsp) POSTsubmit— creates the run request and redirects to its detail page at/batch-control/requests/<id>/.Approver candidates: global approver list ∩ job-level restriction (if configured).D-66: root-relative URL of the dialog form (dialog.jelly), which the classic sidebar entry (action.jelly) opens in core's dialog.The one sidebar entry on a controlled job that reads "Request Run" (U-02): core's relabeled build link is namedRequestRunUiDecorator.BLOCKED_BUILD_LABELso the two cannot be confused.getEvent()D-66: on the new job page the entry opens the request form in core's dialog, as core's own "Build with Parameters" does (DialogEvent); relative to the job's URL.The names of the job's file parameters (RequestRunPrefill.isFileDefinition(hudson.model.ParameterDefinition)).The refusal of the last submission on this request, or an empty one (DEF-09).getGroup()Hosting review 2026-10-02: on the new job page the run request is the job's build button, so it sits first in the app bar rather than in the overflow menu.Job<?, ?> getJob()D-58c: the runs of this job replayed under a permission window, for the review section.Job<?, ?> The job, under the name core'sl:job-subpagereads (it.object), so the request form renders as a sub-page of the job in both the classic and the new job page.The job's parameter definitions, rendered by each definition's ownindex.jelly.The names of the job's parameters whose values the form never fills in, so the user provides them again (D-72, D-60): file parameters (RequestRunPrefill.isFileDefinition(hudson.model.ParameterDefinition)) and password parameters.D-72, D-72a (SPEC item 11): the id of the incident whose rerun continues on this form, ornull.The reason the form starts with on a rerun that continues here (getRerunIncidentId()): the reason the rerun would have generated, editable; otherwise empty.Rendered as a build action (the build colour) on the new job page; seegetGroup().nullwithoutBatchControl/Request: perAction.getUrlName()that makes the action unreachable, so its whole URL space answers 404 (absent, not refused).Permissions for the request form'sl:layout.booleanisActive()True when run control is on and this job requires approved runs.booleanWhether the current user may submit a run request for this job:BatchControl/RequestandItem/Readon the job (D-38a;Item/Buildis not required), the checksRunRequestService.create(hudson.model.Job<?, ?>, java.util.List<hudson.model.ParameterValue>, java.lang.String, java.lang.String)makes.booleanD-60: whether the form shows values carried from a refused build submission.booleanWhether the page shows the "marked as reviewed" confirmation (constant text only).booleanD-58b (3): whether this page offers "Mark as reviewed": the job is in the "changed under a grant" state (itself or through an ancestor,GrantService.isChangedUnderGrant(hudson.model.Item)) and the viewer holds Item/Configure on it.parameterField(String name) D-72b: theFormErrorsfield of the parameter namedname, whose message the form shows right below that parameter (_form.jelly).selectedRunId(ParameterDefinition definition) T-06-103 (D-60, DEF-09): the run the form shows selected for the run parameterdefinition, ornullto render the definition's own view (RequestRunPrefill.selectedRunId(hudson.model.ParameterDefinition); core's view does not show a carried run).submitQuery(boolean dialog) D-66, D-72a: the query string of the request form's action, with its?, or empty:dialog=truefor the dialog form (Dialogs.fromDialogQuery(jakarta.servlet.http.HttpServletRequest)) and "fromRerun"=<id>when the form continues an incident rerun (getRerunIncidentId(), already validated).Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods inherited from interface hudson.model.Action
getDescription, isVisibleInContextMenu
-
Constructor Details
-
JobRequestAction
-
-
Method Details
-
getJob
-
getObject
The job, under the name core'sl:job-subpagereads (it.object), so the request form renders as a sub-page of the job in both the classic and the new job page. -
getIconFileName
- Specified by:
getIconFileNamein interfaceAction
-
isCanRequestRun
public boolean isCanRequestRun()Whether the current user may submit a run request for this job:BatchControl/RequestandItem/Readon the job (D-38a;Item/Buildis not required), the checksRunRequestService.create(hudson.model.Job<?, ?>, java.util.List<hudson.model.ParameterValue>, java.lang.String, java.lang.String)makes. View gating only;doSubmit(org.kohsuke.stapler.StaplerRequest2, org.kohsuke.stapler.StaplerResponse2)and the service check for real. -
getDisplayName
The one sidebar entry on a controlled job that reads "Request Run" (U-02): core's relabeled build link is namedRequestRunUiDecorator.BLOCKED_BUILD_LABELso the two cannot be confused.- Specified by:
getDisplayNamein interfaceAction- Specified by:
getDisplayNamein interfaceModelObject
-
getGroup
Hosting review 2026-10-02: on the new job page the run request is the job's build button, so it sits first in the app bar rather than in the overflow menu. Only where the entry is shown at all (getIconFileName()); core's ownBuildJobActionis in the same group and readsRequestRunUiDecorator.BLOCKED_BUILD_LABELon a controlled job. -
getSemantic
Rendered as a build action (the build colour) on the new job page; seegetGroup().- Specified by:
getSemanticin interfaceAction
-
getUrlName
nullwithoutBatchControl/Request: perAction.getUrlName()that makes the action unreachable, so its whole URL space answers 404 (absent, not refused).doSubmit(org.kohsuke.stapler.StaplerRequest2, org.kohsuke.stapler.StaplerResponse2)re-checks the permission on top of this. Alsonullon a job's sub-item (a matrix configuration, a Maven module, D-82): run requests are made on its parent job, whose refusal page and notices link that job's form.- Specified by:
getUrlNamein interfaceAction
-
getDialogUrl
D-66: root-relative URL of the dialog form (dialog.jelly), which the classic sidebar entry (action.jelly) opens in core's dialog. -
getEvent
D-66: on the new job page the entry opens the request form in core's dialog, as core's own "Build with Parameters" does (DialogEvent); relative to the job's URL. The full page stays for the refused direct build (D-60) and direct links. -
checkDialogPermission
public void checkDialogPermission()D-66: the check of the dialog view (dialog.jelly, rendered without a layout): the permission ofgetViewPermissions(), on the job. -
getViewPermissions
Permissions for the request form'sl:layout. -
isActive
public boolean isActive()True when run control is on and this job requires approved runs. Never on a job's sub-item (D-82): it has no approval property and no run requests of its own. -
getParameterDefinitions
The job's parameter definitions, rendered by each definition's ownindex.jelly.e2e-03 DEF-09: when a submission is being refused, each definition whose value was parsed is replaced by a copy defaulting to that value (
ParameterDefinition.copyWithDefaultValue(hudson.model.ParameterValue)), so the re-rendered form shows what the user entered. Sensitive values (password parameters) and file values are never copied back into the page (D-72: the form says to provide them again,getReenterParameterNames()). -
isPrefilled
public boolean isPrefilled()D-60: whether the form shows values carried from a refused build submission. -
getReenterParameterNames
The names of the job's parameters whose values the form never fills in, so the user provides them again (D-72, D-60): file parameters (RequestRunPrefill.isFileDefinition(hudson.model.ParameterDefinition)) and password parameters. Shown on a refused submission, on a refused direct build (D-60; files are not carried, issue #10) and on a rerun that continues here. -
getFileParameterNames
The names of the job's file parameters (RequestRunPrefill.isFileDefinition(hudson.model.ParameterDefinition)). -
getRerunIncidentId
D-72, D-72a (SPEC item 11): the id of the incident whose rerun continues on this form, ornull. On a GET it comes from "fromRerun"=<id>; on a refused submission it is the referencedoSubmit(org.kohsuke.stapler.StaplerRequest2, org.kohsuke.stapler.StaplerResponse2)validated (the hidden field of the same name, or the action's query string when the body was over the size cap and never read), and nothing is read from the body here. Either way the id counts only whenIncidentService.linkableIncident(java.lang.String, hudson.model.Job<?, ?>)accepts it (an existing incident of this job, and a viewer holdingBatchControl/ViewHistorywho may request a run of the job, the rights of the rerun itself), the same ruledoSubmit(org.kohsuke.stapler.StaplerRequest2, org.kohsuke.stapler.StaplerResponse2)links the request by; anything else is ignored, so a crafted link shows no notice and reveals nothing. The form then says which values must be provided again and that the request will be linked to the incident, and carries the id back in the hidden field; the values that could be recovered arrive asp.<name>like a refused build's (D-60). -
getRerunReason
The reason the form starts with on a rerun that continues here (getRerunIncidentId()): the reason the rerun would have generated, editable; otherwise empty. No argument on purpose: Stapler would bind a one-argument getter to a URL. -
submitQuery
D-66, D-72a: the query string of the request form's action, with its?, or empty:dialog=truefor the dialog form (Dialogs.fromDialogQuery(jakarta.servlet.http.HttpServletRequest)) and "fromRerun"=<id>when the form continues an incident rerun (getRerunIncidentId(), already validated). Both travel in the query string as well as in hidden fields so that a submission refused before its body is read (over the size cap) is still answered with the right view and the incident reference;doSubmit(org.kohsuke.stapler.StaplerRequest2, org.kohsuke.stapler.StaplerResponse2)reads the hidden field first and validates the reference again wherever it comes from. -
getFormErrors
The refusal of the last submission on this request, or an empty one (DEF-09). -
getApproverOptions
Approver candidates: global approver list ∩ job-level restriction (if configured). -
isShowMarkReviewed
public boolean isShowMarkReviewed()D-58b (3): whether this page offers "Mark as reviewed": the job is in the "changed under a grant" state (itself or through an ancestor,GrantService.isChangedUnderGrant(hudson.model.Item)) and the viewer holds Item/Configure on it.doMarkReviewed()re-checks, andGrantService.markReviewed(hudson.model.Item)refuses a user whose Configure comes from a grant. -
getMarkedRuns
D-58c: the runs of this job replayed under a permission window, for the review section. -
doMarkReviewed
public org.kohsuke.stapler.HttpResponse doMarkReviewed()POSTmarkReviewed(D-58b (3)): the deliberate review of this job after changes made under a permission window.GrantService.markReviewed(hudson.model.Item)refuses a user whose Configure comes from a grant and writes theGUARD_REVIEWEDrecord; this page only asks for Item/Configure first. Redirects back to this page with a short confirmation. -
isReviewedNotice
public boolean isReviewedNotice()Whether the page shows the "marked as reviewed" confirmation (constant text only). -
doSubmit
public void doSubmit(org.kohsuke.stapler.StaplerRequest2 req, org.kohsuke.stapler.StaplerResponse2 rsp) throws IOException, jakarta.servlet.ServletException POSTsubmit— creates the run request and redirects to its detail page at/batch-control/requests/<id>/. A refused submission re-renders the form with HTTP 400, the message next to the field it concerns and the user's input kept (e2e-03 DEF-09).D-72: the form posts
multipart/form-data, so file parameters are uploaded with it, and the request keeps the submitted values with their types (create). Because requesting a run does not requireItem/Build(D-38a), the size is checked in two stages (D-74 (2),RequestBodyLimit), each answered with HTTP 413 and the empty form, nothing created or kept:- right after the permission checks and before this endpoint reads the body, the
declared
Content-Length(RequestBodyLimit.exceeds(jakarta.servlet.http.HttpServletRequest)), an early filter that a body without a declared length passes; - before anything is stored, what the request would keep
(
RequestBodyLimit.checkKept(java.util.List<? extends hudson.model.ParameterValue>, java.util.Map<java.lang.String, java.lang.Long>), increate): the values plus the uploaded parts each was created from, measured here (RequestBodyLimit.uploadedSize(org.kohsuke.stapler.StaplerRequest2, java.util.Collection<java.lang.String>)) before itscreateValue, since creating a value may consume its part.
Job#getDynamicbuilds the job's widgets andHistoryWidgetreads a paging parameter. That happens for every URL under a job, before any plugin code, and is bounded only by Stapler'sorg.kohsuke.stapler.RequestImpl.FILEUPLOAD_MAX_*properties.) When the form's own checks refuse a submission, the temporary files of its file values are disposed of here (ParameterFiles); once the values are handed to the service, it disposes of them on its own refusals. The re-rendered form never shows a password or a file again.D-72a (SPEC item 11): a submission from the form an incident rerun fell back to carries the incident id in the field "fromRerun". It is read after the permission and size checks, passed through
IncidentService.linkableIncident(java.lang.String, hudson.model.Job<?, ?>)and only the id that check returns goes tocreate, which links the request so that a successful run recordsresolvedByRunId; an invalid reference is ignored. A refused submission keeps the validated reference on the re-rendered form.N-01:
parseParameters(org.kohsuke.stapler.StaplerRequest2, net.sf.json.JSONObject, java.util.List<hudson.model.ParameterValue>, java.util.Map<java.lang.String, java.lang.Long>)is inside thetryon purpose. A parameter definition rejects a bad value by throwingIllegalArgumentException— a choice parameter given a value outside its choices, for instance — and that is the same class the service's own validation throws. Parsing outside thetryturned user-supplied input into an uncaught exception and an HTTP 500 "Oops!" page while an empty reason correctly answered 400; both are user input and both belong in the same 400 channel, now the re-rendered form.security-08 S-10: a scripted submission with no
jsonfield used to store an empty parameter map, so the later approved build ran with whatever defaults the job had at build time rather than the values the approver saw.parseRawParameters(org.kohsuke.stapler.StaplerRequest2, java.util.List<hudson.model.ParameterValue>, java.util.Map<java.lang.String, java.lang.Long>)now reads each defined parameter straight from the request the way core'sParametersDefinitionProperty#_doBuild/buildWithParametersdo, so the stored values are complete either way.D-72b: a parameter name submitted more than once in the
jsonfield is refused here, before the service sees any value, as a field error below that parameter (parameterField(java.lang.String)); on the raw channel each definition reads its own field, and a definition that refuses a repeated field is reported the same way. The service's own refusals are filed byfileServiceRefusal(io.jenkins.plugins.batchcontrol.ui.FormErrors, java.lang.RuntimeException): a message about one of the job's parameters below it, the reason's next to the reason, and a failed save (StoreWriteException) above the form, always as the re-rendered form (HTTP 400), never an error page. A request over the kept-size cap (RequestTooLargeException) is answered with HTTP 413, like an oversized body.- Throws:
IOExceptionjakarta.servlet.ServletException
- right after the permission checks and before this endpoint reads the body, the
declared
-
parameterField
D-72b: theFormErrorsfield of the parameter namedname, whose message the form shows right below that parameter (_form.jelly). Not a getter on purpose: a one-argument getter would be bound to a URL. -
selectedRunId
T-06-103 (D-60, DEF-09): the run the form shows selected for the run parameterdefinition, ornullto render the definition's own view (RequestRunPrefill.selectedRunId(hudson.model.ParameterDefinition); core's view does not show a carried run). Not a getter on purpose, likeparameterField(java.lang.String).
-