Skip to content

Cicd Pipelines

170 companion flashcards · AI-assisted study content · Open the deck →

This deck walks you through the core ideas behind Continuous Integration and Continuous Delivery pipelines, along with hands-on details for two of the most widely used tools in the space: GitHub Actions and Jenkins. You'll find cards on fundamental concepts like pipeline stages, build artifacts, and dependency caching, as well as more specific topics such as matrix builds, reusable workflows, and Jenkins Shared Libraries. It's a great mix of "why" and "how," so you come away understanding both the principles and the practical configuration behind them.

The deck is well suited for developers and DevOps engineers who are setting up or maintaining pipelines, students preparing for technical interviews, or anyone transitioning into a role that involves automated build and release workflows. Because the terminology overlaps heavily between tools and concepts, the cards are also useful as a refresher even if you already have some experience. Pay extra attention to the questions that compare similar ideas, such as Continuous Delivery versus Continuous Deployment, since those distinctions often come up in interviews and real-world architecture discussions.

To get the most out of your study sessions, try reviewing the cards in short bursts rather than long cramming sessions, and revisit the more technical topics like workflow syntax or Jenkins declarative structure on a separate day from the conceptual ones. When you get a card wrong, take a moment to mentally connect it back to the broader pipeline picture before moving on, since CI/CD concepts build on each other in a chain from commit to deployment.

Foundations of CI/CD

Continuous Integration (CI) is a development practice where engineers frequently merge code changes into a shared repository — often multiple times per day. Each merge triggers an automated build and test process, surfacing integration problems within minutes rather than weeks. The core benefits include early bug detection, reduced merge conflicts, faster feedback loops, and a consistent build process across environments. CI is the foundation of any modern software delivery practice, and the disciplines that compose it — test automation, source control hygiene, and pipeline reliability — shape everything that follows.

Continuous Delivery extends CI by ensuring that every successful build is in a deployable state, ready to be released to production at any moment, while still keeping a human approval checkpoint before the actual promotion. Continuous Deployment goes one step further: every change that passes all stages of the pipeline is automatically deployed to production with no human in the loop. The distinction comes down to a single decision gate: delivery keeps a deliberate, manual checkpoint before production, whereas deployment removes it entirely. Choosing between them depends on risk tolerance, regulatory constraints, and the maturity of your automated tests.

A typical CI/CD pipeline moves work through a series of stages that turn source code into running software. The pipeline begins with a Source stage where the latest commit is checked out of version control; Build then compiles code and resolves dependencies. The Test stage runs unit, integration, and end-to-end automated checks. Static Analysis catches lint and code-quality issues, and Security Scan runs static analysis, dynamic analysis, and dependency vulnerability checks. Package produces a deployable artifact, Deploy pushes that artifact to staging or production, and Release makes it visible to end users. Each stage is an opportunity to fail fast — the build should collapse at the earliest, cheapest indicator of trouble.

Branching strategy determines the rhythm of merges that feed the pipeline. GitFlow is a structured model with multiple long-lived branches, including main, develop, feature, release, and hotfix; it works well for scheduled releases but can produce painful merge conflicts when branches live long. Trunk-based development is the opposite extreme: everyone commits to a single trunk at least daily, hides incomplete work behind feature flags, and leans on continuous integration to keep the mainline green. Feature branches sit between these poles: each piece of work is isolated in a dedicated branch that triggers automated builds and status checks, kept short-lived and rebased frequently. Modern CI/CD strongly favors trunk-based or very short-lived branches because they dramatically reduce merge risk.

GitHub Actions in Depth

GitHub Actions is a CI/CD platform built directly into GitHub, where every push, pull request, or scheduled event can trigger an automated workflow defined in YAML under `.github/workflows/`. A workflow is composed of one or more jobs, each of which is an independent unit of work that runs on a designated runner. By default, jobs run in parallel, but the `needs` keyword creates explicit dependencies so that, for example, a deploy job can wait for both build and test to complete first. Inside each job, steps execute sequentially and either run a shell command via `run:` or invoke a reusable action via `uses:`. Reusable actions can come from the GitHub Marketplace or from your own repositories, and a composite action lets you package several shell steps into a single reusable unit. The distinction between composite actions and reusable workflows matters: composites are step-level reuse, while reusable workflows invoked through `workflow_call` are whole-workflow reuse with their own jobs.

The runner is the server that actually executes a job. GitHub-hosted runners are managed virtual machines that are provisioned fresh for each job, available on Ubuntu, Windows, and macOS, and selected through the `runs-on:` key. Self-hosted runners are machines you operate yourself, giving you full control over the execution environment; they are valuable for specialized hardware, private network access, GPU workloads, or cost optimization at scale. Either flavor supports ephemeral mode — a runner that handles one job and then unregisters — which improves isolation. When maintaining self-hosted runners, the safe drain procedure is to remove the runner from the repository or organization, wait for any in-flight job to complete, and only then stop the runner service to avoid leaving a ghost entry in the UI.

Matrix builds amplify the value of a single job definition by running it across multiple combinations of variables such as operating system and language version. The `strategy.matrix` keyword defines those combinations, and GitHub automatically creates one job per cell. To control cost and feedback speed, `fail-fast: true` cancels pending matrix jobs when any one fails, while `max-parallel:` caps how many run concurrently. For monorepos or cases where the matrix depends on repository state, a dynamic matrix can be computed at runtime by emitting the matrix as an output from a setup job and consuming it in a downstream job. This pattern lets you build only the targets affected by a particular change.

Workflows respond to a rich set of events. `push` and `pull_request` are the daily drivers; `pull_request` runs in an isolated concurrency group so it does not affect a production deployment in flight. `workflow_dispatch` lets a human trigger the workflow from the GitHub UI, CLI, or REST API, optionally with typed input parameters, while `schedule` runs on a cron expression with a minimum interval of five minutes. `workflow_run` triggers one workflow after another finishes, enabling clean separation of CI and CD responsibilities with different permissions and approvers. For security, `pull_request_target` must be handled with care because it runs in the context of the base branch with access to secrets — any workflow that uses it must never echo attacker-controlled content. Path filters (`on.push.paths`) restrict runs to changes in specific directories, saving CI minutes in monorepos.

A few cross-cutting concepts give Actions its flexibility. Concurrency groups ensure that only one in-flight run per branch or workflow exists at a time, with `cancel-in-progress: true` aborting older superseded runs. `continue-on-error: true` allows a step or job to fail without halting the pipeline, useful for surfacing warnings without blocking merges. `timeout-minutes` enforces an upper bound on a job's wall-clock duration with a default of 360 minutes, and the workflow-run timeout is configurable up to 43,200 minutes as well. The automatically provisioned `secrets.GITHUB_TOKEN` carries the least-privilege scopes you grant in a `permissions:` block, and OIDC lets Actions assume short-lived cloud IAM roles without storing long-lived keys. Service containers provide sidecar dependencies such as a database for integration tests, and actions like `actions/checkout@v4` clone the repository with options like `fetch-depth: 0` for full git history when needed.

Jenkins and Alternative CI/CD Platforms

Jenkins pioneered the idea of pipeline as code with the Jenkinsfile, a text file checked into the repository root that defines the build in Groovy. Declarative pipelines are the recommended style for most projects: a top-level `pipeline { }` block contains an `agent any` directive, a `stages { }` block enumerating the work to do, optional `environment { }` settings, and a `post { }` section for cleanup and notifications. Scripted pipelines use a more flexible Groovy-based `node { }` syntax that allows programmatic control flow at the cost of readability. The Jenkins architecture splits into a controller, which hosts configuration, scheduling, and the UI, and one or more agents, which actually run the build jobs. An agent specifies where a pipeline or stage runs — `agent any`, a labeled node, a Docker container — and `agent none` at the top of a pipeline forces each stage to declare its own environment for heterogeneous builds. An executor is a slot on an agent that runs one concurrent build, so a four-CPU agent typically has four executors.

Reusability in Jenkins comes from several mechanisms. Shared Libraries are separate Git repositories that hold Groovy code, packaged into a `vars/` directory of global functions, a `src/` directory of classes, and a `resources/` directory of static files. Production Jenkinsfiles should pin libraries by immutable tag using the `@Library('my-lib@1.4.0') _` syntax so a stray admin change cannot alter what runs. A multibranch pipeline automatically creates a job per branch, eliminating manual job creation as the team scales, and a Pipeline job vastly outperforms the older Freestyle GUI-configured model. Common idioms include `retry(3)` for flaky network operations, `withCredentials(...)` for masking secrets, `input` for manual approval gates, `when { branch 'main' }` for conditional stages, `parallel { }` for concurrency, and `triggers { cron('H 2 * * *') }` for jittered nightly schedules. Jenkins has more than 1,800 plugins, so managing them carefully matters: too many creates compatibility and security risk. The pipeline-linter REST endpoint (`/pipeline-model-converter/validate`) lets a CI job syntax-check a Jenkinsfile against the controller's installed plugins before any real build attempt.

GitLab CI/CD is the most direct competitor to GitHub Actions for teams already on GitLab. Pipelines are defined in `.gitlab-ci.yml` at the repository root and are auto-detected by GitLab on every push. The file organizes jobs into named stages, and jobs in the same stage run in parallel. GitLab introduces the `needs:` keyword for DAG-style dependencies that let non-adjacent jobs start as soon as their inputs are ready, dramatically cutting pipeline time. The `rules:` keyword replaces the older `only/except` syntax and supports complex conditions, manual triggers, delayed execution, and exclusion. Artifacts declared with `artifacts:` flow to downstream jobs of the same pipeline, and a `reports:` subkey integrates JUnit, cobertura, and dotenv formats. Runners are tagged agents available in shared, group, project, or specific scopes.

Beyond the two giants, several platforms serve specialized needs. CircleCI separates the runtime environment (executor — docker, machine, macos, windows, or self-hosted) from the steps within a job, and its orbs ecosystem packages reusable configuration the way Actions packages reusable steps. CircleCI contexts provide shared groups of environment variables and secrets across projects. Bitbucket Pipelines offers simple repo-integrated YAML with first-class deployment tracking. Travis CI pioneered the modern YAML-based CI experience via `.travis.yml`, with travis-ci.com the current supported successor. Buildkite uses a hybrid model where Buildkite's cloud handles orchestration while your own infrastructure runs the agents — attractive for keeping secrets on-premises. Drone CI is container-native by design, with each pipeline step running in its own Docker container. Tekton goes furthest, exposing low-level CI/CD primitives as Kubernetes Custom Resource Definitions that require Kubernetes expertise but offer maximum flexibility. The choice between Jenkins, GitHub Actions, and Tekton often comes down to hosting model and ecosystem; pre-commit-less, webhook-driven event triggers are preferred over polling whenever the SCM supports them.

Pipeline Internals, Caching, and Configuration

Build artifacts are the output files produced by a build stage — compiled binaries, Docker images, test reports, coverage reports, or any other deliverable. They flow between stages and jobs, and the same artifact should be promoted across environments unchanged. In GitHub Actions `actions/upload-artifact` and `actions/download-artifact` move files between jobs in a run; in Jenkins `archiveArtifacts` makes a file persistent across the controller, and `stash` provides a transient, same-node handoff between stages. A build number — exposed as `github.run_number` in Actions and `BUILD_NUMBER` in Jenkins — gives every run a monotonically increasing identifier for traceability, and artifact retention policies govern how long built binaries remain downloadable. The default GitHub Actions artifact retention is 90 days, configurable per artifact. An artifact itself is distinct from a release: a release is a named, versioned collection of artifacts plus release notes, typically marked with a Git tag.

Caching is one of the highest-leverage optimizations in any pipeline. Dependency caching stores downloaded packages such as `node_modules`, `~/.m2`, or pip's cache so that they need not be re-fetched on every run. The cache key typically encodes a hash of the lockfile so that the cache invalidates automatically when dependencies change; in GitHub Actions, both `actions/cache@v4` and `actions/setup-node` with `cache: 'npm'` implement this pattern. Build caching, by contrast, stores intermediate compilation outputs — Gradle's build cache, Next.js's `.next/cache`, ccache for C/C++, or Docker layer caching — to skip work done in previous runs. Remote build caching, where the cache is shared across CI jobs and developer machines via systems like Bazel's remote cache, Nx cloud, or Turborepo's remote cache, can cut monorepo build times dramatically. The distinction between `actions/cache` and `actions/upload-artifact` is important: the former is an opaque, restored-on-hit accelerator keyed on inputs, while the latter is a named bundle that downstream consumers can explicitly download.

Containers make every step of a build reproducible. Running pipeline steps inside Docker eliminates environment drift between machines and between local development and CI. In GitHub Actions the `container:` key launches all steps inside a specified image, while Jenkins can use `agent { docker { image 'maven:3.9' } }` to achieve the same effect. For multi-platform support — shipping one image that runs on both Intel and ARM nodes — `docker buildx build --platform linux/amd64,linux/arm64 --push` produces a manifest list that the registry serves correctly per architecture. Daemonless builders such as Kaniko and Buildah are useful in locked-down environments where a Docker daemon is unavailable. Best practices for containerized builds include tagging images with the Git commit SHA (never just `latest`), using multi-stage builds for smaller final images, and pinning deployments to the image's content-addressable digest for true reproducibility. Docker layer caching in particular uses `cache-from: type=gha` to pull previous layers from the GitHub Actions cache and typically yields five-to-ten-times speedups when only the application layer changes.

Secrets need careful handling because pipelines touch dozens of credentials. GitHub Secrets encrypt values at the repository, environment, or organization level; they are automatically masked in logs and are not passed to workflows triggered from forks by default. Environments can require approvers before secrets are exposed, making them an effective approval gate. Jenkins stores secrets through the Credentials plugin across scopes of system, global, or folder; `credentials()` and `withCredentials` bind them to environment variables within a block, with masking applied. For more demanding scenarios, HashiCorp Vault offers dynamic, short-lived secrets, automatic rotation, encryption as a service, and a complete audit log of every access. AWS Secrets Manager provides equivalent functionality tightly integrated with AWS IAM, which is convenient when your infrastructure already lives in AWS. Modern pipelines increasingly use OIDC: GitHub Actions can mint a short-lived cloud IAM token for each workflow run, eliminating the need to store long-lived cloud keys at all.

Several configuration primitives apply across platforms. Environment variables pass values to pipeline steps without hardcoding, with the `env:` key in GitHub Actions and the `environment { }` block in Jenkins, often scoped to the workflow, job, or step. Notifications alert teams to pipeline results through Slack or Microsoft Teams integrations, email, or PagerDuty for production incidents — best practice is to alert on every failure and on successes only when relevant. Approval gates insert a human checkpoint before sensitive stages, implemented in GitHub Actions through environment protection rules (required reviewers, a wait timer, deployment branch restrictions, or external policy checks) and in Jenkins through the `input` step. Infrastructure as Code — Terraform, Pulumi, Ansible, CloudFormation — follows a deliberate pipeline rhythm of `fmt -check`, `validate`, `plan`, manual approval, and `apply`, with state files stored remotely and locked to prevent concurrent modifications. Shell steps benefit from `set -euo pipefail` to fail on the first error, undefined variables, or any pipeline-stage failure rather than only the last.

Testing, Code Quality, and Security Scanning

Testing is the engine of CI's feedback loop. The test pyramid says you should have many unit tests at the base, fewer integration tests in the middle, and a small number of end-to-end tests at the top — and CI mirrors that structure by running fast unit tests on every commit, integration tests after build, and end-to-end tests against staging. To keep the loop tight, tests should run in parallel using sharding, and the generated JUnit XML reports feed back into the CI UI for inspection and trend tracking. Test parallelization has limits, however: shared state, order-dependent tests, and cost-per-runner all conspire to make more than eight-to-ten-way parallelism yield diminishing returns. Tools like `pytest-xdist`, Jest's `--shard`, and Knapsack for Ruby help with sharding. The test stage should be designed to surface meaningful failures quickly and isolate the most common flake sources — shared databases, file systems, timing assumptions, or nondeterministic inputs.

Flaky tests are CI's worst productivity drain because they erode trust in red builds. Tracking flake rate as a key performance indicator and quarantining known-flaky tests into a separate, less-frequently-run suite keeps the main pipeline trustworthy while still surfacing the problem. Each quarantined test should have a clear owner and a tracking ticket so it eventually gets fixed. Local pre-commit hooks complement CI but do not replace it: a pre-commit hook runs on the developer's machine before `git commit`, catching fast issues like lint or formatting with no network round trip, but it is bypassable with `--no-verify` and so cannot be the authoritative gate. The pre-commit framework provides a managed multi-language solution via `.pre-commit-config.yaml`, while CI remains the enforcer of what must be true. Implemented with tools like Husky, pre-commit.com, or lefthook, hooks should stay under five seconds.

Code quality gates are automated checkpoints that enforce minimum standards before code can proceed. Common gates include test coverage above a threshold (e.g., 80% lines and branches), zero critical security vulnerabilities, no new code smells, all linting rules passing, and performance benchmarks within acceptable bounds. Test coverage thresholds are enforced by running tests with coverage (`jest --coverage`), configuring thresholds in the test framework's config, and failing the CI step when the percentage drops below the line. Uploading reports to SonarQube or Codecov tracks coverage trends over time. Linting belongs early in the pipeline so obvious issues are caught before slower tests execute; popular linters include ESLint for JavaScript and TypeScript, Pylint and Ruff for Python, RuboCop for Ruby, and PHP_CodeSniffer for PHP. SonarQube consolidates all of these signals — bugs, vulnerabilities, code smells, duplications, and coverage — into a quality gate that can fail a pipeline when thresholds are not met. GitHub branch protection provides the enforcement mechanism by requiring status checks to pass before a pull request can merge.

Static and dynamic security scanning address different threat models. SAST (Static Application Security Testing) analyzes source code without executing it to find patterns that suggest SQL injection, cross-site scripting, hardcoded credentials, or buffer overflows; popular tools are SonarQube, Semgrep, GitHub CodeQL, and Checkmarx, and they integrate as a build-time check. DAST (Dynamic Application Security Testing), in contrast, tests a running application by simulating external attacks — tools like OWASP ZAP, Burp Suite, and Nuclei can detect authentication flaws, server misconfigurations, runtime injection, and exposed sensitive data. Because DAST requires a deployed target, it is run after deployment to a test environment. Dependency scanning, sometimes called Software Composition Analysis, is the third pillar: tools such as Dependabot, Snyk, Trivy, `npm audit`, and `pip-audit` compare third-party libraries against vulnerability databases like the NVD and block builds with critical findings. Together these three classes of scan catch most common production security issues before they ship.

Deployment Strategies and Progressive Delivery

The deploy stage is where built artifacts become running software, and choosing a strategy shapes both safety and velocity. A recreate deployment simply shuts down the old version and starts the new one, which is simple but causes downtime and is suitable only for development environments, applications that cannot run multiple versions simultaneously, or major schema changes where backward compatibility is impossible. Rolling deployment incrementally replaces instances of the old version with the new batch by batch and is the default in Kubernetes — it requires no extra infrastructure but means mixed versions run during the rollout, slowing rollback. Blue-green deployment maintains two identical production environments and switches traffic from the old (blue) to the new (green) environment once it is verified, giving zero-downtime releases and instant rollback at the cost of double infrastructure and tricky database migrations.

Canary deployment routes a small percentage of real production traffic — typically 5%, then 25%, then 50%, then 100% — to the new version while monitoring error rate and latency. The newer version gets real-world load without putting all customers at risk, and metrics-degradation triggers automatic rollback. A/B testing is similar in mechanics but different in purpose: the split measures business outcomes such as conversion or revenue rather than stability, with traffic routed by user ID, geography, or cookies. A beta release is separate from both — it is a user-opt-in program that collects qualitative feedback rather than measuring production traffic. Dark launching deploys a new code path behind a feature flag and exercises it with real production traffic without exposing outputs to users, validating scale before any visible change. Each strategy trades off infrastructure cost, complexity, and risk in a different way, and the maturity of monitoring and traffic management decides which is safe.

Progressive delivery is the umbrella term for canary, blue-green, feature flags, and dark launches combined with automated safety checks driven by metrics and error budgets. A service mesh such as Istio, Linkerd, or Consul makes progressive delivery practical by giving every pod a sidecar that controls traffic without app changes — a `VirtualService` can route 5% of requests to v2 and 95% to v1 and ramp the weights up over time. Argo Rollouts is a Kubernetes controller that supersedes standard Deployments with first-class canary and blue-green strategies, automated Prometheus analysis, and traffic splitting through Istio or NGINX. Spinnaker, the Netflix-origin platform, includes canary analysis with both manual judgment and automated scoring via Kayenta, which compares canary and baseline metric distributions using statistical tests such as Jensen-Shannon divergence and produces a score from 0 to 100 that drives the pipeline forward or rolls it back.

GitOps extends the same ideas to infrastructure and configuration. In a GitOps model, Git is the single source of truth for both application code and the desired state of the cluster, and an agent continuously reconciles actual state to that description. ArgoCD watches Git repositories and syncs cluster state to match; Flux CD provides similar functionality with a more modular toolkit architecture that platform teams often prefer. Both detect drift and alert when the running cluster deviates from what Git describes. Combined with Helm charts, which package Kubernetes manifests as versioned templates, GitOps gives you reproducible, auditable infrastructure deployments driven by pull requests. Multi-environment deployments typically flow `dev → staging → production`, with environment protection rules (`environment: production` with required reviewers in GitHub Actions) gating the final promotion; ideally the exact same immutable artifact is promoted through each tier rather than being rebuilt per environment.

Ephemeral preview environments push progressive delivery into the pull request workflow. Each PR can be deployed to a unique URL — tools like Vercel, Netlify, Render, Heroku Review Apps, Gitpod, or ArgoCD PR apps spin up a dedicated environment, expose it for design and integration review, and tear it down automatically when the merge or close occurs. SHIPPED is the final tier in a typical release pipeline where the artifact is exposed to all end users; lower tiers such as DEV, STAGING, and PROD-CANARY gate access to internal users or a small percentage of real traffic first, building confidence progressively. Feature flag services like LaunchDarkly, Flagsmith, Unleash, and GrowthBook decouple release from deploy: a flag ships in production but stays off until you flip it, allowing dark launches, gradual rollouts, A/B tests, and instant rollback with no rebuild. Argo Rollouts and ArgoCD are complementary — ArgoCD applies the new ReplicaSet definition, and Argo Rollouts drives the gradual traffic shift.

Supply Chain Security and Engineering Excellence

Modern CI/CD pipelines must defend against attacks on the software supply chain. A Software Bill of Materials (SBOM) is a machine-readable list of every component in an artifact — libraries, versions, licenses, hashes — in formats such as SPDX or CycloneDX, generated at build time using tools like `syft` and used for vulnerability tracking, license compliance, and regulatory reporting. SLSA (Supply-chain Levels for Software Artifacts) is a security framework with progressive levels: Level 1 is provenance documentation, Level 2 is signed provenance from a hosted build platform, Level 3 is a hardened build platform resistant to runner compromise, and Level 4 is hermetic, reproducible builds with two-party review. Adopting SLSA means generating provenance, signing it, and verifying it on deploy. Sigstore solves the historically painful problem of code-signing key management with components like cosign for signing, rekor as a tamper-evident transparency log, and fulcio as a certificate authority that issues short-lived certificates bound to OIDC identities, enabling keyless signing from CI.

Policy engines evaluate declarative rules against proposed changes. OPA/Gatekeeper, Kyverno, and Conftest let you write "block deploy unless the image is signed" or "block deploy if the SBOM contains GPL-licensed code" as version-controlled, testable files. Combined with the principle of least privilege — granting each CI job and runner the minimum IAM scope required, using OIDC federation instead of long-lived secrets, and isolating jobs in ephemeral runners — policy-driven supply chain security dramatically reduces blast radius if a job is compromised. Immutable infrastructure reinforces the same property at runtime: servers and containers are never modified in place, every change is a new build, and rollback simply means redeploying the previous image.

Two core principles guide artifact management. The first is "build once, deploy many": package the artifact in CI once, then promote that exact binary through staging, canary, and production to avoid drift. The second is to use immutable tags. A container tag like `myapp:abc1234` (a Git SHA) never changes once pushed, while mutable tags like `latest` or `stable` can be silently overwritten and break reproducibility. Pinning a deployment to an image's content-addressable digest (`myapp@sha256:...`) guarantees the running bytes match what CI built, even if a tag later moves. Combining immutable tags with build numbers — exposed as `github.run_number` in Actions and `BUILD_NUMBER` in Jenkins — gives complete traceability from a production log entry back to the commit and pipeline run that produced it.

Monorepos introduce their own CI challenges. When a single repository holds dozens of services, building everything on every pull request wastes enormous time. Affected-target detection using build orchestrators with knowledge of the dependency graph is the answer. Bazel is Google's hermetic build system with remote cache and remote execution capabilities that deliver identical results locally and in CI. Turborepo is a JavaScript/TypeScript-focused orchestrator that uses a content-addressable cache and pipeline graph to skip work whose inputs have not changed. Nx, Buck, and similar tools solve the same problem in their respective ecosystems. With remote build caching enabled, a fresh CI build for a five-package monorepo that took twenty-five minutes can drop to under three minutes when most packages are cache hits.

Engineering excellence is ultimately measured by the four DORA metrics. Lead time for changes measures how long it takes a commit to reach production — elite performers achieve less than one hour. Deployment frequency counts how often production is updated — elite performers deploy on demand, multiple times per day. Change failure rate is the percentage of changes that result in degraded service or require remediation — elite performers stay below 15%. Mean time to recover (MTTR) measures from incident detection to service restoration — elite performers recover in under an hour. All four metrics improve dramatically with small batches, trunk-based development, automated testing, canary releases, immutable artifacts, and fast rollback. Strong CI/CD practices are the primary lever. Process choices also matter: a release train introduces a fixed cadence (such as every Tuesday) so features either make the train or wait, providing predictable operational load; deployment freezes block production changes during high-risk windows such as holidays; and a hotfix-versus-rollback policy — ship a new artifact for permanent repair, redeploy a previous artifact for immediate mitigation — keeps the playbook clear. Infrastructure cost also matters: Actions Runner Controller (ARC) on Kubernetes, Buildkite Elastic CI on AWS, and GitLab Runner autoscaler all dynamically provision self-hosted runners based on job backlog to minimize idle compute, while GitHub-hosted runners are billed by the minute with multipliers for Linux, Windows, and macOS that make workload selection an economic lever as well as a technical one.

Frequently asked questions

What is Continuous Integration (CI)?

Continuous Integration is a development practice where developers frequently merge code changes into a shared repository, often multiple times a day. Each merge triggers an automated build and test process to detect integration errors early.

Key benefits:
  • Early bug detection
  • Reduced integration conflicts
  • Faster feedback loops
  • Consistent build process

How does GitHub Actions manage secrets?

GitHub Secrets are encrypted variables stored at the repository, environment, or organization level.

Access in workflows:
${{ secrets.MY_SECRET }}

Key rules:
  • Secrets are masked in logs automatically
  • They are not passed to workflows from forks by default
  • Environment secrets can require reviewers for approval
  • Use GITHUB_TOKEN for built-in repo access
Never hardcode secrets in code or workflow files.

What is SAST (Static Application Security Testing)?

SAST analyzes source code without executing it to find security vulnerabilities early in the development cycle.

What it detects:
  • SQL injection patterns
  • Cross-site scripting (XSS)
  • Buffer overflows
  • Hardcoded credentials
Popular tools: SonarQube, Semgrep, CodeQL (GitHub), Checkmarx

SAST runs in CI as a build-time check and is best at finding issues in code you write, not in dependencies.

What is the purpose of a build number in CI/CD?

A build number is a monotonically increasing identifier (e.g., 4231 or 2026.06.22-r17) assigned to each pipeline run. It enables:
  • Traceability of which exact artifact is deployed
  • Correlation between logs, metrics, and a specific commit
  • Reproducible rollback to a known good build
GitHub Actions exposes it as ${{ github.run_number }}; Jenkins provides BUILD_NUMBER.

What is a workflow_run event and when do you use it?

workflow_run triggers a workflow after another workflow finishes. Common pattern: a CI workflow builds on PRs, a separate workflow_run deploys the merged artifact after the CI workflow on the main branch completes successfully. Lets you split CI and CD with different permissions and approvers.

What is the post section in a Declarative Jenkinsfile?

The post section runs steps after all stages complete, with sub-blocks based on result:
post {
  always { cleanWs() }
  success { slackSend 'Build passed' }
  failure { slackSend 'Build failed' }
  unstable { }
  changed { }
}

Common for cleanup, notifications, and reporting.

What is the difference between a CircleCI executor and a step?

An executor is the runtime environment for a job: docker, machine (full VM), macos, windows, or self-hosted. A step is an individual command or action within a job, like - run: npm test or - checkout. Jobs run on executors; steps are units of work within a job.

What is flaky test quarantine?

A flaky test quarantine is the practice of isolating known-flaky tests into a separate CI suite that runs less frequently or is excluded from required status checks. Each quarantined test has an owner and a ticket. Goal: stop flakes from blocking PRs while still surfacing them.

What is Sigstore and what problem does it solve?

Sigstore is a toolset for signing and verifying software artifacts (containers, binaries, SBOMs). Components: cosign (sign), rekor (transparency log), fulcio (cert authority for short-lived certs). Solves: key management for code signing — no need to manage long-lived signing keys; instead, identities are bound to OIDC tokens.

What is a deployment freeze?

A deployment freeze blocks production deployments during high-risk windows (holidays, Black Friday, end-of-quarter). Implemented in CI/CD via rules: - if: $DEPLOY_FREEZE == 'true' or pipeline-level guard. Forces a discussion before override. Avoid freezes by improving release safety, not by gating velocity.

Drill this topic

170 flashcards on Cicd Pipelines — free, no signup needed to start.

Study Cicd Pipelines flashcards

LearnWiki pages are generated with AI assistance from LearnCoachAssist's reviewed study catalog and may contain errors — verify anything critical against your course materials.