Course outline

DevOps / Basic: shared foundations / Lesson 5

Continuous integration and useful feedback

Design a pipeline that verifies a specific change, reports meaningful evidence, and separates untrusted contributions from privileged actions.

About 4 min readContent reviewed
On this page

Lesson goals

  • Design required gates and useful feedback ordering.
  • Isolate job state and preserve failure evidence.
  • Separate untrusted execution from release privileges.

Integration is a team practice

Continuous integration combines frequent integration with automated feedback on the integrated result. A server that builds a long-lived branch once a week does not remove the risk of accumulated divergence. Keep the main development line usable, make failures visible, and assign a response owner. Checks should help the team decide whether the change preserves the intended contract. Fast feedback is useful when it is trustworthy; a five-second test that ignores failures is worse evidence than a slower focused test. Explain what each gate protects instead of treating a pipeline diagram as proof of quality.

Order feedback by cost and signal

Start with quick deterministic checks that catch common mistakes, then add targeted integration and artifact verification. Run independent work in parallel only within available capacity. A failed required gate must prevent promotion, while optional diagnostics should be labeled explicitly. The first example describes a provider-neutral stage graph, not valid configuration for a specific CI vendor. It puts compilation before tests that require its output and records the selected source. A real implementation must use the provider’s documented syntax and preserve exit status rather than masking it through shell pipelines or unconditional success steps.

yaml Provider-neutral teaching graph
source: reviewed-commit
stages:
  - name: static-checks
    required: true
  - name: build
    after: static-checks
  - name: contract-tests
    after: build
  - name: publish-candidate
    after: contract-tests

The ordering expresses dependencies and a required gate. This invented teaching schema is not accepted by GitHub Actions, GitLab CI, or another runner as written.

Isolate the job environment

A job should declare its toolchain, dependencies, permissions, working directory, and outputs. Avoid relying on a developer’s untracked files or a previous job’s leftovers. Use isolated test data and deterministic clocks where behavior depends on time. The second example demonstrates a pure in-memory gate: one failed required check makes the decision false. It does not run a CI system. In a real pipeline, capture useful reports even when a test fails, then clean up owned resources. Preserve enough context to diagnose the first failure without exposing environment secrets or full user data.

python Harmless gate decision simulation
required = {"syntax": True, "contracts": False, "artifact": True}
allowed = all(required.values())
print(allowed)
print(",".join(name for name, passed in required.items() if not passed))
Expected output
False
contracts

all returns false because contracts failed. The failed check remains named, so a consumer can diagnose the decision instead of seeing only an unexplained red status.

Separate trust from convenience

An untrusted pull request can modify build scripts as well as application code. Giving that job deployment credentials gives the contribution a path to privileged actions. Use minimal permissions, separate trusted release jobs, and review third-party actions or plugins as executable dependencies. Cache and artifact access should respect the same trust boundary. Pin external workflow components to reviewed identities where the platform supports it and maintain an update policy. Never make a secret available merely to eliminate a failing optional test; choose an isolated substitute or a safely authorized test environment instead.

Maintain signal over time

A flaky required test teaches people to ignore the pipeline. Investigate shared state, timing assumptions, environmental differences, and weak assertions before adding retries. If a temporary quarantine is justified, give it an owner, expiry, and replacement coverage. Track queue time separately from execution time to see whether adding runners addresses the actual delay. Retain reports according to a deliberate policy and make the verified commit visible in every result. CI is complete when a developer can use the evidence to act, not when a job simply displays a green icon.

Common errors and fixes

A failed test still permits publication

Why it happens
Its exit status was ignored or the gate was optional accidentally.
How to fix it
Make promotion depend on the required result.
Prevent it next time
Test the pipeline’s failure behavior with a synthetic failing check.

Untrusted code receives a deploy credential

Why it happens
Contribution jobs and trusted release jobs share privileges.
How to fix it
Separate execution trust and minimize credential scope.
Prevent it next time
Review workflow changes and artifact handoffs as security boundaries.

Repeated reruns replace diagnosis

Why it happens
A flaky test has no owner or failure evidence.
How to fix it
Capture first-failure context and isolate the cause.
Prevent it next time
Track quarantine expiry and eliminate shared-state assumptions.

Check your understanding

1. A job finishes in two minutes after waiting twenty minutes. Will doubling test speed solve most delay?

Show worked solution

No. Total feedback falls from twenty-two to twenty-one minutes if the queue stays unchanged. Investigate runner capacity, scheduling, and admission policy. Keep execution optimization separate from queue diagnosis so the intervention targets the dominant part of the feedback time.

2. A pull request changes its own workflow. Why should its passing job not deploy automatically?

Show worked solution

The contribution controls executable steps and may forge evidence or extract credentials if given privilege. Use a separately trusted release workflow over reviewed content and verified artifacts. Passing an untrusted script is not authorization to access the release environment.

Key takeaways

  • Continuous integration combines frequent integration with automated feedback on the integrated result.
  • A job should declare its toolchain, dependencies, permissions, working directory, and outputs.
  • A flaky required test teaches people to ignore the pipeline.

Official references