Class RequestItem

java.lang.Object
io.jenkins.plugins.batchcontrol.action.RequestItem
All Implemented Interfaces:
ModelObject

@Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class) public class RequestItem extends Object implements ModelObject
One run request at /batch-control/requests/<id>/: detail view plus the four state-changing POST endpoints (approve, reject, cancel, changeApprover).

Every endpoint is @RequirePOST (GET never changes state) and performs its permission check before delegating; all business rules (approver eligibility, comment requirements, requester-only/requester-or-Manage rules, atomic state transitions) are enforced by RunRequestService — this class contains zero state logic.

  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static final class 
    One row of the recent-run table.
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    doApprove(org.kohsuke.stapler.StaplerRequest2 req, org.kohsuke.stapler.StaplerResponse2 rsp, String comment)
    POST approve?comment=... — approver decision (comment optional).
    void
    doCancel(org.kohsuke.stapler.StaplerRequest2 req, org.kohsuke.stapler.StaplerResponse2 rsp)
    POST cancel — authenticated users only; service enforces requester-or-Manage.
    void
    doChangeApprover(org.kohsuke.stapler.StaplerRequest2 req, org.kohsuke.stapler.StaplerResponse2 rsp)
    POST changeApprover with the repeated approvers field — replaces the designated set (D-26, D-37); the service enforces requester-only, PENDING and eligibility.
    void
    doReject(org.kohsuke.stapler.StaplerRequest2 req, org.kohsuke.stapler.StaplerResponse2 rsp, String comment)
    POST reject?comment=... — approver decision (service enforces non-empty comment).
    format(Instant instant)
    Jelly helper: human-readable timestamp.
    The refusal of form form on this request, or an empty one (DEF-09, Jelly).
    int
    The approved-but-not-run timeout, for the disabled-job and cancelled-run notices.
    Approver candidates for the change-approver form (global list ∩ job restriction).
     
    Root-relative URL of the build this request produced.
     
    Job URL relative to the Jenkins root if the job exists and the user may see it, else null.
    int
    How many recent-run rows were actually found (at most getRecentRunLimit()).
    int
    How many recent runs this rendering shows, from the runs query parameter (?runs=20) and defaulting to 5.
    The sizes offered by the ?runs= links below the recent-run table.
    The most recent runs of the requested job, newest first, so an approver can see how the job behaved last time without opening a second tab (T-E2E-05).
     
    D-38a: the frozen sentence shown when isRequesterLacksBuild() holds.
    Permissions for this screen's l:layout (the same set its section gate checks).
    boolean
    Whether the request is approved but its build has not been recorded yet (UX-10).
    boolean
    View gating for the cancel link; the service enforces requester-or-Manage.
    boolean
    View gating for the change-approver form; the service enforces requester-only.
    boolean
    View gating for the approve/reject forms: only a member of the designated set sees them (D-29, D-37).
    boolean
    isDesignated(String approver)
    Whether the change-approver picker starts with this candidate checked: the current members, so the form edits the set rather than retyping it.
    boolean
    D-55 (SPEC item 3): whether the request's job is disabled, so the decision form says to enable it first and offers no Approve button, and an approved request says that it waits.
    boolean
     
    boolean
    R2-05: whether the request is approved but the queue item of its run was cancelled, from the queue or by disabling the job (which cancels the job's queued items, D-55), before a build started.
    boolean
    Whether the job has more runs than were shown, so the view can tell "these are all of them" apart from "this is the newest page of a longer history".
    boolean
    D-38a: whether the detail page states that the requester does not hold Item/Build on the job (evaluated for the requester, not the viewer).
    join(List<String> approvers)
    Jelly helper: an approver set for display (a1, a2); empty for none.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Method Details

    • getRequest

      public RunRequest getRequest()
    • getId

      public String getId()
    • getDisplayName

      public String getDisplayName()
      Specified by:
      getDisplayName in interface ModelObject
    • format

      public String format(Instant instant)
      Jelly helper: human-readable timestamp.
    • isRequesterLacksBuild

      public boolean isRequesterLacksBuild()
      D-38a: whether the detail page states that the requester does not hold Item/Build on the job (evaluated for the requester, not the viewer).
    • getRequesterLacksBuildNotice

      public String getRequesterLacksBuildNotice()
      D-38a: the frozen sentence shown when isRequesterLacksBuild() holds.
    • getJobUrl

      @CheckForNull public String getJobUrl()
      Job URL relative to the Jenkins root if the job exists and the user may see it, else null.
    • getExecutedRunUrl

      @CheckForNull public String getExecutedRunUrl()
      Root-relative URL of the build this request produced.
      Returns:
      null when the request produced no run, when the stored id is not of the form jobFullName#number, when the build has since been deleted, or when the job is not visible to the caller (P-09). The view then renders the stored id as plain text instead of a dead link.
    • getRecentRuns

      public List<RequestItem.RecentRun> getRecentRuns()
      The most recent runs of the requested job, newest first, so an approver can see how the job behaved last time without opening a second tab (T-E2E-05). At most getRecentRunLimit() rows.

      P-09: the job is resolved through the permission-aware findJob(), so a caller who may see the request but not the job — and a request whose job has been deleted — gets an empty list; the run history of an invisible job is never disclosed. The runs query parameter only changes how many rows this list holds, never whether the job is resolved, so it cannot be used to step around that check. The view distinguishes the two cases through getJobUrl().

    • getRecentRunLimit

      public int getRecentRunLimit()
      How many recent runs this rendering shows, from the runs query parameter (?runs=20) and defaulting to 5.

      The value is matched against RECENT_RUN_LIMIT_OPTIONS rather than clamped, so anything else — a value above the cap such as ?runs=100000, a negative number, a non-multiple such as 7, or text — silently falls back to the default instead of producing an error page. That makes the largest option the enforced upper bound on how much build history one page load may read, whatever the caller types in the URL.

    • getRecentRunCount

      public int getRecentRunCount()
      How many recent-run rows were actually found (at most getRecentRunLimit()).
    • getRecentRunLimitOptions

      public List<Integer> getRecentRunLimitOptions()
      The sizes offered by the ?runs= links below the recent-run table.
    • isRecentRunsTruncated

      public boolean isRecentRunsTruncated()
      Whether the job has more runs than were shown, so the view can tell "these are all of them" apart from "this is the newest page of a longer history". Call after getRecentRuns().
    • getApproverOptions

      public List<String> getApproverOptions()
      Approver candidates for the change-approver form (global list ∩ job restriction).
    • isPending

      public boolean isPending()
    • isAwaitingExecution

      public boolean isAwaitingExecution()
      Whether the request is approved but its build has not been recorded yet (UX-10).

      Approving redirects back to this read-only page, and the APPROVED → EXECUTED transition plus the run id are written later by the execution listener, so the page the approver lands on is one refresh behind. The view uses this to say so. It turns false as soon as the status moves on (EXECUTED, EXPIRED, INVALIDATED) and is false for PENDING, REJECTED and CANCELLED. R2-05: it is false as well once the queue item of the approved run was cancelled (isQueueCancelled()): that run will not start, so "starts shortly" would be false.

    • isQueueCancelled

      public boolean isQueueCancelled()
      R2-05: whether the request is approved but the queue item of its run was cancelled, from the queue or by disabling the job (which cancels the job's queued items, D-55), before a build started. The service records it (RunRequestService#recordQueueCancelled) and never submits that run again; the approved-run timeout ends the request. The view says that the run will not start instead of the isAwaitingExecution() notice.
    • isJobDisabled

      public boolean isJobDisabled()
      D-55 (SPEC item 3): whether the request's job is disabled, so the decision form says to enable it first and offers no Approve button, and an approved request says that it waits. Resolved through the permission-aware findJob() (P-09): for a viewer who may not read the job this is false, and the service's own refusal of the approval is what they see. Display only; the service enforces the refusal.
    • getApprovedRunTimeoutMinutes

      public int getApprovedRunTimeoutMinutes()
      The approved-but-not-run timeout, for the disabled-job and cancelled-run notices.
    • isCanDecide

      public boolean isCanDecide()
      View gating for the approve/reject forms: only a member of the designated set sees them (D-29, D-37). The endpoints and the service re-check for real.
    • join

      public String join(@CheckForNull List<String> approvers)
      Jelly helper: an approver set for display (a1, a2); empty for none.
    • isDesignated

      public boolean isDesignated(String approver)
      Whether the change-approver picker starts with this candidate checked: the current members, so the form edits the set rather than retyping it.
    • isCanCancel

      public boolean isCanCancel()
      View gating for the cancel link; the service enforces requester-or-Manage.
    • isCanChangeApprover

      public boolean isCanChangeApprover()
      View gating for the change-approver form; the service enforces requester-only.
    • getViewPermissions

      public Permission[] getViewPermissions()
      Permissions for this screen's l:layout (the same set its section gate checks).
    • doApprove

      public void doApprove(org.kohsuke.stapler.StaplerRequest2 req, org.kohsuke.stapler.StaplerResponse2 rsp, @QueryParameter String comment) throws IOException, jakarta.servlet.ServletException
      POST approve?comment=... — approver decision (comment optional). D-72b: a comment holding a character that cannot be stored is shown next to the comment; a request whose stored values do not match the displayed ones, or that was stored before D-72, is refused by the service (IllegalStateException) and its message shown above the form, like a failed save; the request stays pending.
      Throws:
      IOException
      jakarta.servlet.ServletException
    • doReject

      public void doReject(org.kohsuke.stapler.StaplerRequest2 req, org.kohsuke.stapler.StaplerResponse2 rsp, @QueryParameter String comment) throws IOException, jakarta.servlet.ServletException
      POST reject?comment=... — approver decision (service enforces non-empty comment).
      Throws:
      IOException
      jakarta.servlet.ServletException
    • doCancel

      public void doCancel(org.kohsuke.stapler.StaplerRequest2 req, org.kohsuke.stapler.StaplerResponse2 rsp) throws IOException, jakarta.servlet.ServletException
      POST cancel — authenticated users only; service enforces requester-or-Manage.
      Throws:
      IOException
      jakarta.servlet.ServletException
    • doChangeApprover

      public void doChangeApprover(org.kohsuke.stapler.StaplerRequest2 req, org.kohsuke.stapler.StaplerResponse2 rsp) throws IOException, jakarta.servlet.ServletException
      POST changeApprover with the repeated approvers field — replaces the designated set (D-26, D-37); the service enforces requester-only, PENDING and eligibility.
      Throws:
      IOException
      jakarta.servlet.ServletException
    • formErrors

      public FormErrors formErrors(String form)
      The refusal of form form on this request, or an empty one (DEF-09, Jelly).