Class QuestionStore
java.lang.Object
io.jenkins.plugins.interactiveinput.store.QuestionStore
In-memory registry of human-in-the-loop
Questions with XStream persistence to
$JENKINS_HOME/interactive-input/questions.xml (§8.1, §8.2).
The store is the single authority for question lifecycle and permissions. Paused pipeline steps
register a transient QuestionStore.Resolution keyed by question id; when a question reaches a terminal
state (answered, aborted, expired) the store invokes that resolution so the pipeline resumes. The
question metadata survives a Jenkins restart via XStream; the resolution is re-registered when the
step's onResume runs.
Concurrency: the questions map is a ConcurrentHashMap; all transitions on a single
Question are serialised via synchronized (question) (§8.9).
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic interfaceCallback invoked once when a question reaches a terminal state. -
Field Summary
Fields -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidAbort a question (cancel the input).voidabortForShutdown(String questionId, String byUserId) Transition a WAITING question to ABORTED without invoking its resolver.Record a human answer and resume the pipeline.answerParameters(String questionId, Map<String, Object> parameterValues, String byUserId, String source) Record aninput-style parameter answer and resume the pipeline (B24).booleanbooleanbooleanbooleanbooleanstatic Choicevoidcompact(long now, long retentionMs) Remove terminal questions older thanretentionMs.intcountAnswerableForJob(String jobFullName) intintcountNotificationsForBuild(String jobFullName, int buildNumber) intcountNotificationsForJob(String jobFullName) static StringvoidexpireOverdue(long now) Expire every overdue WAITING question.Job<?, ?> static QuestionStoreget()booleanhasAnyForBuild(String jobFullName, int buildNumber) Existence probe (no permission filter) used by the run-action factory to decide whether to attach the per-build surfaces.booleanhasNotificationForBuild(String jobFullName, int buildNumber) booleanhasWaitingForBuild(String jobFullName, int buildNumber) listAll()listAnswerableForJob(String jobFullName) listForBuild(String jobFullName, int buildNumber) listNotificationsForJob(String jobFullName) listReadableForJob(String jobFullName) intStartup self-heal: purge questions whose owning build no longer exists (deleted before this cleanup shipped, or while the controller was down).voidregister(String questionId, QuestionStore.Resolution resolution) Attach a paused step's resolver.voidRemove a question outright (used by the input-step bridge to drop a mirror when the underlying native input has settled or the bridge has been disabled).intremoveForBuild(String jobFullName, int buildNumber) Purge every question of a now-deleted build (any status).Register a new WAITING question and persist it.voidunregister(String questionId)
-
Field Details
-
SOURCE_UI
Source tags for the audit trail (§7.7).- See Also:
-
SOURCE_REST
- See Also:
-
SOURCE_BRIDGE
- See Also:
-
SOURCE_SYSTEM
- See Also:
-
-
Constructor Details
-
QuestionStore
public QuestionStore()
-
-
Method Details
-
get
-
submit
Register a new WAITING question and persist it.- Returns:
- the same question for convenience
-
register
Attach a paused step's resolver. If the question already reached a terminal state (e.g. it was answered while the step was being resumed after a restart), the resolver is invoked immediately. -
unregister
-
answer
@NonNull public Answer answer(@NonNull String questionId, @CheckForNull String choiceId, @CheckForNull String freeText, @NonNull String byUserId, @NonNull String source) Record a human answer and resume the pipeline. Callers must pre-check permissions (a 403 is the REST/UI layer's responsibility); this method assumes the caller is authorised.- Throws:
IllegalStateException- if the question is missing or already settled
-
answerParameters
@NonNull public Answer answerParameters(@NonNull String questionId, @NonNull Map<String, Object> parameterValues, @NonNull String byUserId, @NonNull String source) Record aninput-style parameter answer and resume the pipeline (B24). Callers must pre-check permissions and pre-validate/convert the values (the REST/UI layer's responsibility); this method assumes the caller is authorised and the values are already the resolvedParameterValue.getValue()objects. Only parameter names are logged — never values, so a password parameter is not leaked.- Throws:
IllegalStateException- if the question is missing or already settled
-
abort
Abort a question (cancel the input). Delivers an abort to the pipeline.- Throws:
IllegalStateException- if the question is missing or already settled
-
abortForShutdown
Transition a WAITING question to ABORTED without invoking its resolver. Used when the framework stops the step itself (e.g. the build is aborted) and will deliver the cause to the pipeline directly. No-op if the question is missing or already terminal. -
get
-
remove
Remove a question outright (used by the input-step bridge to drop a mirror when the underlying native input has settled or the bridge has been disabled). -
listAnswerable
- Returns:
- all WAITING questions the current user is allowed to answer (bell + default REST list).
-
listReadable
- Returns:
- all WAITING questions the current user can at least read (Item.READ on the source job).
-
listAll
- Returns:
- every WAITING question (admin only; callers must enforce
Overall/Administer).
-
listAnswerableForJob
- Returns:
- WAITING questions for
jobFullNamethe current user may answer.
-
listReadableForJob
- Returns:
- WAITING questions for
jobFullNamethe current user can at least read.
-
countAnswerableForJob
- Returns:
- the number of WAITING questions for
jobFullNamethe current user may answer.
-
listForBuild
- Returns:
- every question (any status) recorded for a specific build that the current user can read. Used by the per-build audit view; includes settled questions until compaction.
-
hasWaitingForBuild
- Returns:
trueifjobFullName#buildNumberhas any WAITING question.
-
hasAnyForBuild
Existence probe (no permission filter) used by the run-action factory to decide whether to attach the per-build surfaces. Anyone reaching a build page already holdsItem.READ, so this leaks nothing beyond what the audit view (which is permission-checked) would show.- Returns:
trueif any question (any status) is recorded for this build.
-
listNotifications
- Returns:
- WAITING questions to surface for the current user across all jobs.
-
listNotificationsForJob
- Returns:
- WAITING questions to surface for the current user, scoped to one job.
-
countNotifications
public int countNotifications() -
countNotificationsForJob
-
countNotificationsForBuild
- Returns:
- the number of WAITING questions to surface for the current user on a single build,
honouring the user-scope and lock-to-starter switches. Drives the run-page sidebar count
badge (the per-build equivalent of
countNotificationsForJob(String)).
-
hasNotificationForBuild
- Returns:
trueif the build has a WAITING question the current user should be notified of (drives the build-history badge, honouring user-scope and lock).
-
canAnswer
- Returns:
trueif the current authentication may answer the question.
-
canAbort
- Returns:
trueif the current authentication may abort the question (and thereby abort the run). RequiresItem.CANCELon the source job, or — when asubmitterFilteris set — membership in that set.Jenkins.ADMINISTERand security-off always pass.Item.BUILDalone is not enough: aborting a pipeline is Cancel, not Build.
-
canAnswerEffective
- Returns:
trueif the current authentication may answer after applying the lock-to-build-starter switch. This iscanAnswer(Question)unless the switch is on, in which case only the build starter (or a Jenkins administrator) may answer; builds with no human starter are never locked. This is the check the REST answer endpoint and the modal'scanAnswerflag use — it can only ever restrict, never widen, access.
-
canAbortEffective
- Returns:
trueif the current authentication may abort after applying the lock-to-build-starter switch. Same restriction ascanAnswerEffective(Question): the lock can only ever restrict, never widen, Cancel.
-
canView
- Returns:
trueif the current authentication can read the source job (Item.READ).
-
findJob
-
currentUserId
- Returns:
- the user id of the current authentication, or
"SYSTEM"if unauthenticated.
-
expireOverdue
public void expireOverdue(long now) Expire every overdue WAITING question. Called by the SLA ticker. -
compact
public void compact(long now, long retentionMs) Remove terminal questions older thanretentionMs. Called by the SLA ticker. -
removeForBuild
Purge every question of a now-deleted build (any status). A question is meaningful only alongside its build — its audit trail lives on the build page, which is gone — so on build deletion its questions are removed outright, clearing them from the notification centre and the sidebar/badge counts. Invoked by theRunListenerwhen a build is deleted.- Returns:
- the number of questions removed.
-
reconcileDeletedBuilds
public int reconcileDeletedBuilds()Startup self-heal: purge questions whose owning build no longer exists (deleted before this cleanup shipped, or while the controller was down). Only acts when the job still resolves but the build is gone, so a temporarily-unresolvable job never loses its questions. Invoked once fromBuildLifecycleCleanup'sonLoaded.- Returns:
- the number of questions removed.
-
choice
-