Chapter 13Lesson 02~190 minutes

CI/CD Components, Component Catalog, inputs, Versioned Reuse, and Organization-Wide Pipeline Building Blocks: Guided Hands-On Workflow and Core Operations

This guided workflow builds a tiny component contract with typed inputs, exercises valid and invalid consumers, simulates two released versions without paid infrastructure, inspects generated job names and expanded configuration, and shows the exact syntax for consuming a version-pinned GitLab component.

CI/CD componentsspec:inputsComponent CatalogVersioned reusePipeline APIs

Learning objectives

  • Create a small component-like contract with typed, documented, validated inputs and caller-controlled job naming.
  • Consume two simulated versions and compare their effective generated jobs without depending on a paid/admin feature.
  • Trigger a deliberate input-validation failure and interpret it as a configuration-creation failure rather than a runner failure.
  • Inspect expanded configuration, component/ref identity, pipeline/job IDs, and non-secret outputs as evidence.
  • Document a safe upgrade path from one component version to another and complete a layer-selection challenge.

1. Disposable workflow and two execution paths

Use a throwaway project/branch such as glci-ch13-components-lab / glci/ch13-components. The mandatory path uses local component-shaped files with spec:inputs so the contract can be learned without catalog settings. If your disposable GitLab project supports components, an optional path tests the same template with include:component pinned to the current SHA.

Safety: all messages and identities are synthetic. The component performs no deployment, publication, registry mutation, cloud call, runner registration, secret retrieval, or admin change. Do not place real credentials in inputs or logs.

2. Create the component-shaped project layout

Create a root README and two simulated version snapshots. In a real component project the distributable component would normally live at templates/greeting/template.yml; the two files below exist only so one consumer pipeline can compare a v1 and v1.1 contract deterministically.

README.md
templates/
  greeting-v1.yml
  greeting-v1_1.yml
.gitlab-ci.yml

3. Version 1.0 contract: small, typed, explicit

spec:
  inputs:
    job-prefix:
      description: "Unique prefix for generated job"
      regex: '^[a-z0-9-]{2,24}$'
    stage:
      default: test
      options: [test, verify]
    greeting:
      default: hello-v1
---
"$[[ inputs.job-prefix ]]-greet":
  stage: $[[ inputs.stage ]]
  image: alpine:3.20.3
  script:
    - printf 'contract=v1.0\n'
    - printf 'greeting=%s\n' '$[[ inputs.greeting ]]'
    - printf 'source=%s sha=%s pipeline=%s job=%s\n' "$CI_PIPELINE_SOURCE" "$CI_COMMIT_SHA" "$CI_PIPELINE_ID" "$CI_JOB_ID"

The component exposes only three knobs. It does not assume a production stage, secret, runner tag, external API, or project-specific path.

4. Version 1.1 contract: additive compatible behavior

spec:
  inputs:
    job-prefix:
      description: "Unique prefix for generated job"
      regex: '^[a-z0-9-]{2,24}$'
    stage:
      default: test
      options: [test, verify]
    greeting:
      default: hello-v1.1
    uppercase:
      type: boolean
      default: false
---
"$[[ inputs.job-prefix ]]-greet":
  stage: $[[ inputs.stage ]]
  image: alpine:3.20.3
  script:
    - value='$[[ inputs.greeting ]]'
    - if [ '$[[ inputs.uppercase ]]' = 'true' ]; then value="$(printf '%s' "$value" | tr '[:lower:]' '[:upper:]')"; fi
    - printf 'contract=v1.1\n'
    - printf 'greeting=%s\n' "$value"
    - printf 'source=%s sha=%s pipeline=%s job=%s\n' "$CI_PIPELINE_SOURCE" "$CI_COMMIT_SHA" "$CI_PIPELINE_ID" "$CI_JOB_ID"

The new boolean has a default, so existing callers can remain compatible. That is an example of a reasonable minor-version change if the generated job behavior stays within the documented contract.

5. Consume both simulated versions with different job prefixes

stages: [test, verify]

include:
  - local: templates/greeting-v1.yml
    inputs:
      job-prefix: old
      stage: test
      greeting: compatible
  - local: templates/greeting-v1_1.yml
    inputs:
      job-prefix: new
      stage: verify
      greeting: compatible
      uppercase: true

consumer-proof:
  stage: verify
  image: alpine:3.20.3
  script:
    - printf 'consumer_sha=%s\n' "$CI_COMMIT_SHA"

Validate first. The expanded configuration should contain old-greet, new-greet, and consumer-proof. The two component instances do not collide because the caller controls the prefix.

6. Prove validation failure before runtime

Change one consumer to use job-prefix: BAD PREFIX!. Because the input regex rejects that value, GitLab should reject the configuration before any runner starts. Preserve the validation message as evidence; do not “fix” it by deleting the regex.

include:
  - local: templates/greeting-v1_1.yml
    inputs:
      job-prefix: "BAD PREFIX!"
      stage: verify
      greeting: test

This is an interface failure. There is no useful runner log because no job should exist yet.

7. Optional real component path pinned to exact source identity

If the same disposable project is structured as a component project, test the component from its current commit SHA. GitLab’s component documentation recommends testing a component against the current SHA before release.

include:
  - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/greeting@$CI_COMMIT_SHA
    inputs:
      job-prefix: sha-pinned
      stage: test
      greeting: current-sha

For a separate consumer project, replace $CI_PROJECT_PATH with the exact component-project path and pin a reviewed SHA or exact governed release. Both projects must be on the same GitLab instance and authorization must permit access.

8. Model two released versions without publishing to the catalog

To practice upgrade reasoning without catalog side effects, record two synthetic release identities: v1.0.0 → <SHA-A> and v1.1.0 → <SHA-B>. Compare the two template diffs, expanded jobs, and README contract. If you own a disposable component project, you may create those tags, but catalog publication is optional and not required for the lesson.

Evidence v1.0.0 v1.1.0
Source identity SHA-A SHA-B
Required inputs job-prefix job-prefix
Optional inputs stage, greeting stage, greeting, uppercase
Generated job pattern -greet -greet
Breaking change? Baseline No, if default preserves old behavior

9. Inspect the generated jobs and runtime identity

For a successful run, record the consumer SHA/pipeline source, pipeline ID, generated job names and IDs, runner/executor, and logs showing only synthetic arguments. In the expanded configuration, prove the interpolated job names and stage values before execution.

printf 'source=%s ref=%s sha=%s pipeline=%s job=%s runner=%s version=%s
'   "$CI_PIPELINE_SOURCE" "$CI_COMMIT_REF_NAME" "$CI_COMMIT_SHA"   "$CI_PIPELINE_ID" "$CI_JOB_ID" "${CI_RUNNER_ID:-not-observed}" "${CI_RUNNER_VERSION:-not-observed}"

10. Write an upgrade note before changing consumers

A useful upgrade note names the old and new component identity, input changes, generated-job changes, permission/secret changes, side effects, compatibility claim, test evidence, rollback reference, and deadline for deprecation if applicable. “Upgrade to latest” is not an upgrade plan.

11. Layer-selection challenge

A consumer succeeds with v1 but configuration fails with v1.1 before any job appears. The component project is reachable and the runner fleet is healthy. Where do you investigate first?

Expected reasoning: compare resolved version, spec:inputs, supplied arguments, and expanded configuration. This is a component contract/configuration layer problem until evidence proves otherwise.

12. Cleanup and retained evidence

Delete only the disposable branch/project/tags created for the lab after exporting the non-secret evidence packet. If you enabled catalog-project settings in an optional experiment, disable or delete only the disposable project you created; do not modify organization-wide catalog settings.

Knowledge check

Why does the lab use different job prefixes for the two versions?

What should happen when BAD PREFIX! violates the input regex?

Why is adding an optional input with a default usually compatible?

What is the safest real-component test reference before publication?

What belongs in an upgrade note besides version numbers?

Next lesson

Configuration, design choices, and tradeoffs

Choose component architecture, SemVer/pinning policy, ownership, least privilege, and upgrade strategy for organization-wide reuse.

Version and compatibility note

GitLab and GitLab Runner evolve continuously. Treat version-sensitive YAML, runner/executor behavior, APIs, security features, policy controls, tiers, and deprecations as assumptions to verify against the current official GitLab documentation before production use. Preserve the exact project/ref/SHA, compiled configuration, pipeline/job IDs, runner/tool versions, and external target evidence used for any reproducible lab or incident record.

Official references and version notes

Documentation verification date: 2026-09-11. Component, input, catalog, component-context, analytics, and publication behavior is version-sensitive. Re-check the GitLab version deployed on Self-Managed or Dedicated instances before relying on newer syntax.

  • CI/CD components and CI/CD Catalog — component projects, version selectors, permissions, testing, publication, security guidance, and current project limits.
  • CI/CD inputs — spec:inputs, interpolation, types, defaults, options, regex validation, size limits, and include inputs.
  • CI/CD YAML syntax reference — include:component, include:inputs, component context, and current parsing semantics.
  • Pipeline editor — validate and inspect expanded configuration before execution.
  • CI Lint — syntax/configuration validation and pipeline simulation where available.
  • Component examples — testing components against the current SHA and coupling versioned resources to component releases.
Current behavior used by this chapter: CI/CD components and the Catalog are available on Free/Premium/Ultimate and GitLab.com/Self-Managed/Dedicated. A component project can currently contain up to 100 components. A component reference can use a commit SHA, tag, or branch; catalog-published components additionally support partial SemVer selectors such as 1/1.2 and ~latest. Catalog releases require SemVer and publication through a GitLab release job. Components can only be referenced from the same GitLab instance. Inputs are resolved at pipeline creation; missing required or invalid typed/options/regex values reject configuration before runner execution. A string inside one input must be under 1 KB, and a string containing interpolated input content must be under 1 MB. Component context fields (name, sha, version, reference) are current functionality but should be version-checked on older instances.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.