Jenkins / Execution and source foundations / Lesson 2
Declarative structure and step contracts
Read pipeline, agent, stages, steps, and post as a structured execution definition.
On this page
Lesson goals
- Distinguish Declarative syntax from arbitrary Groovy.
- Explain stage-level agent allocation and post-condition scope.
A Jenkinsfile is executable delivery code
Declarative Pipeline provides a structured model built on Jenkins Pipeline subsystems and Groovy syntax rules. The pipeline block contains supported sections and directives rather than any arbitrary sequence of Groovy statements. Scripted Pipeline is another model, and script can provide a deliberate escape hatch within Declarative steps. Choose the simpler form that clearly represents the workflow. Parcel’s examples use Declarative structure with short platform snippets and keep business transformations in ordinary testable programs instead of growing a large orchestration script.
Identify where execution capacity is requested
The following complete-looking definition is still non-runnable course text: it is never saved as a Jenkinsfile or submitted to a controller. agent none avoids one global executor allocation, while the stage declares a synthetic label. A real installation needs the relevant Pipeline plugins and an authorized eligible agent. echo produces a log line only; it does not compile, test, retain, or release Parcel. The example’s purpose is to expose structure and prerequisites without inventing a successful Jenkins run.
pipeline {
agent none
stages {
stage("Review fixture") {
agent { label "parcel-lab" }
steps {
echo "Synthetic fixture review"
}
post {
always { echo "Stage observation finished" }
}
}
}
}
The label is a teaching name, not a configured agent. post belongs to this stage and its always condition does not make failed preceding work successful. No Jenkins syntax validator or engine was run.
Stage names organize evidence, not isolation
A stage marks a meaningful portion of the workflow and helps present results, but a stage name alone does not select a new node or clean a workspace. Agent placement determines allocation scope. Stages sharing an allocation can share files, while stages with different agents need explicit transfer. Declare the evidence each stage produces and what downstream work requires. Splitting one shell script into several stage names may improve navigation without changing the underlying process, trust, or artifact lifecycle.
Post conditions preserve separate outcomes
Pipeline-level and stage-level post blocks observe their respective completion scopes. Conditions such as success, failure, unstable, aborted, always, and cleanup have documented meanings and evaluation order. A report or cleanup step can fail independently of the original test. Preserve both facts instead of allowing the final visible action to rewrite the story. always means the condition is selected regardless of that scope’s completion status; it is not a guarantee that every external failure or lost workspace can be repaired. File-dependent post work still needs an appropriate workspace context.
Keep evidence requirements explicit
The complete local model below evaluates whether every declared stage observation is present and successful. It refuses missing packaging evidence even when tests passed. It does not simulate Declarative parsing, Jenkins results, or post ordering. Its small scope helps separate a report about completed steps from the release predicate. Real Pipelines need explicit handling of unstable, failed, aborted, and skipped outcomes and must bind observations to the intended revision and candidate. A green log-printing stage is not interchangeable with a successful required application check.
required = {"compile", "tests", "package"}
observed = {"compile": "success", "tests": "success"}
missing = sorted(required - observed.keys())
ready = not missing and all(observed[k] == "success" for k in required)
print(bool(ready))
print(missing)
False
['package']
The model uses synthetic result strings and no Jenkins objects. It illustrates missing-evidence rejection rather than a production build-result algorithm.
Common errors and fixes
An arbitrary Groovy statement is placed where a Declarative directive is required.
- Why it happens
- The structured DSL was mistaken for unrestricted Groovy.
- How to fix it
- Use the documented directive shape or a small justified script block.
- Prevent it next time
- Review syntax at the correct Declarative scope.
A new stage is assumed to provide a clean machine.
- Why it happens
- Presentation boundaries were confused with agent and workspace boundaries.
- How to fix it
- Declare allocation and data transfer explicitly.
- Prevent it next time
- Document which stages share execution and files.
A successful post report hides an earlier failed test in the release decision.
- Why it happens
- Reporting outcome replaced required application evidence.
- How to fix it
- Preserve the original result and evaluate required checks explicitly.
- Prevent it next time
- Separate diagnostic, cleanup, and release contracts.
Check your understanding
1. Why use agent none for a workflow whose stages need different node classes?
Show worked solution
It avoids holding one global executor while allowing each stage to request its intended class. It also makes stage allocation and file-transfer assumptions visible. Each file-dependent operation still needs an appropriate execution context.
2. Does post always guarantee an artifact upload after the agent disappears?
Show worked solution
No. The condition can be selected while the needed workspace or agent is unavailable. Retain evidence through appropriate mechanisms and state recovery limitations. A post condition is not a guarantee of resource availability or external delivery.
Key takeaways
- Read Declarative directives at their actual scope.
- Stage presentation, execution allocation, and evidence are separate.