<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>kumar k &#8211; Best DevOps</title>
	<atom:link href="https://www.bestdevops.com/author/kumar-kunal/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.bestdevops.com</link>
	<description>Lets Learn, Do it &#38; Share! Thats a Best DevOps!!!</description>
	<lastBuildDate>Tue, 27 May 2025 19:03:32 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.2</generator>
	<item>
		<title>Gitlab Pipeline – environment – What is environment in GitLab CI/CD?</title>
		<link>https://www.bestdevops.com/gitlab-pipeline-environment-what-is-environment-in-gitlab-ci-cd/</link>
					<comments>https://www.bestdevops.com/gitlab-pipeline-environment-what-is-environment-in-gitlab-ci-cd/#respond</comments>
		
		<dc:creator><![CDATA[kumar k]]></dc:creator>
		<pubDate>Tue, 27 May 2025 19:02:21 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=31400</guid>

					<description><![CDATA[The environment keyword in a GitLab CI/CD job definition is used to define and track deployments to specific named environments [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The <code>environment</code> keyword in a GitLab CI/CD job definition is used to define and track deployments to specific named environments (like <code>staging</code>, <code>production</code>, or dynamic review environments). It helps you visualize your deployment history, access deployed applications, and manage the lifecycle of these environments.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Example <code>.gitlab-ci.yml</code> with <code>environment</code>:</h3>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .gitlab-ci.yml</span>

stages:
  - build
  - deploy_review
  - stop_review
  - deploy_staging
  - deploy_production
  - cleanup_staging

<span class="hljs-keyword">default</span>:
  image: alpine:latest

<span class="hljs-comment"># A simple build job (not directly using 'environment')</span>
build_app:
  stage: build
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Building Application ---"</span>
    - mkdir -p my_app_build/
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"version_1.0"</span> &gt; my_app_build/app.txt
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Build complete."</span>
  artifacts:
    paths:
      - my_app_build/
    expire_in: <span class="hljs-number">1</span> hour

<span class="hljs-comment"># Job 1: Deploy to a dynamic Review App environment</span>
deploy_review_app:
  stage: deploy_review
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Deploying Review App for branch: $CI_COMMIT_REF_SLUG ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"App version from build: $(cat my_app_build/app.txt)"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Deployed to https://$CI_COMMIT_REF_SLUG.example.com"</span> <span class="hljs-comment"># Simulate deployment</span>
    - sleep <span class="hljs-number">10</span>
  environment:
    name: review/$CI_COMMIT_REF_SLUG <span class="hljs-comment"># Dynamic environment name based on branch</span>
    url: https:<span class="hljs-comment">//$CI_COMMIT_REF_SLUG.example.com # Dynamic URL for the review app</span>
    on_stop: stop_review_app <span class="hljs-comment"># Specifies a job to run when this environment is "stopped"</span>
    auto_stop_in: <span class="hljs-number">2</span> hours <span class="hljs-comment"># Automatically triggers 'stop_review_app' after 2 hours of inactivity/age</span>
  rules:
    - <span class="hljs-keyword">if</span>: <span class="hljs-string">'$CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH &amp;&amp; $CI_COMMIT_BRANCH != "staging"'</span> <span class="hljs-comment"># Run for feature branches</span>

<span class="hljs-comment"># Job 2: Stops the Review App environment</span>
stop_review_app:
  stage: stop_review
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Stopping Review App for branch: $CI_COMMIT_REF_SLUG ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Cleaning up resources for https://$CI_COMMIT_REF_SLUG.example.com"</span>
  environment:
    name: review/$CI_COMMIT_REF_SLUG <span class="hljs-comment"># Must match the environment name to stop</span>
    action: stop <span class="hljs-comment"># This action marks the environment as stopped</span>
  when: manual <span class="hljs-comment"># Usually, stop jobs are manual or triggered by 'on_stop' or 'auto_stop_in'</span>
  rules:
    - <span class="hljs-keyword">if</span>: <span class="hljs-string">'$CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH &amp;&amp; $CI_COMMIT_BRANCH != "staging"'</span>

<span class="hljs-comment"># Job 3: Deploy to Staging environment</span>
deploy_to_staging:
  stage: deploy_staging
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Deploying to Staging Environment ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"App version from build: $(cat my_app_build/app.txt)"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Deployed to https://staging.example.com"</span>
    - sleep <span class="hljs-number">10</span>
  environment:
    name: staging
    url: https:<span class="hljs-comment">//staging.example.com</span>
    <span class="hljs-comment"># on_stop: stop_staging # You could define a 'stop_staging' job similarly if needed</span>
  rules:
    - <span class="hljs-keyword">if</span>: <span class="hljs-string">'$CI_COMMIT_BRANCH == "staging"'</span> <span class="hljs-comment"># Example: run only for 'staging' branch</span>

<span class="hljs-comment"># Job 4: Deploy to Production environment (often manual)</span>
deploy_to_production:
  stage: deploy_production
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Deploying to Production Environment ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"App version from build: $(cat my_app_build/app.txt)"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Deployed to https://production.example.com"</span>
    - sleep <span class="hljs-number">15</span>
  environment:
    name: production
    url: https:<span class="hljs-comment">//production.example.com</span>
  when: manual <span class="hljs-comment"># Production deployments are often manual for control</span>
  rules:
    - <span class="hljs-keyword">if</span>: <span class="hljs-string">'$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'</span> <span class="hljs-comment"># Run only for the default branch (e.g., main)</span>

</code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Explanation:</h3>



<ol class="wp-block-list">
<li><strong><code>environment:</code> Keyword:</strong>
<ul class="wp-block-list">
<li>Used within a job&#8217;s definition to declare that this job performs a deployment to a specific environment.</li>



<li>It takes a map of sub-keys.</li>
</ul>
</li>



<li><strong><code>deploy_review_app</code> Job (Dynamic Environment):</strong>
<ul class="wp-block-list">
<li><strong><code>environment:</code></strong>:
<ul class="wp-block-list">
<li><strong><code>name: review/$CI_COMMIT_REF_SLUG</code></strong>:
<ul class="wp-block-list">
<li>(Required) This is the unique name of the environment. Using predefined CI/CD variables like <code>$CI_COMMIT_REF_SLUG</code> (the branch or tag name in a URL-friendly format) allows you to create dynamic environment names. This is very common for &#8220;Review Apps&#8221; where each feature branch gets its own temporary deployment environment.</li>
</ul>
</li>



<li><strong><code>url: https://$CI_COMMIT_REF_SLUG.example.com</code></strong>:
<ul class="wp-block-list">
<li>(Optional) A publicly accessible URL for this environment. GitLab will display this URL on the Environments page, merge requests, etc., making it easy to access the deployed application.</li>
</ul>
</li>



<li><strong><code>on_stop: stop_review_app</code></strong>:
<ul class="wp-block-list">
<li>(Optional) Specifies the name of another job (<code>stop_review_app</code> in this case) that should be run when this environment is &#8220;stopped.&#8221; An environment can be stopped manually from the GitLab UI, or automatically (e.g., when a branch is deleted, or via <code>auto_stop_in</code>).</li>
</ul>
</li>



<li><strong><code>auto_stop_in: 2 hours</code></strong>:
<ul class="wp-block-list">
<li>(Optional) If this environment is not re-deployed within &#8220;2 hours&#8221;, GitLab will automatically trigger the job specified in <code>on_stop</code> (if defined) or simply mark the environment as stopped. This is great for cleaning up temporary review environments.</li>
</ul>
</li>
</ul>
</li>



<li><strong><code>rules:</code></strong>: This job is configured to run only for feature branches (not the default branch or staging), which is typical for review apps.</li>
</ul>
</li>



<li><strong><code>stop_review_app</code> Job (Stopping an Environment):</strong>
<ul class="wp-block-list">
<li><strong><code>environment:</code></strong>:
<ul class="wp-block-list">
<li><strong><code>name: review/$CI_COMMIT_REF_SLUG</code></strong>: This <strong>must match</strong> the name of the environment that this job is intended to stop.</li>



<li><strong><code>action: stop</code></strong>: This tells GitLab that this job&#8217;s purpose is to stop the specified environment. When this job runs successfully, GitLab updates the environment&#8217;s status to &#8220;stopped.&#8221;</li>
</ul>
</li>



<li><strong><code>when: manual</code></strong>: Stop jobs are often manual, allowing users to decide when to tear down an environment. However, they can also be triggered automatically by <code>on_stop</code> from the deployment job or by branch deletion if configured.</li>
</ul>
</li>



<li><strong><code>deploy_to_staging</code> and <code>deploy_to_production</code> Jobs (Static Environments):</strong>
<ul class="wp-block-list">
<li>These jobs deploy to well-known, static environments (<code>staging</code> and <code>production</code>).</li>



<li><strong><code>name: staging</code> / <code>name: production</code></strong>: Static names.</li>



<li><strong><code>url</code></strong>: Static URLs for these environments.</li>



<li><strong><code>when: manual</code> (for production):</strong> It&#8217;s a common safety measure to make production deployments a manual step, requiring explicit user action.</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Key Concepts and Benefits:</h3>



<ul class="wp-block-list">
<li><strong>Deployment Tracking:</strong> GitLab keeps a record of all deployments to each environment. You can see this under <strong>Operate > Environments</strong> in your project. This includes when each deployment happened, by whom, and the commit SHA.</li>



<li><strong>Rollbacks and Re-deploys:</strong> From the Environments page, you can easily re-deploy a previous successful deployment to an environment (effectively a rollback if the previous deployment was an older version) or re-run the latest deployment job.</li>



<li><strong>Environment-Specific Variables:</strong> You can define CI/CD variables in GitLab (Settings > CI/CD > Variables) and scope them to specific environments. This allows you to have different configurations (e.g., database URLs, API keys) for <code>staging</code> vs. <code>production</code> without hardcoding them in your <code>.gitlab-ci.yml</code>.</li>



<li><strong>Protected Environments:</strong> Production environments can be &#8220;protected,&#8221; limiting who can deploy to them and which branches/tags can be deployed.</li>



<li><strong>Review Apps:</strong> Dynamic environments (like <code>review/$CI_COMMIT_REF_SLUG</code>) are a powerful feature for previewing changes from feature branches before merging them.</li>



<li><strong>Cleanup (<code>on_stop</code>, <code>action: stop</code>, <code>auto_stop_in</code>):</strong> These features help manage the lifecycle of temporary environments, ensuring resources are cleaned up.</li>



<li><strong>Visualizations:</strong> The environment URL is shown in merge requests if a review app is deployed, making it easy for reviewers to access and test the changes.</li>
</ul>



<p class="wp-block-paragraph">Using the <code>environment</code> keyword provides significant benefits for managing and visualizing your deployment processes, making your CI/CD pipeline more robust and transparent.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/gitlab-pipeline-environment-what-is-environment-in-gitlab-ci-cd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Gitlab Pipeline – tags – What is tags in GitLab CI/CD?</title>
		<link>https://www.bestdevops.com/gitlab-pipeline-tags-what-is-tags-in-gitlab-ci-cd/</link>
					<comments>https://www.bestdevops.com/gitlab-pipeline-tags-what-is-tags-in-gitlab-ci-cd/#respond</comments>
		
		<dc:creator><![CDATA[kumar k]]></dc:creator>
		<pubDate>Tue, 27 May 2025 19:00:12 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=31397</guid>

					<description><![CDATA[The tags keyword in a GitLab CI/CD job definition is used to specify which GitLab Runners should execute that job. [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The <code>tags</code> keyword in a GitLab CI/CD job definition is used to specify which GitLab Runners should execute that job. GitLab Runners are the agents that actually run your CI/CD tasks. When you set up a runner, you can assign it one or more tags. Then, in your <code>.gitlab-ci.yml</code>, you can specify that a job should only be executed by runners that possess certain tags.</p>



<p class="wp-block-paragraph">This allows you to:</p>



<ul class="wp-block-list">
<li>Designate specific runners for specific types of jobs (e.g., runners with Docker installed, runners on a particular OS like Windows or macOS, runners with access to specific hardware like GPUs, or runners dedicated to deployment tasks).</li>



<li>Control resource allocation and job execution environments.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Example <code>.gitlab-ci.yml</code> with <code>tags</code>:</h3>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .gitlab-ci.yml</span>

stages:
  - build
  - test
  - deploy

<span class="hljs-keyword">default</span>:
  image: alpine:latest <span class="hljs-comment"># A global default image</span>

<span class="hljs-comment"># Job 1: Requires a runner with the 'docker' tag</span>
build_with_docker_runner:
  stage: build
  tags:
    - docker <span class="hljs-comment"># This job will only be picked up by a runner that has the 'docker' tag.</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Building with a Docker-enabled runner ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This job expects the runner to have Docker capabilities."</span>
    - docker info <span class="hljs-comment"># Example command that would require Docker</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Build complete."</span>

<span class="hljs-comment"># Job 2: Requires a runner with BOTH 'linux' AND 'gpu' tags</span>
gpu_accelerated_tests:
  stage: test
  tags:
    - linux   <span class="hljs-comment"># Runner must have 'linux' tag</span>
    - gpu     <span class="hljs-comment"># AND runner must also have 'gpu' tag</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Running GPU Accelerated Tests ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This job needs a Linux runner with GPU access."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Simulating GPU-intensive computations..."</span>
    - sleep <span class="hljs-number">10</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"GPU tests complete."</span>

<span class="hljs-comment"># Job 3: No specific tags defined at the job level</span>
<span class="hljs-comment"># This job can be picked up by:</span>
<span class="hljs-comment"># 1. Runners that are configured to run untagged jobs.</span>
<span class="hljs-comment"># 2. Shared runners (if available and configured for the project) that might not require specific tags.</span>
<span class="hljs-comment"># 3. If 'default:tags:' were defined, it would use those.</span>
generic_script_job:
  stage: test
  <span class="hljs-comment"># No 'tags:' keyword here</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Running Generic Script Job ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This job has no specific tag requirements from the job definition."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"It can run on any available runner that is allowed to pick up untagged jobs for this project."</span>
    - date

<span class="hljs-comment"># Job 4: Deployment job, might target specific deployment runners</span>
deploy_to_production_server:
  stage: deploy
  tags:
    - deploy   <span class="hljs-comment"># Runner must have 'deploy' tag</span>
    - production <span class="hljs-comment"># AND runner must also have 'production' tag</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Deploying to Production ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This job must run on a secure runner designated for production deployments."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Deployment scripts would execute here."</span>
    - sleep <span class="hljs-number">5</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Deployment to production successful."</span>

</code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Explanation:</h3>



<ol class="wp-block-list">
<li><strong><code>tags:</code> Keyword:</strong>
<ul class="wp-block-list">
<li>Used within a job&#8217;s definition (e.g., <code>build_with_docker_runner</code>).</li>



<li>It takes an <strong>array of strings</strong>, where each string is a tag.</li>
</ul>
</li>



<li><strong>How Runners are Tagged (Background):</strong>
<ul class="wp-block-list">
<li>When a GitLab Runner is registered (by a GitLab administrator or a user setting up a specific runner), it can be assigned one or more tags (e.g., <code>docker</code>, <code>linux</code>, <code>windows</code>, <code>macos</code>, <code>ruby-2.7</code>, <code>gpu</code>, <code>deploy-production</code>).</li>



<li>These tags describe the capabilities or purpose of that runner.</li>
</ul>
</li>



<li><strong><code>build_with_docker_runner</code> Job:</strong>
<ul class="wp-block-list">
<li><code>tags: - docker</code>:
<ul class="wp-block-list">
<li>This job specifies that it requires a runner which has the tag <code>docker</code>.</li>



<li>Only runners that have been configured with the <code>docker</code> tag will be eligible to pick up and execute this job. This is useful if the job needs Docker to build images, run containers, etc.</li>
</ul>
</li>
</ul>
</li>



<li><strong><code>gpu_accelerated_tests</code> Job:</strong>
<ul class="wp-block-list">
<li><code>tags: - linux - gpu</code>:
<ul class="wp-block-list">
<li>This job lists multiple tags. For a runner to pick up this job, it <strong>must possess ALL the tags listed</strong> by the job.</li>



<li>So, this job requires a runner that is tagged with <code>linux</code> AND also tagged with <code>gpu</code>. A runner tagged only with <code>linux</code> (but not <code>gpu</code>) would not pick it up.</li>
</ul>
</li>
</ul>
</li>



<li><strong><code>generic_script_job</code> Job:</strong>
<ul class="wp-block-list">
<li>This job <strong>does not have a <code>tags:</code> keyword</strong>. Its behavior depends on the runner configurations for your project/instance:
<ul class="wp-block-list">
<li><strong>Untagged Runners:</strong> Runners can be configured to pick up jobs that don&#8217;t specify any tags (i.e., &#8220;run untagged jobs&#8221;). If such runners are available to your project, one of them might pick up this job.</li>



<li><strong>Shared Runners:</strong> If your project has access to shared runners provided by your GitLab instance, their configuration determines if they pick up untagged jobs.</li>



<li><strong><code>default:tags:</code>:</strong> If you had a <code>default:tags:</code> section at the top level of your <code>.gitlab-ci.yml</code>, this job would inherit those default tags.</li>
</ul>
</li>
</ul>
</li>



<li><strong><code>deploy_to_production_server</code> Job:</strong>
<ul class="wp-block-list">
<li><code>tags: - deploy - production</code>:
<ul class="wp-block-list">
<li>This illustrates a common use case for deploying to a specific environment. You would tag your production deployment runners with <code>deploy</code> and <code>production</code> to ensure only those trusted and specifically configured runners handle such critical tasks.</li>
</ul>
</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Key Concepts and Behavior:</h3>



<ul class="wp-block-list">
<li><strong>Purpose:</strong> To ensure that jobs are executed on runners that have the necessary capabilities, environment, or permissions.</li>



<li><strong>Matching Logic:</strong>
<ul class="wp-block-list">
<li>A job will only be executed by a runner if the runner has <strong>all</strong> the tags specified in the job&#8217;s <code>tags</code> list.</li>



<li>A runner can have more tags than a job specifies. As long as it has the ones the job <em>requires</em>, it&#8217;s a match. For example, a runner tagged <code>[docker, linux, fast]</code> can run a job with <code>tags: [docker, linux]</code>.</li>
</ul>
</li>



<li><strong>No Tags in Job:</strong> If a job has no <code>tags</code> defined, it can only be picked up by runners that are configured to run untagged jobs.</li>



<li><strong>Runner Configuration:</strong>
<ul class="wp-block-list">
<li>When registering a runner, you specify its tags.</li>



<li>You also configure whether a runner can pick up untagged jobs.</li>



<li>Runners can be &#8220;shared&#8221; (available to multiple projects), &#8220;group&#8221; (available to projects in a group), or &#8220;specific&#8221; (registered for a single project).</li>
</ul>
</li>



<li><strong><code>default:tags:</code>:</strong> You can set default tags for all jobs using the <code>default:</code> top-level keyword: YAML<code>default: tags: - common-runner</code> Job-level <code>tags</code> will override these defaults.</li>



<li><strong>Order of Tags:</strong> The order of tags in the <code>tags</code> list in your job definition, or on the runner, does not matter.</li>
</ul>



<p class="wp-block-paragraph">Using <code>tags</code> effectively is crucial for managing a diverse set of CI/CD tasks that may require different operating systems, software dependencies, or security contexts. It gives you precise control over where your jobs run.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/gitlab-pipeline-tags-what-is-tags-in-gitlab-ci-cd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Gitlab Pipeline – extends – What is extends in GitLab CI/CD?</title>
		<link>https://www.bestdevops.com/gitlab-pipeline-extends-what-is-extends-in-gitlab-ci-cd/</link>
					<comments>https://www.bestdevops.com/gitlab-pipeline-extends-what-is-extends-in-gitlab-ci-cd/#respond</comments>
		
		<dc:creator><![CDATA[kumar k]]></dc:creator>
		<pubDate>Tue, 27 May 2025 18:58:54 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=31394</guid>

					<description><![CDATA[The extends keyword in GitLab CI/CD allows you to reuse configuration from other job definitions or &#8220;hidden&#8221; job templates within [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The <code>extends</code> keyword in GitLab CI/CD allows you to reuse configuration from other job definitions or &#8220;hidden&#8221; job templates within your <code>.gitlab-ci.yml</code> file. This is a powerful feature for practicing DRY (Don&#8217;t Repeat Yourself) principles, making your CI/CD configuration more maintainable, consistent, and easier to manage.</p>



<p class="wp-block-paragraph">&#8220;Hidden&#8221; jobs are typically used as templates. Their names start with a dot (<code>.</code>), and they are not processed as regular jobs by GitLab CI unless explicitly extended.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Example <code>.gitlab-ci.yml</code> with <code>extends</code>:</h3>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .gitlab-ci.yml</span>

stages:
  - setup
  - test
  - build

<span class="hljs-keyword">default</span>:
  image: alpine:latest <span class="hljs-comment"># A global default image</span>

<span class="hljs-comment"># 1. Define a hidden job template for common test configurations</span>
.base_test_config:
  stage: test
  image: ruby:<span class="hljs-number">3.0</span> <span class="hljs-comment"># Specific image for test jobs</span>
  tags:
    - docker <span class="hljs-comment"># Default tags for these test jobs</span>
  variables:
    TEST_SUITE_VERSION: <span class="hljs-string">"v1.2"</span>
    RAILS_ENV: <span class="hljs-string">"test"</span>
  before_script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Base Test Config: before_script ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Setting up common test environment..."</span>
    - bundle install --jobs $(nproc) --path vendor/bundle <span class="hljs-comment"># Example common setup</span>
  script: <span class="hljs-comment"># This is a base script; jobs extending this can add more commands</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Base Test Config: script ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Running common pre-test checks..."</span>
  after_script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Base Test Config: after_script ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Cleaning up common test resources."</span>

<span class="hljs-comment"># 2. Define another hidden job template, perhaps for a specific type of test</span>
.rspec_test_template:
  extends: .base_test_config <span class="hljs-comment"># This template itself extends another one</span>
  variables:
    TEST_FRAMEWORK: <span class="hljs-string">"RSpec"</span> <span class="hljs-comment"># Overrides or adds to variables from .base_test_config</span>
  before_script: <span class="hljs-comment"># Commands here will run AFTER commands from .base_test_config's before_script</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- RSpec Template: before_script ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Setting up RSpec specific environment..."</span>
  script: <span class="hljs-comment"># Commands here will run AFTER commands from .base_test_config's script</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- RSpec Template: script ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Executing RSpec tests with framework $TEST_FRAMEWORK on Rails env $RAILS_ENV"</span>
    <span class="hljs-comment"># Placeholder for actual rspec command</span>

<span class="hljs-comment"># --- Regular Jobs using 'extends' ---</span>

<span class="hljs-comment"># Job 1: Extends the base test configuration</span>
unit_tests:
  extends: .base_test_config
  <span class="hljs-comment"># This job inherits: stage, image, tags, variables (TEST_SUITE_VERSION, RAILS_ENV),</span>
  <span class="hljs-comment"># before_script, script, and after_script from .base_test_config.</span>
  script: <span class="hljs-comment"># Commands here run AFTER the script block from .base_test_config</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Unit Tests: script ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Running unit tests for version $TEST_SUITE_VERSION..."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Actual unit test commands would go here."</span>

<span class="hljs-comment"># Job 2: Extends the RSpec template (which itself extends .base_test_config)</span>
<span class="hljs-comment"># It also overrides a variable and adds specific script commands.</span>
feature_tests_rspec:
  extends: .rspec_test_template
  variables:
    RAILS_ENV: <span class="hljs-string">"test_feature"</span> <span class="hljs-comment"># Overrides RAILS_ENV from .base_test_config (via .rspec_test_template)</span>
    SPEC_FILES: <span class="hljs-string">"spec/features"</span>
  script: <span class="hljs-comment"># Commands here run AFTER script blocks from .base_test_config AND .rspec_test_template</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Feature Tests (RSpec): script ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Running RSpec feature tests from $SPEC_FILES on Rails env $RAILS_ENV"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Test Suite version: $TEST_SUITE_VERSION, Framework: $TEST_FRAMEWORK"</span>
    - bundle exec rspec $SPEC_FILES <span class="hljs-comment"># Example actual command</span>

<span class="hljs-comment"># Job 3: Extends the base but completely overrides its 'script' and 'before_script'</span>
<span class="hljs-comment"># while keeping other things like image and variables.</span>
custom_setup_test:
  extends: .base_test_config
  before_script: <span class="hljs-comment"># This completely replaces .base_test_config's before_script</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Custom Setup Test: entirely new before_script ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Performing a very different setup."</span>
  script: <span class="hljs-comment"># This completely replaces .base_test_config's script</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Custom Setup Test: entirely new script ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Running tests with custom setup. RAILS_ENV is $RAILS_ENV."</span>

<span class="hljs-comment"># Job 4: Example of a non-test job, not using extends</span>
<span class="hljs-comment"># This job will use the global default image 'alpine:latest'</span>
build_documentation:
  stage: build
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Building documentation..."</span>
    - mkdir <span class="hljs-keyword">public</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Docs built"</span> &gt; <span class="hljs-keyword">public</span>/index.html
  artifacts:
    paths:
      - <span class="hljs-keyword">public</span></code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Explanation:</h3>



<ol class="wp-block-list">
<li><strong>Hidden Job Templates (<code>.</code> prefix):</strong>
<ul class="wp-block-list">
<li>Jobs like <code>.base_test_config</code> and <code>.rspec_test_template</code> start with a dot (<code>.</code>). This makes them &#8220;hidden&#8221; jobs.</li>



<li>Hidden jobs are not run directly as part of your pipeline. They serve as templates that other regular jobs can inherit from using the <code>extends</code> keyword.</li>
</ul>
</li>



<li><strong><code>extends:</code> Keyword:</strong>
<ul class="wp-block-list">
<li>Used within a job definition to specify one or more template jobs whose configurations should be inherited.</li>



<li><code>extends: .base_test_config</code> means the <code>unit_tests</code> job will inherit all configurations from <code>.base_test_config</code>.</li>



<li><code>extends: .rspec_test_template</code> means <code>feature_tests_rspec</code> inherits from <code>.rspec_test_template</code>. Since <code>.rspec_test_template</code> itself extends <code>.base_test_config</code>, <code>feature_tests_rspec</code> effectively inherits from both, with <code>.rspec_test_template</code>&#8216;s definitions taking precedence over <code>.base_test_config</code> where there are overlaps, and then <code>feature_tests_rspec</code>&#8216;s own definitions taking precedence over both.</li>
</ul>
</li>



<li><strong>Merge Strategy (How Inheritance Works):</strong><br>GitLab performs a &#8220;deep merge&#8221; of the configurations. The specific job&#8217;s configurations always take precedence over what&#8217;s inherited.
<ul class="wp-block-list">
<li><strong>Scalars (single values like <code>image</code>, <code>stage</code>):</strong> The value from the extending job (the most specific one) is used. If the extending job doesn&#8217;t define it, the value from the template is used.</li>



<li><strong>Hashes (key-value pairs like <code>variables</code>):</strong> They are merged. If both the template and the extending job define the same variable key, the value from the <strong>extending job</strong> (the most specific one) wins. New variables from either are included.
<ul class="wp-block-list">
<li>Example: <code>.base_test_config</code> defines <code>RAILS_ENV: "test"</code>. <code>feature_tests_rspec</code> defines <code>RAILS_ENV: "test_feature"</code>. So, <code>feature_tests_rspec</code> will use <code>test_feature</code>.</li>
</ul>
</li>



<li><strong>Arrays (lists like <code>script</code>, <code>before_script</code>, <code>after_script</code>, <code>tags</code>):</strong>
<ul class="wp-block-list">
<li><strong><code>script</code></strong>: Commands from the extended template&#8217;s <code>script</code> are executed <strong>before</strong> the commands in the extending job&#8217;s <code>script</code>. They are effectively prepended.</li>



<li><strong><code>before_script</code></strong>: Commands from the extended template&#8217;s <code>before_script</code> are executed <strong>before</strong> the commands in the extending job&#8217;s <code>before_script</code>. They are prepended.</li>



<li><strong><code>after_script</code></strong>: Commands from the extended template&#8217;s <code>after_script</code> are executed <strong>before</strong> the commands in the extending job&#8217;s <code>after_script</code>. They are prepended.</li>



<li><strong><code>tags</code></strong>: The <code>tags</code> array from the extending job <strong>replaces</strong> the <code>tags</code> array from the template.</li>



<li><strong>Important Exception:</strong> If an extending job redefines <code>script</code>, <code>before_script</code>, or <code>after_script</code> completely (as shown in <code>custom_setup_test</code>), the template&#8217;s corresponding script block is <strong>not</strong> prepended; the job&#8217;s definition entirely replaces it for that specific script block. To achieve prepending, the job must also include the script keywords from the template if it wants to re-define only parts, which <code>extends</code> handles implicitly for these script arrays if the job <em>also</em> has a script section. <em>Correction based on typical CI behavior:</em> For <code>script</code>, <code>before_script</code>, and <code>after_script</code>, GitLab CI <strong>prepends</strong> the inherited script content to the specific job&#8217;s script content. If you want to completely override, you&#8217;d typically need to ensure the template doesn&#8217;t have that script section, or you are actually replacing a more deeply nested script. However, the common understanding and use of <code>extends</code> with these script arrays is that the inherited commands run, then the specific job&#8217;s commands run. My example <code>custom_setup_test</code> reflects this prepending for <code>before_script</code> and <code>script</code>.</li>



<li><em>Self-correction for clarity:</em> The most accurate way to describe <code>script</code>, <code>before_script</code>, and <code>after_script</code> merging with <code>extends</code> is: the commands from the extended configuration are executed, <em>then</em> the commands from the current job&#8217;s configuration for that same key are executed. They are effectively combined in sequence.</li>
</ul>
</li>
</ul>
</li>



<li><strong><code>unit_tests</code> Job:</strong>
<ul class="wp-block-list">
<li>Inherits <code>stage: test</code>, <code>image: ruby:3.0</code>, <code>tags</code>, <code>variables</code>, the <code>before_script</code>, the initial <code>script</code> part, and <code>after_script</code> from <code>.base_test_config</code>.</li>



<li>Its own <code>script</code> block adds more commands that run <em>after</em> the <code>script</code> block from <code>.base_test_config</code>.</li>
</ul>
</li>



<li><strong><code>feature_tests_rspec</code> Job:</strong>
<ul class="wp-block-list">
<li>Inherits from <code>.rspec_test_template</code>.</li>



<li><code>.rspec_test_template</code> first inherits from <code>.base_test_config</code>.</li>



<li>Then, <code>.rspec_test_template</code>&#8216;s own definitions (like <code>TEST_FRAMEWORK: "RSpec"</code> and its <code>before_script</code> and <code>script</code>) are merged.</li>



<li>Finally, <code>feature_tests_rspec</code>&#8216;s own definitions (like <code>RAILS_ENV: "test_feature"</code> and its <code>script</code>) are merged, taking highest precedence.</li>



<li>The <code>before_script</code> commands will run in order: <code>.base_test_config</code>&#8216;s -> <code>.rspec_test_template</code>&#8216;s.</li>



<li>The <code>script</code> commands will run in order: <code>.base_test_config</code>&#8216;s -> <code>.rspec_test_template</code>&#8216;s -> <code>feature_tests_rspec</code>&#8216;s.</li>
</ul>
</li>



<li><strong><code>custom_setup_test</code> Job:</strong>
<ul class="wp-block-list">
<li>This job extends <code>.base_test_config</code> but provides its <em>own complete</em> <code>before_script</code> and <code>script</code> definitions. In this case, for these specific keys, the definitions from <code>.base_test_config</code> are <em>prepended</em> to the definitions in <code>custom_setup_test</code>.</li>



<li><em>Correction/Clarification:</em> If a job defines <code>script</code> and extends a template that also defines <code>script</code>, the inherited script runs, then the job&#8217;s script runs. The example above where I said it &#8220;replaces&#8221; was slightly off for these script arrays; the behavior is more like chaining.</li>
</ul>
</li>



<li><strong>Extending Multiple Templates:</strong>
<ul class="wp-block-list">
<li>You can extend multiple templates: <code>extends: [.template_A, .template_B]</code>.</li>



<li>Configurations are merged from left to right. <code>.template_B</code>&#8216;s values would override <code>.template_A</code>&#8216;s if there are conflicts, and then the current job&#8217;s values override anything from the templates.</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Benefits of <code>extends</code>:</h3>



<ul class="wp-block-list">
<li><strong>DRY (Don&#8217;t Repeat Yourself):</strong> Reduces a lot of boilerplate and repeated configuration.</li>



<li><strong>Consistency:</strong> Ensures common settings (like Docker images, setup scripts, tags) are applied consistently across similar jobs.</li>



<li><strong>Maintainability:</strong> If you need to change a common setting (e.g., update a Docker image version), you only need to change it in the template, and all jobs extending it will get the update.</li>



<li><strong>Readability:</strong> Job definitions become shorter and focus on what&#8217;s unique to them.</li>
</ul>



<p class="wp-block-paragraph"><code>extends</code> is a very powerful tool for organizing your GitLab CI/CD configurations, especially as your pipelines grow in complexity. It&#8217;s preferred over older YAML anchor/alias methods for CI configurations because <code>extends</code> performs a more intelligent &#8220;deep merge&#8221; suitable for CI job structures.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/gitlab-pipeline-extends-what-is-extends-in-gitlab-ci-cd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Gitlab Pipeline – trigger – What is trigger in GitLab CI/CD?</title>
		<link>https://www.bestdevops.com/gitlab-pipeline-trigger-what-is-trigger-in-gitlab-ci-cd/</link>
					<comments>https://www.bestdevops.com/gitlab-pipeline-trigger-what-is-trigger-in-gitlab-ci-cd/#respond</comments>
		
		<dc:creator><![CDATA[kumar k]]></dc:creator>
		<pubDate>Tue, 27 May 2025 18:56:55 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=31392</guid>

					<description><![CDATA[Okay, here&#8217;s a basic GitLab CI/CD YAML example that demonstrates how the trigger configuration option is used, focusing on creating [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Okay, here&#8217;s a basic GitLab CI/CD YAML example that demonstrates how the <code>trigger</code> configuration option is used, focusing on creating <strong>parent-child pipelines</strong> within the same project. This is a common way to break down complex CI/CD logic into more manageable pieces.</p>



<p class="wp-block-paragraph">The <code>trigger</code> keyword allows a job in your main <code>.gitlab-ci.yml</code> (the parent pipeline) to initiate a new, separate pipeline (the child pipeline) based on another YAML file within the same project or even in a different project (multi-project pipelines).</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Example Files:</h3>



<p class="wp-block-paragraph">You&#8217;ll need two YAML files in your repository for this example:</p>



<ol class="wp-block-list">
<li><strong><code>.gitlab-ci.yml</code></strong> (The main/parent pipeline configuration)</li>



<li><strong><code>.child-pipeline.yml</code></strong> (The configuration for the child pipeline)</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading">File 1: <code>.gitlab-ci.yml</code> (Parent Pipeline)</h4>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .gitlab-ci.yml</span>

stages:
  - setup
  - build_and_trigger
  - deploy <span class="hljs-comment"># This stage might run jobs from the parent or child</span>

<span class="hljs-keyword">default</span>:
  image: alpine:latest

<span class="hljs-comment"># A regular job in the parent pipeline</span>
prepare_environment:
  stage: setup
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Parent Pipeline: Preparing Environment ---"</span>
    - export PARENT_VARIABLE=<span class="hljs-string">"Hello from Parent"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Parent variable set."</span>

<span class="hljs-comment"># This job triggers a child pipeline defined in another YAML file</span>
trigger_build_services_pipeline:
  stage: build_and_trigger
  <span class="hljs-comment"># 'trigger' keyword starts the definition for a downstream pipeline</span>
  trigger:
    <span class="hljs-keyword">include</span>: <span class="hljs-string">'.child-pipeline.yml'</span> <span class="hljs-comment"># Path to the child pipeline's YAML configuration in THIS project</span>
    strategy: depend <span class="hljs-comment"># The trigger job will mirror the status of the child pipeline.</span>
                     <span class="hljs-comment"># If the child pipeline succeeds, this job succeeds. If it fails, this job fails.</span>
    forward_pipeline_variables: <span class="hljs-keyword">true</span> <span class="hljs-comment"># Forwards predefined CI variables (like CI_COMMIT_REF_NAME) to the child.</span>
    forward_yaml_variables: <span class="hljs-keyword">true</span> <span class="hljs-comment"># Forwards variables defined in this parent YAML (like PARENT_VARIABLE if it was global or job level)</span>
                                  <span class="hljs-comment"># <span class="hljs-doctag">Note:</span> For variables defined in the 'script' like PARENT_VARIABLE above,</span>
                                  <span class="hljs-comment"># you'd typically pass them explicitly using 'trigger:variables:'.</span>
  variables: <span class="hljs-comment"># Explicitly pass variables to the child pipeline</span>
    PASSED_FROM_PARENT: <span class="hljs-string">"This data comes from the trigger job"</span>
    ANOTHER_PARENT_VAR: <span class="hljs-string">"Value_XYZ"</span>
  script: <span class="hljs-comment"># This script runs BEFORE the trigger actually happens.</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Parent Pipeline: About to trigger child pipeline for building services ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This job will now trigger and wait for .child-pipeline.yml"</span>

<span class="hljs-comment"># Another job in the parent pipeline that might run after the trigger job (if strategy:depend is used)</span>
<span class="hljs-comment"># or in parallel if it's in the same stage and doesn't depend on the trigger job.</span>
parent_final_step:
  stage: deploy
  needs: &#91;<span class="hljs-string">"trigger_build_services_pipeline"</span>] <span class="hljs-comment"># Make this explicitly depend on the trigger job</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Parent Pipeline: Final Step ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This runs after the child pipeline (triggered by 'trigger_build_services_pipeline') completes successfully."</span>

</code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading">File 2: <code>.child-pipeline.yml</code> (Child Pipeline Configuration)</h4>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .child-pipeline.yml</span>

<span class="hljs-comment"># This file defines the jobs that will run in the child pipeline.</span>
<span class="hljs-comment"># It can have its own stages, jobs, variables, etc.</span>

<span class="hljs-keyword">default</span>:
  image: alpine:latest

stages:
  - build_child
  - test_child

variables:
  CHILD_PIPELINE_VAR: <span class="hljs-string">"Specific to Child Pipeline"</span>

build_service_a:
  stage: build_child
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Child Pipeline: Building Service A ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Accessing variable passed from parent: $PASSED_FROM_PARENT"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Accessing another parent var: $ANOTHER_PARENT_VAR"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Accessing child-specific variable: $CHILD_PIPELINE_VAR"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Accessing forwarded predefined variable (e.g., branch): $CI_COMMIT_REF_NAME"</span>
    - sleep <span class="hljs-number">10</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Service A built."</span>
  artifacts:
    paths:
      - service_a.txt
    expire_in: <span class="hljs-number">1</span> hour

test_service_a:
  stage: test_child
  needs: &#91;<span class="hljs-string">"build_service_a"</span>] <span class="hljs-comment"># Child pipeline can also use 'needs'</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Child Pipeline: Testing Service A ---"</span>
    - <span class="hljs-keyword">if</span> &#91; -f <span class="hljs-string">"service_a.txt"</span> ]; then <span class="hljs-keyword">echo</span> <span class="hljs-string">"Artifact from child build_service_a found."</span>; <span class="hljs-keyword">else</span> <span class="hljs-keyword">echo</span> <span class="hljs-string">"Artifact NOT found!"</span>; <span class="hljs-keyword">exit</span> <span class="hljs-number">1</span>; fi
    - sleep <span class="hljs-number">5</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Service A tests passed."</span>

</code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Explanation:</h3>



<ol class="wp-block-list">
<li><strong><code>trigger:</code> Keyword (in <code>.gitlab-ci.yml</code>):</strong>
<ul class="wp-block-list">
<li>Used within a job (<code>trigger_build_services_pipeline</code> in this case) to initiate a downstream (child) pipeline.</li>



<li><strong><code>include: '.child-pipeline.yml'</code></strong>:
<ul class="wp-block-list">
<li>This specifies that the child pipeline&#8217;s configuration is defined in the <code>.child-pipeline.yml</code> file located in the <strong>same project and same Git ref</strong> (branch/commit) as the parent pipeline. This is the core of a &#8220;parent-child pipeline.&#8221;</li>
</ul>
</li>



<li><strong><code>strategy: depend</code></strong>:
<ul class="wp-block-list">
<li>(Optional, but very common) This makes the parent trigger job (<code>trigger_build_services_pipeline</code>) wait for the entire child pipeline to complete.</li>



<li>The status of the trigger job will then mirror the status of the child pipeline. If the child pipeline succeeds, the trigger job succeeds. If the child pipeline fails, the trigger job fails.</li>



<li>Without <code>strategy: depend</code> (or if set to <code>strategy: none</code>), the trigger job would be marked as successful as soon as it successfully <em>initiates</em> the child pipeline, without waiting for it to finish.</li>
</ul>
</li>



<li><strong><code>forward_pipeline_variables: true</code></strong>:
<ul class="wp-block-list">
<li>(Optional) Forwards most of the predefined CI/CD variables (like <code>CI_COMMIT_SHA</code>, <code>CI_COMMIT_REF_NAME</code>, <code>CI_PROJECT_DIR</code>, etc.) from the parent pipeline to the child pipeline.</li>
</ul>
</li>



<li><strong><code>forward_yaml_variables: true</code></strong>:
<ul class="wp-block-list">
<li>(Optional) Forwards variables defined in the parent YAML (global <code>variables:</code> block or job-level <code>variables:</code> block of the trigger job) to the child pipeline.</li>



<li><strong>Note:</strong> Variables set dynamically within a <code>script</code> block of the trigger job (like <code>PARENT_VARIABLE</code> in <code>prepare_environment</code>) are not automatically forwarded by this. For those, you need to pass them explicitly.</li>
</ul>
</li>



<li><strong><code>variables:</code> (under <code>trigger:</code>):</strong>
<ul class="wp-block-list">
<li>This block allows you to explicitly pass new variables or override existing ones to the child pipeline.</li>



<li><code>PASSED_FROM_PARENT: "This data comes from the trigger job"</code>: This variable will be available in all jobs of the triggered child pipeline.</li>
</ul>
</li>



<li><strong><code>script:</code> (in the trigger job):</strong>
<ul class="wp-block-list">
<li>Any commands in the <code>script</code> section of the trigger job are executed <em>before</em> the downstream pipeline is actually triggered. This can be used for setup or logging.</li>
</ul>
</li>
</ul>
</li>



<li><strong><code>.child-pipeline.yml</code> (Child Pipeline):</strong>
<ul class="wp-block-list">
<li>This is a standard GitLab CI/CD YAML file. It defines its own <code>stages</code>, <code>jobs</code>, <code>variables</code>, etc.</li>



<li>It runs in the context of the same project, commit, and Git ref as the parent pipeline that triggered it.</li>



<li><strong>Accessing Variables:</strong> Jobs in the child pipeline (like <code>build_service_a</code>) can access:
<ul class="wp-block-list">
<li>Variables explicitly passed via <code>trigger:variables:</code> (e.g., <code>$PASSED_FROM_PARENT</code>).</li>



<li>Forwarded predefined variables (if <code>forward_pipeline_variables: true</code>).</li>



<li>Forwarded YAML variables from the parent (if <code>forward_yaml_variables: true</code>).</li>



<li>Its own globally or job-level defined variables (e.g., <code>$CHILD_PIPELINE_VAR</code>).</li>
</ul>
</li>



<li><strong>Artifacts in Child Pipeline:</strong> Jobs in the child pipeline can produce artifacts. These artifacts are scoped to the child pipeline. If the parent pipeline (or other pipelines) needs these, you would typically use <code>needs:</code> with <code>project</code> and <code>job</code> attributes to fetch artifacts from a completed child pipeline job (this is more of an advanced multi-project artifact passing scenario). For parent-child, if <code>strategy: depend</code> is used, the trigger job itself can have artifacts from the child if the child pipeline is configured to produce artifacts that are then &#8220;passed up&#8221; (this is a more nuanced behavior that depends on GitLab version and configuration). Usually, artifacts from the child are used within the child pipeline itself or by downstream multi-project pipelines.</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Key Concepts and Benefits:</h3>



<ul class="wp-block-list">
<li><strong>Modularity:</strong> Break down a very large, monolithic <code>.gitlab-ci.yml</code> into smaller, more focused YAML files. This improves readability and maintainability.</li>



<li><strong>Reusability:</strong> Child pipeline configurations can potentially be reused or triggered by multiple parent pipelines or different trigger jobs.</li>



<li><strong>Dynamic Pipeline Generation:</strong> You can dynamically choose which child pipeline to trigger based on conditions in the parent.</li>



<li><strong>Isolation:</strong> Child pipelines can have their own stages and flow, providing some level of isolation.</li>



<li><strong>Multi-Project Pipelines (Brief Mention):</strong>
<ul class="wp-block-list">
<li>Instead of <code>trigger:include:</code>, you can use <code>trigger:project: 'namespace/another-project'</code> and <code>trigger:branch: 'some-branch'</code> to trigger a pipeline in a completely different GitLab project. This is useful for microservice architectures or when coordinating deployments across multiple repositories.</li>
</ul>
</li>
</ul>



<h3 class="wp-block-heading">How it Looks in the UI:</h3>



<ul class="wp-block-list">
<li>The trigger job in the parent pipeline will show a link to the downstream (child) pipeline.</li>



<li>If <code>strategy: depend</code> is used, the trigger job will remain in a &#8220;running&#8221; state until the child pipeline completes, and then its status will reflect the child&#8217;s status.</li>
</ul>



<p class="wp-block-paragraph">Using <code>trigger</code> for parent-child pipelines is a great way to manage complexity as your CI/CD processes grow.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/gitlab-pipeline-trigger-what-is-trigger-in-gitlab-ci-cd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Gitlab Pipeline – parrallel – What is parrallel in GitLab CI/CD?</title>
		<link>https://www.bestdevops.com/gitlab-pipeline-parrallel-what-is-parrallel-in-gitlab-ci-cd/</link>
					<comments>https://www.bestdevops.com/gitlab-pipeline-parrallel-what-is-parrallel-in-gitlab-ci-cd/#respond</comments>
		
		<dc:creator><![CDATA[kumar k]]></dc:creator>
		<pubDate>Tue, 27 May 2025 18:54:58 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=31389</guid>

					<description><![CDATA[The parallel keyword in a GitLab CI/CD job definition allows you to run multiple instances of the same job concurrently. [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The <code>parallel</code> keyword in a GitLab CI/CD job definition allows you to run multiple instances of the same job concurrently. This is extremely useful for:</p>



<ul class="wp-block-list">
<li><strong>Speeding up test suites:</strong> By splitting tests across several parallel jobs (test sharding/splitting).</li>



<li><strong>Building for multiple targets/architectures:</strong> Running the same build script with different configuration variables.</li>



<li><strong>Processing data in chunks:</strong> Dividing a large dataset or a list of items among parallel jobs.</li>
</ul>



<p class="wp-block-paragraph">GitLab provides two main ways to use <code>parallel</code>:</p>



<ol class="wp-block-list">
<li><strong>Fixed number of parallel jobs:</strong> <code>parallel: &lt;number></code></li>



<li><strong>Matrix of parallel jobs:</strong> <code>parallel:matrix:</code> (using variable combinations)</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Example <code>.gitlab-ci.yml</code> with <code>parallel</code>:</h3>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .gitlab-ci.yml</span>

stages:
  - test
  - build

<span class="hljs-keyword">default</span>:
  image: alpine:latest

<span class="hljs-comment"># Job 1: Demonstrates a fixed number of parallel jobs for sharding tests</span>
parallel_test_execution:
  stage: test
  parallel: <span class="hljs-number">3</span> <span class="hljs-comment"># Run this job 3 times in parallel</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Parallel Test Execution ---"</span>
    <span class="hljs-comment"># CI_NODE_INDEX is 1-based (e.g., 1, 2, 3)</span>
    <span class="hljs-comment"># CI_NODE_TOTAL is the total number of parallel jobs (e.g., 3)</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This is test job instance $CI_NODE_INDEX of $CI_NODE_TOTAL."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Simulating test execution for a subset of tests..."</span>
    <span class="hljs-comment"># Example: Logic to select a subset of tests based on CI_NODE_INDEX</span>
    - |
      <span class="hljs-keyword">if</span> &#91; <span class="hljs-string">"$CI_NODE_INDEX"</span> -eq <span class="hljs-number">1</span> ]; then
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Running test group 1 (e.g., unit tests part 1)"</span>
        sleep <span class="hljs-number">5</span>
      elif &#91; <span class="hljs-string">"$CI_NODE_INDEX"</span> -eq <span class="hljs-number">2</span> ]; then
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Running test group 2 (e.g., unit tests part 2)"</span>
        sleep <span class="hljs-number">7</span>
      elif &#91; <span class="hljs-string">"$CI_NODE_INDEX"</span> -eq <span class="hljs-number">3</span> ]; then
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Running test group 3 (e.g., integration tests part 1)"</span>
        sleep <span class="hljs-number">6</span>
      fi
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Test instance $CI_NODE_INDEX finished."</span>

<span class="hljs-comment"># Job 2: Demonstrates a matrix of parallel jobs for different configurations</span>
build_multi_target:
  stage: build
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Building for Target: $TARGET_OS, Arch: $TARGET_ARCH ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This is job instance $CI_NODE_INDEX of $CI_NODE_TOTAL in the matrix."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Fetching dependencies for $TARGET_OS-$TARGET_ARCH..."</span>
    - sleep <span class="hljs-number">10</span> <span class="hljs-comment"># Simulate build time</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Build complete for $TARGET_OS-$TARGET_ARCH."</span>
    - mkdir -p <span class="hljs-string">"build_output/${TARGET_OS}_${TARGET_ARCH}"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"binary_for_${TARGET_OS}_${TARGET_ARCH}"</span> &gt; <span class="hljs-string">"build_output/${TARGET_OS}_${TARGET_ARCH}/app"</span>
  parallel:
    matrix:
      <span class="hljs-comment"># First set of combinations</span>
      - TARGET_OS: &#91;<span class="hljs-string">"linux"</span>, <span class="hljs-string">"windows"</span>]
        TARGET_ARCH: &#91;<span class="hljs-string">"amd64"</span>]
      <span class="hljs-comment"># Second set of combinations (can have different variables or values)</span>
      - TARGET_OS: &#91;<span class="hljs-string">"darwin"</span>]
        TARGET_ARCH: &#91;<span class="hljs-string">"amd64"</span>, <span class="hljs-string">"arm64"</span>]
      <span class="hljs-comment"># A single specific combination</span>
      - TARGET_OS: &#91;<span class="hljs-string">"linux"</span>]
        TARGET_ARCH: &#91;<span class="hljs-string">"arm64"</span>]
        EXTRA_FLAG: &#91;<span class="hljs-string">"--optimized"</span>] <span class="hljs-comment"># You can add other variables</span>
  artifacts:
    paths:
      - build_output/
    expire_in: <span class="hljs-number">1</span> hour

</code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Explanation:</h3>



<ol class="wp-block-list">
<li><strong><code>parallel:</code> Keyword:</strong>
<ul class="wp-block-list">
<li>Used within a job&#8217;s definition to specify that the job should be run multiple times in parallel.</li>
</ul>
</li>



<li><strong><code>parallel_test_execution</code> Job (Fixed Number):</strong>
<ul class="wp-block-list">
<li><strong><code>parallel: 3</code></strong>:
<ul class="wp-block-list">
<li>This tells GitLab to create and run <strong>3 instances</strong> of the <code>parallel_test_execution</code> job concurrently (assuming enough runners are available).</li>



<li>In the GitLab UI, these jobs will appear as <code>parallel_test_execution 1/3</code>, <code>parallel_test_execution 2/3</code>, and <code>parallel_test_execution 3/3</code>.</li>
</ul>
</li>



<li><strong>Predefined CI/CD Variables:</strong>
<ul class="wp-block-list">
<li><strong><code>$CI_NODE_INDEX</code></strong>: A 1-based index for the current parallel job instance (e.g., 1, 2, or 3 in this case).</li>



<li><strong><code>$CI_NODE_TOTAL</code></strong>: The total number of parallel jobs in this set (e.g., 3 in this case).</li>
</ul>
</li>



<li><strong>Script Logic:</strong> The script uses <code>$CI_NODE_INDEX</code> to simulate running different groups of tests. This is a common pattern for test sharding, where a large test suite is divided among parallel jobs to reduce overall execution time.</li>
</ul>
</li>



<li><strong><code>build_multi_target</code> Job (Matrix):</strong>
<ul class="wp-block-list">
<li><strong><code>parallel:matrix:</code></strong>: This allows you to define a list of variable combinations. GitLab will create a separate parallel job instance for each unique combination.</li>



<li><strong>Variable Combinations:</strong>
<ul class="wp-block-list">
<li>The first matrix entry: YAML<code>- TARGET_OS: ["linux", "windows"] TARGET_ARCH: ["amd64"]</code> This will generate 2 jobs:
<ol class="wp-block-list">
<li><code>TARGET_OS=linux</code>, <code>TARGET_ARCH=amd64</code></li>



<li><code>TARGET_OS=windows</code>, <code>TARGET_ARCH=amd64</code></li>
</ol>
</li>



<li>The second matrix entry: YAML<code>- TARGET_OS: ["darwin"] TARGET_ARCH: ["amd64", "arm64"]</code> This will generate 2 more jobs:
<ol class="wp-block-list">
<li><code>TARGET_OS=darwin</code>, <code>TARGET_ARCH=amd64</code></li>



<li><code>TARGET_OS=darwin</code>, <code>TARGET_ARCH=arm64</code></li>
</ol>
</li>



<li>The third matrix entry: YAML<code>- TARGET_OS: ["linux"] TARGET_ARCH: ["arm64"] EXTRA_FLAG: ["--optimized"]</code> This generates 1 job:
<ol class="wp-block-list">
<li><code>TARGET_OS=linux</code>, <code>TARGET_ARCH=arm64</code>, <code>EXTRA_FLAG=--optimized</code></li>
</ol>
</li>



<li><strong>Total Jobs:</strong> In this example, the <code>build_multi_target</code> job with this matrix configuration would generate 2 + 2 + 1 = <strong>5 parallel job instances</strong>. Each instance will have the specified environment variables (<code>TARGET_OS</code>, <code>TARGET_ARCH</code>, <code>EXTRA_FLAG</code>) set accordingly.</li>
</ul>
</li>



<li><strong>Script Logic:</strong> The script uses these environment variables (e.g., <code>$TARGET_OS</code>, <code>$TARGET_ARCH</code>) to perform actions specific to that combination, like building for a particular operating system and architecture.</li>



<li><strong>Artifacts:</strong> Each parallel job instance can produce its own artifacts. The example shows creating artifacts specific to the build target.</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Key Concepts and Behavior:</h3>



<ul class="wp-block-list">
<li><strong>Purpose:</strong> To significantly speed up pipelines by running identical or similar tasks concurrently or to build/test across a range of configurations.</li>



<li><strong>Runner Availability:</strong> The actual level of parallelism depends on the number of available GitLab Runners that can pick up these jobs. If you define <code>parallel: 10</code> but only have 2 runners available, only 2 jobs will run at a time.</li>



<li><strong>Job Naming:</strong>
<ul class="wp-block-list">
<li>For <code>parallel: &lt;number></code>, jobs are named <code>job_name X/Y</code>.</li>



<li>For <code>parallel:matrix:</code>, jobs are typically named <code>job_name: [VAR1:value1, VAR2:value2, ...]</code> and also include the <code>X/Y</code> suffix based on their order in the expanded matrix.</li>
</ul>
</li>



<li><strong><code>CI_NODE_INDEX</code> and <code>CI_NODE_TOTAL</code>:</strong> These are crucial for dividing work among the parallel instances, especially when using <code>parallel: &lt;number></code>. For <code>parallel:matrix:</code>, you typically rely on the matrix variables themselves to differentiate the work.</li>



<li><strong>Resource Consumption:</strong> Using <code>parallel</code> can consume more CI/CD minutes and runner resources, so use it judiciously where the speed benefits outweigh the costs.</li>



<li><strong>Dependencies and Artifacts:</strong> Each parallel job instance is treated as a separate job. If other jobs <code>need</code> a parallelized job, they would typically need <em>all</em> instances to complete (unless you specifically <code>need</code> a particular instance, which is more advanced). Artifacts from parallel jobs are usually named uniquely or aggregated in a later stage.</li>
</ul>



<p class="wp-block-paragraph">Using <code>parallel</code> effectively can drastically improve the efficiency of your CI/CD pipelines, especially for time-consuming tasks like extensive test suites or multi-platform builds.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/gitlab-pipeline-parrallel-what-is-parrallel-in-gitlab-ci-cd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Gitlab Pipeline – allow_failure – What is allow_failure in GitLab CI/CD?</title>
		<link>https://www.bestdevops.com/gitlab-pipeline-allow_failure-what-is-allow_failure-in-gitlab-ci-cd/</link>
					<comments>https://www.bestdevops.com/gitlab-pipeline-allow_failure-what-is-allow_failure-in-gitlab-ci-cd/#respond</comments>
		
		<dc:creator><![CDATA[kumar k]]></dc:creator>
		<pubDate>Tue, 27 May 2025 18:53:22 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=31386</guid>

					<description><![CDATA[Okay, here&#8217;s a basic GitLab CI/CD YAML (.gitlab-ci.yml) example that demonstrates how the allow_failure configuration option is used, along with [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Okay, here&#8217;s a basic GitLab CI/CD YAML (<code>.gitlab-ci.yml</code>) example that demonstrates how the <code>allow_failure</code> configuration option is used, along with an explanation.</p>



<p class="wp-block-paragraph">The <code>allow_failure</code> keyword in a GitLab CI/CD job definition specifies whether a pipeline should continue running and potentially be marked as successful even if that particular job fails. By default, if any job fails, the entire pipeline is marked as failed, and subsequent stages are typically not executed.</p>



<p class="wp-block-paragraph">This is useful for:</p>



<ul class="wp-block-list">
<li>Non-critical jobs like code quality checks, linters, or experimental tests whose failure shouldn&#8217;t block the main deployment flow.</li>



<li>Jobs that deploy to non-critical environments.</li>



<li>Informational scripts.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Example <code>.gitlab-ci.yml</code> with <code>allow_failure</code>:</h3>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .gitlab-ci.yml</span>

stages:
  - build
  - test
  - deploy

<span class="hljs-keyword">default</span>:
  image: alpine:latest

<span class="hljs-comment"># Job 1: A standard build job that should succeed</span>
build_application:
  stage: build
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Building Application ---"</span>
    - sleep <span class="hljs-number">5</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Application build successful."</span>
    - mkdir -p app_binaries
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"my_app_v1"</span> &gt; app_binaries/app

<span class="hljs-comment"># Job 2: A critical test job. If this fails, the pipeline should reflect a problem.</span>
critical_unit_tests:
  stage: test
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Running Critical Unit Tests ---"</span>
    - sleep <span class="hljs-number">8</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Critical unit tests PASSED."</span>
    <span class="hljs-comment"># To see a pipeline failure, uncomment the next line:</span>
    <span class="hljs-comment"># - echo "Simulating critical test failure!"; exit 1</span>

<span class="hljs-comment"># Job 3: A non-critical or "flaky" test job that is allowed to fail</span>
<span class="hljs-comment"># without stopping the pipeline or marking the pipeline as failed overall (if other critical jobs pass).</span>
non_critical_lint_check:
  stage: test
  allow_failure: <span class="hljs-keyword">true</span> <span class="hljs-comment"># This is the key configuration</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Running Non-Critical Lint Check ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Checking code style..."</span>
    - sleep <span class="hljs-number">3</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Lint check found some non-critical style issues and will 'fail'."</span>
    - <span class="hljs-keyword">exit</span> <span class="hljs-number">1</span> <span class="hljs-comment"># Simulate a failure for this non-critical job</span>

<span class="hljs-comment"># Job 4: Another non-critical job (e.g., an optional test suite)</span>
<span class="hljs-comment"># This also uses allow_failure and will demonstrate that the pipeline continues.</span>
experimental_feature_test:
  stage: test
  allow_failure: <span class="hljs-keyword">true</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Testing Experimental Feature (allowed to fail) ---"</span>
    - sleep <span class="hljs-number">4</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Experimental feature test completed (simulating success for this one, but could fail)."</span>
    - <span class="hljs-keyword">exit</span> <span class="hljs-number">0</span>

<span class="hljs-comment"># Job 5: Deployment job.</span>
<span class="hljs-comment"># This job will run if 'build_application' and 'critical_unit_tests' succeed,</span>
<span class="hljs-comment"># even if 'non_critical_lint_check' failed, because it was allowed to fail.</span>
deploy_to_staging:
  stage: deploy
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Deploying to Staging ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Checking if critical tests passed before deploying..."</span>
    - <span class="hljs-keyword">if</span> &#91; -f <span class="hljs-string">"app_binaries/app"</span> ]; then <span class="hljs-keyword">echo</span> <span class="hljs-string">"App binary found."</span>; <span class="hljs-keyword">else</span> <span class="hljs-keyword">echo</span> <span class="hljs-string">"App binary NOT found! Build might have issues."</span>; <span class="hljs-keyword">exit</span> <span class="hljs-number">1</span>; fi
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Deploying application to staging environment..."</span>
    - sleep <span class="hljs-number">10</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Deployment to staging successful."</span>
  <span class="hljs-comment"># This job depends on the success of prior stages' critical jobs.</span>
  <span class="hljs-comment"># If 'critical_unit_tests' failed (and didn't have allow_failure: true),</span>
  <span class="hljs-comment"># this 'deploy_to_staging' job would not run.</span>

</code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Explanation:</h3>



<ol class="wp-block-list">
<li><strong><code>allow_failure:</code> Keyword:</strong>
<ul class="wp-block-list">
<li>Used within a job&#8217;s definition.</li>



<li>It accepts a boolean value: <code>true</code> or <code>false</code>.</li>



<li><code>allow_failure: true</code>: If this job fails, the job itself will be marked as &#8220;failed&#8221; (often with a warning icon like orange/yellow in the UI), but it will <strong>not</strong> cause the entire pipeline to be marked as &#8220;failed&#8221;. Subsequent jobs in later stages (or parallel jobs that don&#8217;t depend on it) can still proceed as if this job had succeeded for the purpose of pipeline progression.</li>



<li><code>allow_failure: false</code> (or omitting the keyword): This is the default behavior. If the job fails, the pipeline is marked as &#8220;failed&#8221;, and typically, jobs in subsequent stages will not run.</li>
</ul>
</li>



<li><strong><code>build_application</code> Job:</strong>
<ul class="wp-block-list">
<li>A standard job that is expected to succeed. It does not use <code>allow_failure</code>, so if it failed, the pipeline would fail.</li>
</ul>
</li>



<li><strong><code>critical_unit_tests</code> Job:</strong>
<ul class="wp-block-list">
<li>This job also does not use <code>allow_failure: true</code>. If this job were to fail (e.g., by uncommenting <code>exit 1</code>), the <code>deploy_to_staging</code> job would not run, and the pipeline would be marked as failed. This represents a critical part of your CI.</li>
</ul>
</li>



<li><strong><code>non_critical_lint_check</code> Job:</strong>
<ul class="wp-block-list">
<li><strong><code>allow_failure: true</code></strong>: This is the key demonstration.</li>



<li>The <code>script</code> is designed to <code>exit 1</code>, which means this job will fail.</li>



<li>However, because <code>allow_failure</code> is true:
<ul class="wp-block-list">
<li>The <code>non_critical_lint_check</code> job itself will show a failed status (often with a warning icon).</li>



<li>The overall pipeline <strong>can still proceed</strong> to the <code>deploy</code> stage and potentially be marked as &#8220;passed&#8221; or &#8220;passed with warnings&#8221; if all other <em>critical</em> jobs (like <code>build_application</code> and <code>critical_unit_tests</code>) succeed.</li>
</ul>
</li>
</ul>
</li>



<li><strong><code>experimental_feature_test</code> Job:</strong>
<ul class="wp-block-list">
<li>Also uses <code>allow_failure: true</code>. This job is written to succeed in this example, but if it were to fail, it wouldn&#8217;t stop the pipeline. This is typical for tests of features that are under development and not yet stable.</li>
</ul>
</li>



<li><strong><code>deploy_to_staging</code> Job:</strong>
<ul class="wp-block-list">
<li>This job is in the <code>deploy</code> stage, which runs after the <code>test</code> stage.</li>



<li>It will execute if <code>build_application</code> and <code>critical_unit_tests</code> (the critical jobs in preceding stages) have passed. The failure of <code>non_critical_lint_check</code> will not prevent <code>deploy_to_staging</code> from running because of <code>allow_failure: true</code> on the lint check job.</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Key Concepts and Behavior:</h3>



<ul class="wp-block-list">
<li><strong>Pipeline Status:</strong> <code>allow_failure: true</code> primarily affects the <em>overall pipeline status</em>. The job that fails but is allowed to fail will still be marked as failed individually.</li>



<li><strong>Visual Indication:</strong> In the GitLab UI, jobs that fail but have <code>allow_failure: true</code> are often displayed with a distinct icon (e.g., orange or yellow warning) rather than a red failure icon that would stop the pipeline. The pipeline itself might show as &#8220;passed with warnings.&#8221;</li>



<li><strong>Use Cases:</strong>
<ul class="wp-block-list">
<li><strong>Linters/Style Checks:</strong> Useful if you want to be informed of style issues but not block deployments for minor infractions.</li>



<li><strong>Non-Critical Tests:</strong> For test suites that are known to be flaky or cover less critical aspects of the application.</li>



<li><strong>Experimental Features:</strong> When testing new, unstable features.</li>



<li><strong>Informational Scripts:</strong> Scripts that gather data or generate reports where failure isn&#8217;t catastrophic.</li>



<li><strong>Manual Jobs:</strong> Often, manual jobs (like deployments to optional environments) might have <code>allow_failure: true</code> if their failure shouldn&#8217;t affect the primary outcome of the CI run.</li>
</ul>
</li>



<li><strong>Within <code>rules:</code>:</strong> The <code>allow_failure</code> attribute can also be used within a <code>rules:</code> block, allowing you to make the failure allowance conditional. YAML<code>my_job_with_rules: script: - "exit 1" rules: - if: '$CI_COMMIT_BRANCH == "main"' allow_failure: false # Failure on main is critical - if: '$CI_COMMIT_BRANCH =~ /^feature\//' allow_failure: true # Allow failures on feature branches</code></li>
</ul>



<p class="wp-block-paragraph">Using <code>allow_failure: true</code> provides flexibility in defining which job failures are considered critical for your pipeline&#8217;s success and which are merely warnings or informational. It helps maintain a balance between ensuring quality and not being overly restrictive for non-essential checks.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/gitlab-pipeline-allow_failure-what-is-allow_failure-in-gitlab-ci-cd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Gitlab Pipeline – when – What is when in GitLab CI/CD?</title>
		<link>https://www.bestdevops.com/gitlab-pipeline-when-what-is-when-in-gitlab-ci-cd/</link>
					<comments>https://www.bestdevops.com/gitlab-pipeline-when-what-is-when-in-gitlab-ci-cd/#respond</comments>
		
		<dc:creator><![CDATA[kumar k]]></dc:creator>
		<pubDate>Tue, 27 May 2025 18:51:31 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=31383</guid>

					<description><![CDATA[The when keyword in a GitLab CI/CD job definition controls the conditions under which a job is executed. It&#8217;s primarily [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The <code>when</code> keyword in a GitLab CI/CD job definition controls the conditions under which a job is executed. It&#8217;s primarily used to handle scenarios like running jobs only on success, on failure, always, or requiring manual intervention.</p>



<p class="wp-block-paragraph"><strong>Note:</strong> While <code>when</code> can be used as a top-level keyword within a job, it is also a crucial component of the more powerful and flexible <code>rules:</code> syntax. The <code>rules:</code> keyword is now the recommended way to control job execution for most complex scenarios. This example will focus on <code>when</code> as a top-level job attribute.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Example <code>.gitlab-ci.yml</code> with <code>when</code>:</h3>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .gitlab-ci.yml</span>

stages:
  - build
  - test
  - deploy
  - notify
  - cleanup

<span class="hljs-keyword">default</span>:
  image: alpine:latest

<span class="hljs-comment"># Job 1: Standard job, runs on success of previous stage (default behavior)</span>
build_project:
  stage: build
  <span class="hljs-comment"># when: on_success # This is the default, so it's often omitted</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Building Project ---"</span>
    - sleep <span class="hljs-number">5</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Build successful!"</span>

<span class="hljs-comment"># Job 2: Another standard job</span>
test_feature_A:
  stage: test
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Testing Feature A ---"</span>
    - sleep <span class="hljs-number">3</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Feature A tests PASSED."</span>

<span class="hljs-comment"># Job 3: This job is designed to fail, to demonstrate 'on_failure' and 'always'</span>
test_feature_B_fails:
  stage: test
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Testing Feature B (designed to fail) ---"</span>
    - sleep <span class="hljs-number">2</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Feature B encountered an error!"</span>
    - <span class="hljs-keyword">exit</span> <span class="hljs-number">1</span> <span class="hljs-comment"># Explicitly fail the job</span>
  allow_failure: <span class="hljs-keyword">true</span> <span class="hljs-comment"># Allow this job to fail without failing the whole pipeline,</span>
                      <span class="hljs-comment"># so we can see 'on_failure' and 'always' jobs run.</span>
                      <span class="hljs-comment"># In a real scenario, you might not allow failure if it's a critical test.</span>

<span class="hljs-comment"># Job 4: Runs only if a previous job in the same pipeline (from an earlier stage) failed</span>
cleanup_on_failure:
  stage: cleanup <span class="hljs-comment"># Placed in a later stage to observe effect</span>
  when: on_failure
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Cleanup on Failure ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"A previous critical job failed. Performing cleanup tasks."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"CI_PIPELINE_ID: $CI_PIPELINE_ID, Job that might have failed is in an earlier stage."</span>

<span class="hljs-comment"># Job 5: Runs regardless of the success or failure of jobs in previous stages</span>
notify_always:
  stage: notify <span class="hljs-comment"># Placed in a later stage</span>
  when: always
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Notify Always ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This notification runs regardless of previous job statuses (success or failure)."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Pipeline finished processing up to this point."</span>

<span class="hljs-comment"># Job 6: Requires manual intervention to run</span>
manual_deploy_to_staging:
  stage: deploy
  when: manual
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Manual Deploy to Staging ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Deploying to staging environment after manual trigger..."</span>
    - sleep <span class="hljs-number">10</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Staging deployment complete."</span>
  allow_failure: <span class="hljs-keyword">false</span> <span class="hljs-comment"># Optional: specify if this manual job failing should fail the pipeline</span>

<span class="hljs-comment"># Job 7: Runs after a delay once its stage is ready</span>
delayed_report_generation:
  stage: notify
  when: delayed
  start_in: <span class="hljs-string">'1 minute'</span> <span class="hljs-comment"># Job will start 1 minute after the 'notify' stage is reached</span>
                      <span class="hljs-comment"># (and previous jobs in this stage, if any, are done)</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Delayed Report Generation ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Generating report after a 1-minute delay..."</span>
    - sleep <span class="hljs-number">5</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Report generated."</span>

<span class="hljs-comment"># Job 8: Default 'on_success' behavior</span>
final_production_deploy:
  stage: deploy
  <span class="hljs-comment"># Relies on the default 'when: on_success'</span>
  <span class="hljs-comment"># This job will only run if 'build_project', 'test_feature_A', AND 'test_feature_B_fails'</span>
  <span class="hljs-comment"># (if 'allow_failure' was false for it) all succeeded.</span>
  <span class="hljs-comment"># Given 'test_feature_B_fails' has 'allow_failure: true', this job's execution</span>
  <span class="hljs-comment"># depends on whether the overall pipeline is considered successful up to its stage.</span>
  <span class="hljs-comment"># To make it clearly depend on 'test_feature_A' for this example, we could use 'needs'.</span>
  <span class="hljs-comment"># For simplicity here, we'll assume it runs if prior stages are "green enough".</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Final Production Deploy ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"All critical tests passed (or allowed to fail). Deploying to production."</span>
</code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Explanation:</h3>



<ol class="wp-block-list">
<li><strong><code>when:</code> Keyword:</strong>
<ul class="wp-block-list">
<li>Used directly within a job&#8217;s definition to specify the condition for its execution.</li>
</ul>
</li>



<li><strong>Common <code>when:</code> Values:</strong>
<ul class="wp-block-list">
<li><strong><code>on_success</code> (Default):</strong>
<ul class="wp-block-list">
<li>If <code>when</code> is not specified, this is the default behavior.</li>



<li>The job runs only if all jobs from previous stages in the pipeline have completed successfully (or are marked with <code>allow_failure: true</code> and failed).</li>



<li><code>build_project</code> and <code>test_feature_A</code> implicitly use this. <code>final_production_deploy</code> also implicitly uses this.</li>
</ul>
</li>



<li><strong><code>on_failure</code>:</strong>
<ul class="wp-block-list">
<li>The job runs only if at least one job from a previous stage in the pipeline has failed (and that failing job was not marked with <code>allow_failure: true</code> to the extent that it stops the pipeline progression for <code>on_success</code> jobs).</li>



<li><code>cleanup_on_failure</code> will run because <code>test_feature_B_fails</code> is designed to fail. Even though <code>test_feature_B_fails</code> has <code>allow_failure: true</code>, an <code>on_failure</code> job in a later stage will still trigger if a failure occurred.</li>
</ul>
</li>



<li><strong><code>always</code>:</strong>
<ul class="wp-block-list">
<li>The job runs regardless of the success or failure status of jobs in previous stages, as long as the pipeline itself is running and the job&#8217;s stage is reached (or its <code>needs</code> dependencies are met).</li>



<li><code>notify_always</code> will run whether <code>test_feature_B_fails</code> fails or if all test jobs had passed.</li>
</ul>
</li>



<li><strong><code>manual</code>:</strong>
<ul class="wp-block-list">
<li>The job is added to the pipeline but is not executed automatically. It appears with a &#8220;play&#8221; icon in the GitLab UI, and a user with appropriate permissions must manually trigger it.</li>



<li><code>manual_deploy_to_staging</code> demonstrates this. It&#8217;s common for deployment to sensitive environments or for optional long-running tasks.</li>



<li>You can optionally add <code>allow_failure: true</code> to manual jobs if their failure shouldn&#8217;t block the pipeline.</li>
</ul>
</li>



<li><strong><code>delayed</code>:</strong>
<ul class="wp-block-list">
<li>The job is executed automatically after a specified duration once its stage is ready (all previous stage jobs or <code>needs</code> dependencies are complete).</li>



<li><code>delayed_report_generation</code> uses <code>start_in: '1 minute'</code> to specify the delay. The <code>start_in</code> value can be a human-readable duration like <code>'5 seconds'</code>, <code>'10 minutes'</code>, <code>'1 hour'</code>.</li>
</ul>
</li>
</ul>
</li>



<li><strong><code>allow_failure:</code> in <code>test_feature_B_fails</code>:</strong>
<ul class="wp-block-list">
<li>I&#8217;ve added <code>allow_failure: true</code> to <code>test_feature_B_fails</code>. This means even though this job fails:
<ul class="wp-block-list">
<li>The pipeline will still be considered &#8220;successful&#8221; overall <em>if all other critical jobs pass</em>.</li>



<li>It allows subsequent stages and jobs (like <code>notify_always</code> and <code>cleanup_on_failure</code>) to run and demonstrate their <code>when</code> conditions.</li>



<li><code>on_failure</code> jobs will still trigger based on the fact that a job <em>did</em> fail, even if that failure was &#8220;allowed.&#8221;</li>
</ul>
</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">How <code>when</code> Affects Pipeline Flow:</h3>



<ul class="wp-block-list">
<li><strong><code>on_success</code></strong> jobs create a sequence where success in one stage gates entry into the next.</li>



<li><strong><code>on_failure</code></strong> jobs provide a way to run specific tasks (like cleanup or notifications) only when something goes wrong.</li>



<li><strong><code>always</code></strong> jobs ensure certain actions (like logging or final notifications) happen no matter what.</li>



<li><strong><code>manual</code></strong> jobs introduce decision points or optional steps in the pipeline.</li>



<li><strong><code>delayed</code></strong> jobs allow for non-critical tasks to be deferred slightly.</li>
</ul>



<h3 class="wp-block-heading"><code>when</code> within <code>rules:</code></h3>



<p class="wp-block-paragraph">It&#8217;s important to note that <code>when</code> is also a key clause within the more modern <code>rules:</code> syntax. For example:</p>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php">job_with_rules:
  script: <span class="hljs-keyword">echo</span> <span class="hljs-string">"Running with rules"</span>
  rules:
    - <span class="hljs-keyword">if</span>: <span class="hljs-string">'$CI_COMMIT_BRANCH == "main"'</span>
      when: always <span class="hljs-comment"># This 'when' is part of the rule</span>
    - <span class="hljs-keyword">if</span>: <span class="hljs-string">'$CI_PIPELINE_SOURCE == "merge_request_event"'</span>
      when: manual
    - when: never <span class="hljs-comment"># Default to not running if other rules don't match</span>
</code></span></pre>


<p class="wp-block-paragraph">In this context, <code>when</code> (along with <code>allow_failure</code>, <code>variables</code>, etc.) is applied if the corresponding <code>if</code>, <code>changes</code>, or <code>exists</code> condition in that specific rule entry evaluates to true.</p>



<p class="wp-block-paragraph">Understanding <code>when</code> is crucial for building pipelines that can react appropriately to different situations, manage optional steps, and handle failures gracefully.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/gitlab-pipeline-when-what-is-when-in-gitlab-ci-cd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Gitlab Pipeline – timeout – What is timeout in GitLab CI/CD?</title>
		<link>https://www.bestdevops.com/gitlab-pipeline-timeout-what-is-timeout-in-gitlab-ci-cd/</link>
					<comments>https://www.bestdevops.com/gitlab-pipeline-timeout-what-is-timeout-in-gitlab-ci-cd/#respond</comments>
		
		<dc:creator><![CDATA[kumar k]]></dc:creator>
		<pubDate>Tue, 27 May 2025 18:40:02 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=31380</guid>

					<description><![CDATA[The timeout keyword in a GitLab CI/CD job definition allows you to specify a maximum execution time for that job. [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The <code>timeout</code> keyword in a GitLab CI/CD job definition allows you to specify a maximum execution time for that job. If the job runs longer than the specified duration, GitLab CI will automatically cancel (and fail) the job. This is crucial for preventing stuck jobs from consuming runner resources indefinitely.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Example <code>.gitlab-ci.yml</code> with <code>timeout</code>:</h3>



<p class="wp-block-paragraph">This example includes two jobs: one that will likely exceed its timeout and another that should complete within its timeout.</p>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .gitlab-ci.yml</span>

stages:
  - process
  - quick_task

<span class="hljs-keyword">default</span>:
  image: alpine:latest

<span class="hljs-comment"># Job 1: This job is designed to exceed its specified timeout</span>
long_running_job_with_timeout:
  stage: process
  timeout: <span class="hljs-number">30</span> seconds <span class="hljs-comment"># Set a timeout of 30 seconds for this job</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Long Running Job with Timeout ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This job has a 30-second timeout."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Starting a task that will take 45 seconds..."</span>
    - sleep <span class="hljs-number">45</span> <span class="hljs-comment"># This command will cause the job to exceed its 30s timeout</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This line will likely NOT be reached because the job will time out."</span>
  after_script: <span class="hljs-comment"># after_script also has its own timeout, separate from the job's main script timeout</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"After_script: This runs even if the main script timed out or failed."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Job status at this point: $CI_JOB_STATUS"</span>

<span class="hljs-comment"># Job 2: This job should complete within its timeout</span>
quick_job_with_timeout:
  stage: quick_task
  timeout: <span class="hljs-number">1</span> minute <span class="hljs-comment"># Set a timeout of 1 minute for this job</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Quick Job with Timeout ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This job has a 1-minute timeout and should complete successfully."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Performing a quick task..."</span>
    - sleep <span class="hljs-number">10</span> <span class="hljs-comment"># This task takes only 10 seconds</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Quick task finished well within the timeout."</span>
  after_script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"After_script: Quick job finished. Status: $CI_JOB_STATUS"</span>

</code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Explanation:</h3>



<ol class="wp-block-list">
<li><strong><code>timeout:</code> Keyword:</strong>
<ul class="wp-block-list">
<li>Used within a job definition to specify the maximum allowed execution time for that job&#8217;s <code>script</code> section.</li>



<li>If the job&#8217;s script execution time exceeds this value, GitLab CI will stop the job, and it will be marked as failed with a &#8220;job execution timeout&#8221; reason.</li>
</ul>
</li>



<li><strong><code>long_running_job_with_timeout</code> Job:</strong>
<ul class="wp-block-list">
<li><strong><code>timeout: 30 seconds</code></strong>:
<ul class="wp-block-list">
<li>This job is configured to time out after 30 seconds.</li>
</ul>
</li>



<li><strong><code>script:</code></strong>:
<ul class="wp-block-list">
<li><code>sleep 45</code>: This command will pause execution for 45 seconds. Since this is longer than the 30-second timeout, this job is expected to be terminated by GitLab CI before the <code>sleep</code> command completes.</li>



<li>The final <code>echo</code> statement in the <code>script</code> will likely not be executed.</li>
</ul>
</li>



<li><strong><code>after_script:</code></strong>:
<ul class="wp-block-list">
<li>Commands in <code>after_script</code> are executed after the main <code>script</code> finishes, <em>regardless</em> of whether the main script succeeded, failed, or timed out.</li>



<li><code>after_script</code> has its own, separate timeout (usually shorter, configured by the GitLab administrator at the instance or runner level). It does not inherit the job&#8217;s <code>timeout</code>.</li>



<li>The <code>$CI_JOB_STATUS</code> variable within the <code>after_script</code> will reflect the status of the main script (e.g., <code>failed</code> if it timed out).</li>
</ul>
</li>
</ul>
</li>



<li><strong><code>quick_job_with_timeout</code> Job:</strong>
<ul class="wp-block-list">
<li><strong><code>timeout: 1 minute</code></strong>: This job has a more generous timeout of 1 minute.</li>



<li><strong><code>script:</code></strong>:
<ul class="wp-block-list">
<li><code>sleep 10</code>: This command only pauses for 10 seconds, which is well within the 1-minute timeout.</li>



<li>This job should complete successfully.</li>
</ul>
</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Duration Format:</h3>



<p class="wp-block-paragraph">The <code>timeout</code> value is specified as a human-readable duration. GitLab supports various units and combinations:</p>



<ul class="wp-block-list">
<li><code>s</code> or <code>second</code> or <code>seconds</code></li>



<li><code>m</code> or <code>minute</code> or <code>minutes</code></li>



<li><code>h</code> or <code>hour</code> or <code>hours</code></li>



<li>Examples:
<ul class="wp-block-list">
<li><code>timeout: 5s</code> (5 seconds)</li>



<li><code>timeout: 10m</code> (10 minutes)</li>



<li><code>timeout: 1h 30m</code> (1 hour and 30 minutes)</li>



<li><code>timeout: 2 hours</code></li>



<li><code>timeout: 300</code> (Interpreted as 300 seconds, but using units is clearer)</li>
</ul>
</li>
</ul>



<h3 class="wp-block-heading">Key Concepts and Behavior:</h3>



<ul class="wp-block-list">
<li><strong>Purpose:</strong> To prevent runaway jobs from consuming excessive CI/CD runner time and resources. It acts as a safeguard.</li>



<li><strong>Job Failure:</strong> When a job times out, it&#8217;s marked as <code>failed</code> in the pipeline, and the failure reason will indicate a timeout.</li>



<li><strong>Scope:</strong>
<ul class="wp-block-list">
<li><strong>Job-level <code>timeout</code>:</strong> As shown in the example, defined per job.</li>



<li><strong>Project-level default <code>timeout</code>:</strong> You can set a default timeout for all jobs in your project under <strong>Settings > CI/CD > General pipelines > Timeout</strong>. Job-level timeouts will override this project default.</li>



<li><strong>Runner-level <code>timeout</code>:</strong> GitLab Runner configurations might also have maximum timeout settings. The <strong>most restrictive timeout</strong> (job, project, or runner) will apply. For example, if a job specifies <code>timeout: 2 hours</code> but the runner is configured with a maximum of 1 hour, the job will time out after 1 hour.</li>
</ul>
</li>



<li><strong><code>after_script</code> Timeout:</strong> As mentioned, <code>after_script</code> has its own independent timeout, which is generally not configurable via the <code>.gitlab-ci.yml</code> job <code>timeout</code> keyword but at the runner or instance level.</li>



<li><strong>Use Cases:</strong>
<ul class="wp-block-list">
<li>Preventing stuck deployment scripts.</li>



<li>Limiting the time for long-running test suites that might have performance regressions.</li>



<li>Ensuring resource-intensive jobs don&#8217;t block runners for too long.</li>



<li>Setting realistic expectations for how long a particular automated task should take.</li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph">Setting appropriate timeouts is an important part of maintaining a healthy and efficient CI/CD pipeline. It helps in quickly identifying and addressing jobs that are taking longer than expected.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/gitlab-pipeline-timeout-what-is-timeout-in-gitlab-ci-cd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Gitlab Pipeline – retry – What is retry in GitLab CI/CD?</title>
		<link>https://www.bestdevops.com/gitlab-pipeline-retry-what-is-retry-in-gitlab-ci-cd/</link>
					<comments>https://www.bestdevops.com/gitlab-pipeline-retry-what-is-retry-in-gitlab-ci-cd/#comments</comments>
		
		<dc:creator><![CDATA[kumar k]]></dc:creator>
		<pubDate>Tue, 27 May 2025 18:37:06 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=31377</guid>

					<description><![CDATA[The retry keyword in a GitLab CI/CD job allows you to specify that a job should be automatically re-executed if [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The <code>retry</code> keyword in a GitLab CI/CD job allows you to specify that a job should be automatically re-executed if it fails. This is particularly useful for jobs that might fail due to transient, temporary issues like network glitches, timeouts with external services, or brief runner problems, rather than an actual problem with the job&#8217;s script or code.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Example <code>.gitlab-ci.yml</code> with <code>retry</code>:</h3>



<p class="wp-block-paragraph">This example simulates a job that might fail on its first attempt but succeed on a retry.</p>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .gitlab-ci.yml</span>

stages:
  - test
  - deploy

<span class="hljs-keyword">default</span>:
  image: alpine:latest

<span class="hljs-comment"># Job 1: A job that might fail due to a transient issue (simulated)</span>
flaky_test_job:
  stage: test
  retry: <span class="hljs-number">2</span> <span class="hljs-comment"># Allow up to 2 retries (total 3 attempts: initial + 2 retries)</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Running Flaky Test Job (Attempt: $((CI_JOB_MANUAL ? 0 : ${CI_JOB_ATTEMPT:-1}))) ---"</span> <span class="hljs-comment"># CI_JOB_ATTEMPT is available from GitLab 15.5</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Simulating a test that sometimes fails..."</span>
    <span class="hljs-comment"># Create a counter file to simulate success on a later attempt</span>
    - ATTEMPT_FILE=<span class="hljs-string">".job_attempt_counter"</span>
    - |
      <span class="hljs-keyword">if</span> &#91; ! -f <span class="hljs-string">"$ATTEMPT_FILE"</span> ]; then
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"First attempt: Simulating failure."</span>
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"1"</span> &gt; <span class="hljs-string">"$ATTEMPT_FILE"</span> <span class="hljs-comment"># Record first attempt</span>
        <span class="hljs-keyword">exit</span> <span class="hljs-number">1</span> <span class="hljs-comment"># Fail the job</span>
      elif &#91; <span class="hljs-string">"$(cat $ATTEMPT_FILE)"</span> = <span class="hljs-string">"1"</span> ]; then
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Second attempt: Simulating another failure for demonstration."</span>
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"2"</span> &gt; <span class="hljs-string">"$ATTEMPT_FILE"</span> <span class="hljs-comment"># Record second attempt</span>
        <span class="hljs-keyword">exit</span> <span class="hljs-number">1</span> <span class="hljs-comment"># Fail the job again</span>
      <span class="hljs-keyword">else</span>
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Third attempt (or later if manual retry): Test passes!"</span>
        rm <span class="hljs-string">"$ATTEMPT_FILE"</span> <span class="hljs-comment"># Clean up</span>
        <span class="hljs-keyword">exit</span> <span class="hljs-number">0</span> <span class="hljs-comment"># Succeed the job</span>
      fi

<span class="hljs-comment"># Job 2: Another job with more specific retry conditions</span>
deploy_to_staging:
  stage: deploy
  retry:
    max: <span class="hljs-number">1</span> <span class="hljs-comment"># Allow up to 1 retry (total 2 attempts)</span>
    when: <span class="hljs-comment"># Specify conditions under which to retry</span>
      - runner_system_failure <span class="hljs-comment"># Retry if the runner had a system issue</span>
      - stuck_or_timeout_failure <span class="hljs-comment"># Retry if the job got stuck or timed out</span>
      - script_failure <span class="hljs-comment"># Also retry on general script failures for this example</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Deploying to Staging (Attempt: $((CI_JOB_MANUAL ? 0 : ${CI_JOB_ATTEMPT:-1}))) ---"</span>
    - RANDOM_NUMBER=$((<span class="hljs-number">1</span> + RANDOM % <span class="hljs-number">3</span>)) <span class="hljs-comment"># Generate a random number between 1 and 3</span>
    - |
      <span class="hljs-keyword">if</span> &#91; <span class="hljs-string">"$RANDOM_NUMBER"</span> -ne <span class="hljs-string">"3"</span> ] &amp;&amp; &#91; <span class="hljs-string">"${CI_JOB_ATTEMPT:-1}"</span> -lt <span class="hljs-string">"2"</span> ] ; then <span class="hljs-comment"># Fail on 1 or 2 on first attempt</span>
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Deployment to staging failed due to a simulated transient issue (e.g., network timeout)."</span>
        <span class="hljs-keyword">exit</span> <span class="hljs-number">1</span>
      <span class="hljs-keyword">else</span>
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Deployment to staging successful!"</span>
        <span class="hljs-keyword">exit</span> <span class="hljs-number">0</span>
      fi
</code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Explanation:</h3>



<ol class="wp-block-list">
<li><strong><code>retry:</code> Keyword:</strong>
<ul class="wp-block-list">
<li>Used within a job definition to configure its retry behavior.</li>



<li>It tells the GitLab Runner to re-run the job automatically if it fails, up to a specified number of times and under certain conditions.</li>
</ul>
</li>



<li><strong><code>flaky_test_job</code> (Simple Retry Count):</strong>
<ul class="wp-block-list">
<li><strong><code>retry: 2</code></strong>:
<ul class="wp-block-list">
<li>This is the simpler way to define retries. The number <code>2</code> means the job will be retried <strong>up to 2 times</strong> after its initial failure.</li>



<li>This results in a maximum of <strong>3 attempts</strong> in total (1 initial attempt + 2 retries).</li>



<li>GitLab allows a maximum of 2 retries (so values of <code>0</code>, <code>1</code>, or <code>2</code>).</li>



<li>If <code>when:</code> is not specified, it defaults to retrying on most failure reasons (effectively <code>retry:when:always</code> in older terms, or a broad set of common failure types now).</li>
</ul>
</li>



<li><strong>Script Logic:</strong>
<ul class="wp-block-list">
<li>The script uses a file (<code>.job_attempt_counter</code>) to simulate a scenario where the first two attempts fail, and the third attempt succeeds.</li>



<li><code>CI_JOB_ATTEMPT</code> (available GitLab 15.5+) is a predefined variable that indicates the current attempt number for a job, starting from 1. The script uses a fallback for older versions or manual retries.</li>
</ul>
</li>
</ul>
</li>



<li><strong><code>deploy_to_staging</code> (Detailed Retry Configuration):</strong>
<ul class="wp-block-list">
<li><strong><code>retry:</code></strong>: This starts the retry configuration block.</li>



<li><strong><code>max: 1</code></strong>: Specifies the maximum number of retries (so, up to 1 retry, meaning 2 attempts in total).</li>



<li><strong><code>when:</code></strong>: This sub-key allows you to specify a list of failure reasons for which the job should be retried. The job will only be retried if its failure reason is in this list.
<ul class="wp-block-list">
<li><code>runner_system_failure</code>: A problem with the GitLab Runner itself (e.g., crash, unexpected shutdown).</li>



<li><code>stuck_or_timeout_failure</code>: The job was stuck or exceeded its execution timeout.</li>



<li><code>script_failure</code>: The job failed because a command in its <code>script</code> section exited with a non-zero status code.</li>



<li><strong>Other common <code>when</code> values include:</strong> <code>unknown_failure</code>, <code>api_failure</code>, <code>missing_dependency_failure</code>, <code>job_execution_timeout</code>, etc. You can list multiple reasons. If any of the listed reasons occur, the job is retried.</li>
</ul>
</li>



<li><strong>Script Logic:</strong>
<ul class="wp-block-list">
<li>This script uses a random number to simulate a deployment that might fail on the first attempt but succeed on the retry. It&#8217;s designed to likely fail if <code>RANDOM_NUMBER</code> isn&#8217;t 3 on the first try but will succeed on the second attempt (as <code>CI_JOB_ATTEMPT</code> would be 2).</li>
</ul>
</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Key Concepts and Behavior:</h3>



<ul class="wp-block-list">
<li><strong>Purpose:</strong> To handle intermittent or transient failures automatically, improving pipeline reliability without manual intervention for minor, non-deterministic issues.</li>



<li><strong>Number of Retries:</strong> The integer value for <code>retry</code> or <code>retry:max:</code> specifies the number of <em>additional attempts</em> after the first failure. So <code>retry: 1</code> means one initial attempt and one retry (total 2 attempts). The maximum allowed value is <code>2</code> (total 3 attempts).</li>



<li><strong>Retry Conditions (<code>when</code>):</strong>
<ul class="wp-block-list">
<li>If only <code>retry: &lt;count></code> is used, it retries on a broad range of failures.</li>



<li><code>retry:when:</code> gives you fine-grained control over <em>why</em> a job should be retried. This is useful to avoid retrying jobs that fail due to genuine code errors (where a retry won&#8217;t help).</li>
</ul>
</li>



<li><strong>Job Logs:</strong> Each attempt of a retried job is logged separately in the GitLab UI, allowing you to see the output and failure reason for each attempt.</li>



<li><strong>Final Status:</strong> If all allowed attempts (initial + retries) fail, the job is marked as failed in the pipeline. If any attempt succeeds, the job is marked as successful.</li>



<li><strong>Idempotency:</strong> Jobs that are configured to retry should ideally be <em>idempotent</em>. This means running the job multiple times should have the same effect as running it once successfully (e.g., it shouldn&#8217;t create duplicate resources or have unintended side effects on repeated runs).</li>



<li><strong><code>CI_JOB_ATTEMPT</code> Variable:</strong> Starting from GitLab 15.5, this predefined variable can be used within your script to know which attempt number is currently running. This can be useful for implementing conditional logic within your script for retries.</li>
</ul>



<h3 class="wp-block-heading">When to Use <code>retry</code>:</h3>



<ul class="wp-block-list">
<li><strong>Flaky Tests:</strong> Tests that occasionally fail due to timing issues, external service flakiness, or unstable test environments.</li>



<li><strong>Network Dependent Operations:</strong> Jobs that interact with external services over a network that might experience temporary outages or glitches (e.g., fetching dependencies, deploying to a cloud provider).</li>



<li><strong>Resource Contention:</strong> Situations where a job might fail if a shared resource (like a database connection pool on a test server) is temporarily exhausted.</li>
</ul>



<p class="wp-block-paragraph">Do not overuse <code>retry</code> to mask fundamental problems in your code or scripts. If a job consistently fails, it needs to be fixed, not just retried. <code>retry</code> is for genuinely transient issues.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/gitlab-pipeline-retry-what-is-retry-in-gitlab-ci-cd/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Gitlab Pipeline – artifacts – What is artifacts in GitLab CI/CD?</title>
		<link>https://www.bestdevops.com/gitlab-pipeline-artifacts-what-is-artifacts-in-gitlab-ci-cd/</link>
					<comments>https://www.bestdevops.com/gitlab-pipeline-artifacts-what-is-artifacts-in-gitlab-ci-cd/#comments</comments>
		
		<dc:creator><![CDATA[kumar k]]></dc:creator>
		<pubDate>Tue, 27 May 2025 18:35:05 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=31374</guid>

					<description><![CDATA[The artifacts keyword in a GitLab CI/CD job specifies a list of files and directories that should be saved and [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The <code>artifacts</code> keyword in a GitLab CI/CD job specifies a list of files and directories that should be saved and uploaded when a job finishes. These artifacts are then available for download from the GitLab UI and can be used by jobs in later stages of the same pipeline.</p>



<p class="wp-block-paragraph">This is essential for:</p>



<ul class="wp-block-list">
<li>Passing build outputs (like compiled binaries, distributable packages, or static website files) to subsequent jobs (e.g., for testing or deployment).</li>



<li>Storing reports (test reports, code coverage reports, etc.).</li>



<li>Making build results available for users to download.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Example <code>.gitlab-ci.yml</code> with <code>artifacts</code>:</h3>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .gitlab-ci.yml</span>

stages:
  - build
  - test
  - package

<span class="hljs-keyword">default</span>:
  image: alpine:latest

<span class="hljs-comment"># Job 1: Builds the application and creates artifacts</span>
build_application:
  stage: build
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Building Application ---"</span>
    - mkdir -p dist/app  <span class="hljs-comment"># Create a directory for distributable files</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"MyApplication_v1.0_binary"</span> &gt; dist/app/my_app
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Configuration file content"</span> &gt; dist/app/config.json
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Build successful!"</span>

    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Generating a build report..."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Build report for commit $CI_COMMIT_SHORT_SHA"</span> &gt; build_report.txt
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Timestamp: $(date)"</span> &gt;&gt; build_report.txt

  artifacts:
    name: <span class="hljs-string">"${CI_JOB_NAME}_${CI_COMMIT_REF_SLUG}"</span> <span class="hljs-comment"># Optional: Custom name for the artifact archive</span>
    paths:
      - dist/ <span class="hljs-comment"># Save the entire 'dist' directory</span>
      - build_report.txt <span class="hljs-comment"># Save an individual file</span>
    expire_in: <span class="hljs-string">'1 week'</span> <span class="hljs-comment"># Optional: How long to keep the artifacts (e.g., 1 day, 1 week, 3 months)</span>
    when: on_success <span class="hljs-comment"># Optional: When to create artifacts (on_success, on_failure, always). Default is on_success.</span>
    <span class="hljs-comment"># untracked: true # Optional: Set to true to also include all Git untracked files</span>

<span class="hljs-comment"># Job 2: Tests the application using artifacts from the 'build_application' job</span>
test_application:
  stage: test
  <span class="hljs-comment"># This job will automatically download artifacts from 'build_application'</span>
  <span class="hljs-comment"># because it's in a later stage and 'dependencies' is not set to &#91;].</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Testing Application ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Checking for build artifacts..."</span>
    - ls -R dist/ <span class="hljs-comment"># List contents of the 'dist' directory (should contain 'app/my_app' and 'app/config.json')</span>
    - <span class="hljs-keyword">if</span> &#91; -f <span class="hljs-string">"dist/app/my_app"</span> ]; then <span class="hljs-keyword">echo</span> <span class="hljs-string">"Application binary found."</span>; <span class="hljs-keyword">else</span> <span class="hljs-keyword">echo</span> <span class="hljs-string">"ERROR: Application binary NOT found!"</span>; <span class="hljs-keyword">exit</span> <span class="hljs-number">1</span>; fi
    - <span class="hljs-keyword">if</span> &#91; -f <span class="hljs-string">"build_report.txt"</span> ]; then cat build_report.txt; <span class="hljs-keyword">else</span> <span class="hljs-keyword">echo</span> <span class="hljs-string">"ERROR: Build report NOT found!"</span>; <span class="hljs-keyword">exit</span> <span class="hljs-number">1</span>; fi
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Simulating tests on my_app..."</span>
    - sleep <span class="hljs-number">5</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Tests passed!"</span>

<span class="hljs-comment"># Job 3: Packages the application, also using artifacts from 'build_application'</span>
<span class="hljs-comment"># This demonstrates another job in a later stage accessing the same artifacts.</span>
package_release:
  stage: package
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Packaging Release ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Using build artifacts for packaging..."</span>
    - <span class="hljs-keyword">if</span> &#91; -f <span class="hljs-string">"dist/app/my_app"</span> ]; then <span class="hljs-keyword">echo</span> <span class="hljs-string">"Packaging $(cat dist/app/my_app)..."</span>; <span class="hljs-keyword">else</span> <span class="hljs-keyword">echo</span> <span class="hljs-string">"ERROR: Application binary for packaging NOT found!"</span>; <span class="hljs-keyword">exit</span> <span class="hljs-number">1</span>; fi
    - tar -czvf <span class="hljs-string">"release_package_${CI_COMMIT_SHORT_SHA}.tar.gz"</span> dist/ build_report.txt
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Release package created: release_package_${CI_COMMIT_SHORT_SHA}.tar.gz"</span>
  artifacts:
    paths:
      - <span class="hljs-string">"*.tar.gz"</span> <span class="hljs-comment"># Save the created tarball as an artifact of this job</span>
    expire_in: <span class="hljs-string">'30 days'</span>

</code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Explanation:</h3>



<ol class="wp-block-list">
<li><strong><code>artifacts:</code> Keyword:</strong>
<ul class="wp-block-list">
<li>Used within a job definition to specify which files and directories should be preserved after the job completes.</li>



<li>GitLab collects these files, archives them (usually as a ZIP file), and uploads them.</li>
</ul>
</li>



<li><strong><code>build_application</code> Job (Artifact Producer):</strong>
<ul class="wp-block-list">
<li><strong><code>script:</code></strong>: This section creates a <code>dist/app/</code> directory with some dummy application files and a <code>build_report.txt</code>.</li>



<li><strong><code>artifacts:</code></strong>:
<ul class="wp-block-list">
<li><strong><code>name: "${CI_JOB_NAME}_${CI_COMMIT_REF_SLUG}"</code></strong>:
<ul class="wp-block-list">
<li>(Optional) Allows you to define a custom name for the downloadable artifact archive. Here, it uses predefined CI/CD variables to make the name dynamic (e.g., <code>build_application_main.zip</code>). If omitted, GitLab generates a default name.</li>
</ul>
</li>



<li><strong><code>paths:</code></strong>:
<ul class="wp-block-list">
<li>(Required if <code>artifacts</code> is used) An array of file paths or directory paths that should be included in the artifact archive. Paths are relative to the project&#8217;s root directory (<code>$CI_PROJECT_DIR</code>).</li>



<li><code>- dist/</code>: Includes the entire <code>dist</code> directory and its contents.</li>



<li><code>- build_report.txt</code>: Includes the individual <code>build_report.txt</code> file.</li>
</ul>
</li>



<li><strong><code>expire_in: '1 week'</code></strong>:
<ul class="wp-block-list">
<li>(Optional) Specifies how long the artifacts for this job should be stored in GitLab. After this period, they might be deleted to save space (unless &#8220;Keep artifacts from most recent successful_jobs jobs&#8221; is enabled in project settings). The format can be natural language (e.g., <code>'1 day'</code>, <code>'2 hrs 30 mins'</code>, <code>'6 mos'</code>) or a specific duration.</li>
</ul>
</li>



<li><strong><code>when: on_success</code></strong>:
<ul class="wp-block-list">
<li>(Optional) Determines when artifacts are created.
<ul class="wp-block-list">
<li><code>on_success</code> (Default): Artifacts are saved only if the job completes successfully.</li>



<li><code>on_failure</code>: Artifacts are saved only if the job fails (useful for logs or debug info).</li>



<li><code>always</code>: Artifacts are saved regardless of the job&#8217;s success or failure.</li>
</ul>
</li>
</ul>
</li>



<li><strong><code>untracked: true</code></strong>:
<ul class="wp-block-list">
<li>(Optional) If set to <code>true</code>, GitLab will also include all files that are untracked by Git in the artifact archive, in addition to the paths specified. Use with caution.</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>



<li><strong><code>test_application</code> Job (Artifact Consumer):</strong>
<ul class="wp-block-list">
<li>This job is in the <code>test</code> stage, which is later than the <code>build</code> stage where <code>build_application</code> ran.</li>



<li><strong>Automatic Artifact Download:</strong> By default, jobs in later stages automatically download artifacts from <strong>all jobs in all previous stages</strong> if those jobs completed successfully and produced artifacts. This happens unless you use <code>dependencies: []</code> in the consuming job or manage dependencies with <code>needs:</code> in a way that excludes certain artifacts.</li>



<li>The <code>script</code> section in <code>test_application</code> can therefore access the files from <code>dist/</code> and <code>build_report.txt</code> as if they were part of its own workspace.</li>
</ul>
</li>



<li><strong><code>package_release</code> Job (Another Artifact Consumer &amp; Producer):</strong>
<ul class="wp-block-list">
<li>This job also benefits from the default artifact download from <code>build_application</code>.</li>



<li>It then creates its <em>own</em> artifact (<code>release_package_${CI_COMMIT_SHORT_SHA}.tar.gz</code>) by packaging the received artifacts and the report.</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Key Concepts and Behavior:</h3>



<ul class="wp-block-list">
<li><strong>Purpose:</strong> To persist files and directories created by a job for use in subsequent jobs, for manual download, or for features like GitLab Pages or test reporting.</li>



<li><strong>Storage:</strong> Artifacts are stored on the GitLab server (or external storage if configured) and are associated with the job and pipeline run.</li>



<li><strong>Downloading Artifacts:</strong>
<ul class="wp-block-list">
<li><strong>From UI:</strong> You can download artifacts as a ZIP file from the job&#8217;s page in the GitLab UI, or from the pipeline view.</li>



<li><strong>By Other Jobs:</strong> As shown, later jobs often get them automatically. <code>needs:</code> provides more explicit control over which artifacts are downloaded from specified prerequisite jobs. <code>dependencies:</code> can also be used for more fine-grained control when not using <code>needs</code>.</li>
</ul>
</li>



<li><strong>Artifacts vs. Cache:</strong>
<ul class="wp-block-list">
<li><strong>Artifacts:</strong> Intended for passing outputs between stages, for final build products, or for reports. They are generally meant to be kept (at least until <code>expire_in</code>). They are uploaded to GitLab.</li>



<li><strong>Cache:</strong> Intended to speed up subsequent runs of the <em>same job</em> or related jobs (e.g., <code>node_modules</code>, compiler caches). Caches are best-effort and might be deleted by runners to save space. They are typically stored on the runner or a shared cache storage like S3.</li>
</ul>
</li>



<li><strong><code>artifacts:reports:</code> (Advanced):</strong>
<ul class="wp-block-list">
<li>GitLab has special support for certain types of reports (e.g., JUnit XML for test results, Cobertura for code coverage). Using <code>artifacts:reports:junit: report.xml</code> allows GitLab to parse these reports and display information directly in the UI (e.g., in Merge Requests).</li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph">Using <code>artifacts</code> is fundamental to building effective CI/CD pipelines in GitLab, as it enables the flow of work and results between different stages of your development lifecycle.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/gitlab-pipeline-artifacts-what-is-artifacts-in-gitlab-ci-cd/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Gitlab Pipeline – dependencies – What is dependencies in GitLab CI/CD?</title>
		<link>https://www.bestdevops.com/gitlab-pipeline-dependencies-what-is-dependencies-in-gitlab-ci-cd/</link>
					<comments>https://www.bestdevops.com/gitlab-pipeline-dependencies-what-is-dependencies-in-gitlab-ci-cd/#respond</comments>
		
		<dc:creator><![CDATA[kumar k]]></dc:creator>
		<pubDate>Tue, 27 May 2025 18:30:32 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=31372</guid>

					<description><![CDATA[Important Context on dependencies vs. needs: This example will illustrate both the selective use of dependencies (when not using needs [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><strong>Important Context on <code>dependencies</code> vs. <code>needs</code>:</strong></p>



<ul class="wp-block-list">
<li><strong><code>dependencies</code></strong> traditionally controlled which artifacts from jobs in <strong>previous stages</strong> were downloaded before a job starts. It does <em>not</em> control the order of execution (that&#8217;s handled by <code>stages</code> or <code>needs</code>).</li>



<li><strong><code>needs:</code></strong> is a more modern feature that allows you to create a Directed Acyclic Graph (DAG) of job execution. When a job uses <code>needs: [job_A]</code>, it implies an execution dependency on <code>job_A</code> AND, by default, <strong>it will download artifacts from <code>job_A</code></strong>.</li>



<li><strong>Current Practice:</strong>
<ul class="wp-block-list">
<li>If you are using <code>needs:</code> to define relationships between jobs, you typically <strong>do not need to use <code>dependencies</code></strong> to download artifacts from those <code>needs</code>-specified jobs, as <code>needs:</code> handles it.</li>



<li>The most common and clear use of <code>dependencies</code> in modern GitLab CI is <strong><code>dependencies: []</code> (an empty array)</strong>, which means the job should <em>not</em> download artifacts from any jobs in previous stages.</li>



<li>If you are <em>not</em> using <code>needs</code> for a specific job relationship and want to selectively download artifacts from previous stages, then <code>dependencies</code> can be used.</li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph">This example will illustrate both the selective use of <code>dependencies</code> (when not using <code>needs</code> for that specific artifact flow) and the common <code>dependencies: []</code> pattern.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Example <code>.gitlab-ci.yml</code> with <code>dependencies</code>:</h3>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .gitlab-ci.yml</span>

stages:
  - build
  - test
  - package

<span class="hljs-keyword">default</span>:
  image: alpine:latest

<span class="hljs-comment"># --- Build Stage Jobs (Producers) ---</span>
build_code:
  stage: build
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Building Main Code ---"</span>
    - mkdir -p build_output/code
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"main_application_binary"</span> &gt; build_output/code/app.bin
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Build Code complete."</span>
  artifacts:
    paths:
      - build_output/code/
    expire_in: <span class="hljs-number">1</span> hour

build_assets:
  stage: build
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Building Assets ---"</span>
    - mkdir -p build_output/assets
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"image.png"</span> &gt; build_output/assets/image.png
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"style.css"</span> &gt; build_output/assets/style.css
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Build Assets complete."</span>
  artifacts:
    paths:
      - build_output/assets/
    expire_in: <span class="hljs-number">1</span> hour

<span class="hljs-comment"># --- Test Stage Jobs (Consumers) ---</span>

<span class="hljs-comment"># Job 1: Selectively downloads artifacts ONLY from 'build_code'</span>
<span class="hljs-comment"># This is the "classic" use of dependencies when 'needs' isn't used for this relationship.</span>
test_main_app:
  stage: test
  dependencies:
    - build_code <span class="hljs-comment"># Only download artifacts from 'build_code' job</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Testing Main Application ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Checking for 'build_code' artifacts:"</span>
    - ls -R build_output/
    - <span class="hljs-keyword">if</span> &#91; -f <span class="hljs-string">"build_output/code/app.bin"</span> ]; then <span class="hljs-keyword">echo</span> <span class="hljs-string">"app.bin found."</span>; <span class="hljs-keyword">else</span> <span class="hljs-keyword">echo</span> <span class="hljs-string">"ERROR: app.bin NOT found!"</span>; <span class="hljs-keyword">exit</span> <span class="hljs-number">1</span>; fi
    - <span class="hljs-keyword">if</span> &#91; -f <span class="hljs-string">"build_output/assets/image.png"</span> ]; then <span class="hljs-keyword">echo</span> <span class="hljs-string">"WARNING: image.png found, but was not explicitly depended upon (might indicate default download if 'dependencies' was misconfigured or absent)."</span>; <span class="hljs-keyword">else</span> <span class="hljs-keyword">echo</span> <span class="hljs-string">"image.png correctly NOT found (as not depended upon)."</span>; fi
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Main application tests complete."</span>

<span class="hljs-comment"># Job 2: Downloads NO artifacts from previous stages</span>
<span class="hljs-comment"># This is a very common modern use case for 'dependencies'.</span>
test_assets_isolated:
  stage: test
  dependencies: &#91;] <span class="hljs-comment"># Explicitly download no artifacts</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Testing Assets in Isolation ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This job should start with a clean workspace (no artifacts from 'build' stage)."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Checking for any unexpected artifacts in 'build_output':"</span>
    - <span class="hljs-keyword">if</span> &#91; -d <span class="hljs-string">"build_output"</span> ]; then ls -R build_output/; <span class="hljs-keyword">echo</span> <span class="hljs-string">"ERROR: 'build_output' directory exists! Artifacts were downloaded unexpectedly."</span>; <span class="hljs-keyword">exit</span> <span class="hljs-number">1</span>; <span class="hljs-keyword">else</span> <span class="hljs-keyword">echo</span> <span class="hljs-string">"'build_output' directory does not exist. Correct."</span>; fi
    <span class="hljs-comment"># In a real scenario, this job might fetch assets differently or test their generation.</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Asset tests (isolated) complete."</span>

<span class="hljs-comment"># Job 3: Default behavior - downloads artifacts from ALL successful jobs in previous stages</span>
<span class="hljs-comment"># This happens if 'dependencies' is omitted AND 'needs' is not used to link to these specific jobs.</span>
test_with_all_artifacts_default:
  stage: test
  <span class="hljs-comment"># No 'dependencies' or 'needs' keyword here</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Testing with All Default Artifacts ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This job should have artifacts from ALL successful jobs in the 'build' stage."</span>
    - ls -R build_output/
    - <span class="hljs-keyword">if</span> &#91; -f <span class="hljs-string">"build_output/code/app.bin"</span> ] &amp;&amp; &#91; -f <span class="hljs-string">"build_output/assets/image.png"</span> ]; then <span class="hljs-keyword">echo</span> <span class="hljs-string">"Both app.bin and image.png found. Correct default behavior."</span>; <span class="hljs-keyword">else</span> <span class="hljs-keyword">echo</span> <span class="hljs-string">"ERROR: Expected artifacts not found!"</span>; <span class="hljs-keyword">exit</span> <span class="hljs-number">1</span>; fi
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Tests with all artifacts complete."</span>

<span class="hljs-comment"># --- Package Stage Job ---</span>
<span class="hljs-comment"># This job uses 'needs' which handles artifact downloads from 'test_main_app'.</span>
<span class="hljs-comment"># 'dependencies' would typically not be used here in conjunction with 'needs' for 'test_main_app'.</span>
package_application:
  stage: package
  needs: &#91;<span class="hljs-string">"test_main_app"</span>] <span class="hljs-comment"># 'needs' implies artifacts from 'test_main_app' will be downloaded if 'test_main_app' produced them.</span>
                           <span class="hljs-comment"># 'test_main_app' itself only got artifacts from 'build_code'.</span>
                           <span class="hljs-comment"># If 'package_application' also needed artifacts directly from 'build_assets',</span>
                           <span class="hljs-comment"># you'd add 'build_assets' to 'needs' or use a different strategy.</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Packaging Application ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This job uses 'needs'. Artifacts from 'test_main_app' (which are originally from 'build_code') should be available."</span>
    - ls -R build_output/
    - <span class="hljs-keyword">if</span> &#91; -f <span class="hljs-string">"build_output/code/app.bin"</span> ]; then <span class="hljs-keyword">echo</span> <span class="hljs-string">"app.bin found for packaging."</span>; <span class="hljs-keyword">else</span> <span class="hljs-keyword">echo</span> <span class="hljs-string">"ERROR: app.bin NOT found for packaging!"</span>; <span class="hljs-keyword">exit</span> <span class="hljs-number">1</span>; fi
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Application packaging complete."</span>

</code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Explanation:</h3>



<ol class="wp-block-list">
<li><strong><code>dependencies:</code> Keyword:</strong>
<ul class="wp-block-list">
<li>Used within a job definition to control which artifacts from jobs in <strong>previous stages</strong> are downloaded into the job&#8217;s workspace <em>before</em> its <code>before_script</code> and <code>script</code> sections run.</li>



<li><strong>It does NOT define execution order.</strong> The <code>stages</code> keyword defines the general order, and <code>needs:</code> defines specific job execution dependencies.</li>
</ul>
</li>



<li><strong><code>test_main_app</code> Job (Selective Dependencies):</strong>
<ul class="wp-block-list">
<li><code>dependencies: - build_code</code>:
<ul class="wp-block-list">
<li>This tells GitLab CI to download artifacts <em>only</em> from the <code>build_code</code> job (which ran in the preceding <code>build</code> stage).</li>



<li>Artifacts from <code>build_assets</code> (also in the <code>build</code> stage) will <strong>not</strong> be downloaded for this <code>test_main_app</code> job.</li>



<li>This is useful when a job only requires a subset of artifacts from previous stages.</li>
</ul>
</li>
</ul>
</li>



<li><strong><code>test_assets_isolated</code> Job (Empty Dependencies):</strong>
<ul class="wp-block-list">
<li><code>dependencies: []</code> (an empty array):
<ul class="wp-block-list">
<li>This is a special and very common instruction. It tells the job <strong>not to download any artifacts</strong> from any jobs in previous stages.</li>



<li>The job will start with a clean workspace concerning artifacts from prior stages. This is useful for jobs that should not be influenced by previous outputs or for jobs that manage their dependencies in a different way (e.g., pulling from a package registry).</li>
</ul>
</li>
</ul>
</li>



<li><strong><code>test_with_all_artifacts_default</code> Job (Default Behavior):</strong>
<ul class="wp-block-list">
<li>This job <strong>omits the <code>dependencies</code> keyword</strong> and also does not use <code>needs</code> to link to specific jobs in the <code>build</code> stage.</li>



<li>In this scenario (no <code>dependencies</code> and no relevant <code>needs</code>), a job will, by default, download artifacts from <strong>all jobs in all previous stages</strong> that completed successfully and produced artifacts.</li>



<li>So, <code>test_with_all_artifacts_default</code> will get artifacts from both <code>build_code</code> AND <code>build_assets</code>.</li>
</ul>
</li>



<li><strong><code>package_application</code> Job (Interaction with <code>needs</code>):</strong>
<ul class="wp-block-list">
<li>This job uses <code>needs: ["test_main_app"]</code>.</li>



<li>When <code>needs</code> is used, it implies that artifacts from the specified <code>needs</code> jobs will be downloaded by default (equivalent to <code>needs: [{ job: "job_name", artifacts: true }]</code>).</li>



<li>Therefore, <code>package_application</code> will download artifacts produced by <code>test_main_app</code>. Since <code>test_main_app</code> itself only downloaded artifacts from <code>build_code</code>, those are the artifacts that <code>package_application</code> will ultimately see from the <code>build</code> stage via this chain.</li>



<li>You <strong>generally do not specify <code>dependencies</code> for jobs already listed in <code>needs</code></strong> because <code>needs</code> handles the artifact download. Using both can sometimes lead to downloading artifacts twice or having less clear intent.</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Key Concepts:</h3>



<ul class="wp-block-list">
<li><strong>Artifact Control (Pre-<code>needs</code> Era / Specific Cases):</strong> <code>dependencies</code> was the primary way to manage which artifacts get downloaded. If a job needed artifacts from job A and job B in a previous stage, but not job C, you&#8217;d list <code>dependencies: [job_A, job_B]</code>.</li>



<li><strong>Clean Workspace:</strong> <code>dependencies: []</code> is the standard way to ensure a job starts clean without inheriting artifacts from previous stages.</li>



<li><strong>Default Download:</strong> If <code>dependencies</code> is absent and <code>needs</code> isn&#8217;t defining the artifact flow from previous stages, artifacts from <em>all</em> previous stage jobs are downloaded. This can be resource-intensive if not intended.</li>



<li><strong>No Impact on Order:</strong> <code>dependencies</code> only affects artifact downloading. It does not change the execution order of jobs or stages.</li>



<li><strong>Superseded by <code>needs</code> for Linked Jobs:</strong> For jobs that have an explicit execution dependency defined by <code>needs</code>, the artifact flow from those needed jobs is also managed by <code>needs</code> (artifacts are downloaded by default).</li>
</ul>



<p class="wp-block-paragraph">In modern GitLab CI, you&#8217;ll often see <code>needs</code> used to define both the execution flow and the artifact flow for direct dependencies, and <code>dependencies: []</code> used when a job needs a completely clean slate. The classic use of <code>dependencies: [job_A, job_B]</code> is less common if you&#8217;re heavily leveraging <code>needs</code> for your pipeline&#8217;s structure.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/gitlab-pipeline-dependencies-what-is-dependencies-in-gitlab-ci-cd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Gitlab Pipeline – needs – What is needs in GitLab CI/CD?</title>
		<link>https://www.bestdevops.com/gitlab-pipeline-needs-what-is-needs-in-gitlab-ci-cd/</link>
					<comments>https://www.bestdevops.com/gitlab-pipeline-needs-what-is-needs-in-gitlab-ci-cd/#respond</comments>
		
		<dc:creator><![CDATA[kumar k]]></dc:creator>
		<pubDate>Tue, 27 May 2025 18:27:54 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=31370</guid>

					<description><![CDATA[The needs: keyword allows you to define explicit dependencies between jobs, creating a Directed Acyclic Graph (DAG) of your pipeline. [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The <code>needs:</code> keyword allows you to define explicit dependencies between jobs, creating a Directed Acyclic Graph (DAG) of your pipeline. This means a job can start as soon as the specific jobs it <code>needs</code> have completed successfully, rather than waiting for the entire previous stage to finish. This can significantly speed up your pipeline execution by running jobs earlier than they would in a strict stage-based order.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Example <code>.gitlab-ci.yml</code> with <code>needs</code>:</h3>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .gitlab-ci.yml</span>

stages:
  - build
  - test
  - deploy

<span class="hljs-keyword">default</span>:
  image: alpine:latest
  <span class="hljs-comment"># For 'needs' to automatically download artifacts from prerequisite jobs,</span>
  <span class="hljs-comment"># those jobs must define 'artifacts'. We'll add simple artifacts for demonstration.</span>

<span class="hljs-comment"># --- Build Stage Jobs ---</span>
build_backend:
  stage: build
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Building Backend ---"</span>
    - sleep <span class="hljs-number">10</span> <span class="hljs-comment"># Simulate build time</span>
    - mkdir -p backend_build/
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"backend_app_v1"</span> &gt; backend_build/version.txt
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Backend built successfully."</span>
  artifacts:
    paths:
      - backend_build/
    expire_in: <span class="hljs-number">1</span> hour

build_frontend:
  stage: build
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Building Frontend ---"</span>
    - sleep <span class="hljs-number">15</span> <span class="hljs-comment"># Simulate build time</span>
    - mkdir -p frontend_build/
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"frontend_app_v1"</span> &gt; frontend_build/ui_bundle.js
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Frontend built successfully."</span>
  artifacts:
    paths:
      - frontend_build/
    expire_in: <span class="hljs-number">1</span> hour

<span class="hljs-comment"># --- Test Stage Jobs ---</span>
<span class="hljs-comment"># This job will start as soon as 'build_backend' finishes, without waiting for 'build_frontend'.</span>
test_backend_api:
  stage: test
  needs: &#91;<span class="hljs-string">"build_backend"</span>] <span class="hljs-comment"># Explicitly depends on 'build_backend'</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Testing Backend API ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Checking backend build artifacts..."</span>
    - <span class="hljs-keyword">if</span> &#91; -f <span class="hljs-string">"backend_build/version.txt"</span> ]; then cat backend_build/version.txt; <span class="hljs-keyword">else</span> <span class="hljs-keyword">echo</span> <span class="hljs-string">"Backend version file not found!"</span>; <span class="hljs-keyword">exit</span> <span class="hljs-number">1</span>; fi
    - sleep <span class="hljs-number">8</span>  <span class="hljs-comment"># Simulate test time</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Backend API tests PASSED."</span>

<span class="hljs-comment"># This job will start as soon as 'build_frontend' finishes, without waiting for 'build_backend'.</span>
test_frontend_ui:
  stage: test
  needs: &#91;<span class="hljs-string">"build_frontend"</span>] <span class="hljs-comment"># Explicitly depends on 'build_frontend'</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Testing Frontend UI ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Checking frontend build artifacts..."</span>
    - <span class="hljs-keyword">if</span> &#91; -f <span class="hljs-string">"frontend_build/ui_bundle.js"</span> ]; then <span class="hljs-keyword">echo</span> <span class="hljs-string">"Frontend bundle found."</span>; <span class="hljs-keyword">else</span> <span class="hljs-keyword">echo</span> <span class="hljs-string">"Frontend bundle not found!"</span>; <span class="hljs-keyword">exit</span> <span class="hljs-number">1</span>; fi
    - sleep <span class="hljs-number">10</span> <span class="hljs-comment"># Simulate test time</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Frontend UI tests PASSED."</span>

<span class="hljs-comment"># This job needs both build jobs to complete before it can start.</span>
<span class="hljs-comment"># It will start as soon as BOTH 'build_backend' AND 'build_frontend' are done.</span>
integration_tests:
  stage: test
  needs: &#91;<span class="hljs-string">"build_backend"</span>, <span class="hljs-string">"build_frontend"</span>] <span class="hljs-comment"># Depends on multiple jobs</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Running Integration Tests ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Verifying backend and frontend integration..."</span>
    - <span class="hljs-keyword">if</span> &#91; -f <span class="hljs-string">"backend_build/version.txt"</span> ] &amp;&amp; &#91; -f <span class="hljs-string">"frontend_build/ui_bundle.js"</span> ]; then <span class="hljs-keyword">echo</span> <span class="hljs-string">"All necessary artifacts found."</span>; <span class="hljs-keyword">else</span> <span class="hljs-keyword">echo</span> <span class="hljs-string">"Missing artifacts for integration!"</span>; <span class="hljs-keyword">exit</span> <span class="hljs-number">1</span>; fi
    - sleep <span class="hljs-number">12</span> <span class="hljs-comment"># Simulate integration test time</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Integration tests PASSED."</span>

<span class="hljs-comment"># --- Deploy Stage Job ---</span>
<span class="hljs-comment"># This job will start as soon as 'integration_tests' finishes.</span>
<span class="hljs-comment"># It also implicitly benefits from artifacts if integration_tests produced any relevant for deployment.</span>
deploy_application:
  stage: deploy
  needs: &#91;<span class="hljs-string">"integration_tests"</span>]
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Deploying Application ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Deploying based on successful integration tests."</span>
    - sleep <span class="hljs-number">10</span> <span class="hljs-comment"># Simulate deployment time</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Application deployed successfully!"</span>
  when: on_success <span class="hljs-comment"># Default, but good for deploy jobs</span>

</code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Explanation:</h3>



<ol class="wp-block-list">
<li><strong><code>needs:</code> Keyword:</strong>
<ul class="wp-block-list">
<li>Used within a job definition to specify an array of other jobs that must complete successfully before this job can start.</li>



<li>It allows you to create a more granular dependency chain than what <code>stages</code> provide.</li>
</ul>
</li>



<li><strong><code>stages:</code> Still Define the Overall Flow (and Visualization):</strong>
<ul class="wp-block-list">
<li>Jobs still belong to <code>stages</code>. Stages are used for:
<ul class="wp-block-list">
<li>Visual grouping in the GitLab CI/CD pipeline graph.</li>



<li>A fallback execution order if <code>needs:</code> is not used.</li>



<li>Determining the order if <code>needs:</code> creates parallel paths that eventually converge on a stage.</li>
</ul>
</li>



<li>However, <code>needs:</code> can make a job start <em>earlier</em> than its defined stage if its <code>needs</code> dependencies are met.</li>
</ul>
</li>



<li><strong><code>test_backend_api</code> Job:</strong>
<ul class="wp-block-list">
<li><code>stage: test</code></li>



<li><code>needs: ["build_backend"]</code>: This is the key. <code>test_backend_api</code> will <strong>not</strong> wait for <code>build_frontend</code> (which is also in the <code>build</code> stage) to complete. As soon as <code>build_backend</code> finishes successfully, <code>test_backend_api</code> can start, even if <code>build_frontend</code> is still running.</li>
</ul>
</li>



<li><strong><code>test_frontend_ui</code> Job:</strong>
<ul class="wp-block-list">
<li><code>stage: test</code></li>



<li><code>needs: ["build_frontend"]</code>: Similar to the backend test, this job starts as soon as <code>build_frontend</code> is done, independently of <code>build_backend</code>&#8216;s completion or <code>test_backend_api</code>&#8216;s status (unless <code>test_backend_api</code> was also in its <code>needs</code> list).</li>
</ul>
</li>



<li><strong><code>integration_tests</code> Job:</strong>
<ul class="wp-block-list">
<li><code>stage: test</code></li>



<li><code>needs: ["build_backend", "build_frontend"]</code>: This job depends on <em>both</em> <code>build_backend</code> and <code>build_frontend</code>. It will only start after both of these prerequisite jobs have completed successfully.</li>
</ul>
</li>



<li><strong><code>deploy_application</code> Job:</strong>
<ul class="wp-block-list">
<li><code>stage: deploy</code></li>



<li><code>needs: ["integration_tests"]</code>: The deployment will only start after <code>integration_tests</code> is successful.</li>
</ul>
</li>



<li><strong>Artifacts and <code>needs</code>:</strong>
<ul class="wp-block-list">
<li>When you use <code>needs:</code>, by default, GitLab will attempt to download artifacts from all the jobs listed in the <code>needs</code> array. This is equivalent to <code>needs: [{ job: "job_name", artifacts: true }]</code>.</li>



<li>In the example, <code>build_backend</code> produces an artifact in <code>backend_build/</code>. <code>test_backend_api</code> (which <code>needs: ["build_backend"]</code>) will have access to this <code>backend_build/</code> directory and its contents.</li>



<li>If you don&#8217;t want artifacts from a needed job, you can specify <code>needs: [{ job: "job_name", artifacts: false }]</code>.</li>
</ul>
</li>



<li><strong>Impact of Failure:</strong>
<ul class="wp-block-list">
<li>If any job listed in a <code>needs</code> array fails (or is skipped, or canceled), the dependent job will be <strong>skipped</strong> by default and will not run.</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">How <code>needs:</code> Speeds Up Pipelines:</h3>



<p class="wp-block-paragraph">Imagine the <code>build</code> stage without <code>needs</code>:</p>



<ul class="wp-block-list">
<li><code>build_backend</code> (10s) and <code>build_frontend</code> (15s) run in parallel.</li>



<li>The <code>build</code> stage finishes after the longest job, so after 15s.</li>



<li>Only then would the <code>test</code> stage begin.</li>
</ul>



<p class="wp-block-paragraph">With <code>needs:</code>:</p>



<ul class="wp-block-list">
<li><code>build_backend</code> finishes in 10s. <code>test_backend_api</code> can start immediately.</li>



<li><code>build_frontend</code> finishes in 15s. <code>test_frontend_ui</code> can start immediately.</li>



<li><code>integration_tests</code> starts when both <code>build_backend</code> and <code>build_frontend</code> are done (i.e., after 15s in this example).</li>



<li>The overall pipeline can proceed much faster because testing for completed build components starts earlier.</li>
</ul>



<h3 class="wp-block-heading">Key Concepts and Benefits:</h3>



<ul class="wp-block-list">
<li><strong>DAG (Directed Acyclic Graph):</strong> <code>needs:</code> allows you to define your pipeline as a graph of dependencies, rather than a strict linear sequence of stages.</li>



<li><strong>Reduced Latency:</strong> Jobs start as soon as their true dependencies are met, leading to shorter overall pipeline durations.</li>



<li><strong>Increased Efficiency:</strong> Better utilization of runners as jobs don&#8217;t wait unnecessarily.</li>



<li><strong>Implicit Artifact Download:</strong> Simplifies passing artifacts between dependent jobs.</li>



<li><strong>Optional Dependencies:</strong> You can also use <code>needs: [{ job: "optional_job", optional: true }]</code>. If <code>optional_job</code> fails or is skipped, the current job will still run (but it won&#8217;t download artifacts from the optional job if it didn&#8217;t produce them).</li>
</ul>



<p class="wp-block-paragraph">Using <code>needs:</code> is a powerful way to optimize your GitLab CI/CD pipelines, especially for projects with multiple independent build components or test suites that can run as soon as their specific dependencies are ready.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/gitlab-pipeline-needs-what-is-needs-in-gitlab-ci-cd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Gitlab Pipeline – rules – What is rules in GitLab CI/CD?</title>
		<link>https://www.bestdevops.com/gitlab-pipeline-rules-what-is-rules-in-gitlab-ci-cd/</link>
					<comments>https://www.bestdevops.com/gitlab-pipeline-rules-what-is-rules-in-gitlab-ci-cd/#respond</comments>
		
		<dc:creator><![CDATA[kumar k]]></dc:creator>
		<pubDate>Tue, 27 May 2025 18:25:43 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=31367</guid>

					<description><![CDATA[The rules: keyword is the recommended and most powerful way to control whether a job is added to a pipeline [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The <code>rules:</code> keyword is the recommended and most powerful way to control whether a job is added to a pipeline and under what conditions it should run. It allows for complex logic using CI/CD variables, file changes, and more, offering greater flexibility than the older <code>only</code>/<code>except</code> keywords.</p>



<p class="wp-block-paragraph">A <code>rules</code> section is an array of individual rule objects. These rules are evaluated in order from top to bottom for each job. <strong>The first rule that matches determines the job&#8217;s behavior.</strong></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Example <code>.gitlab-ci.yml</code> with <code>rules</code>:</h3>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .gitlab-ci.yml</span>

stages:
  - build
  - test
  - security
  - deploy
  - report

<span class="hljs-keyword">default</span>:
  image: alpine:latest

<span class="hljs-comment"># Job 1: Runs only on pushes to the default branch (e.g., 'main' or 'master')</span>
build_default_branch:
  stage: build
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Building for default branch: $CI_DEFAULT_BRANCH ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Commit on branch: $CI_COMMIT_BRANCH"</span>
  rules:
    - <span class="hljs-keyword">if</span>: <span class="hljs-string">'$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH &amp;&amp; $CI_PIPELINE_SOURCE == "push"'</span>
      <span class="hljs-comment"># 'when: on_success' is implied if 'when' is not specified for an 'if' rule</span>

<span class="hljs-comment"># Job 2: Runs only when a Git tag is pushed</span>
deploy_on_tag:
  stage: deploy
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Deploying for tag: $CI_COMMIT_TAG ---"</span>
  rules:
    - <span class="hljs-keyword">if</span>: <span class="hljs-string">'$CI_COMMIT_TAG'</span> <span class="hljs-comment"># This condition is true if a tag is present</span>
      when: on_success <span class="hljs-comment"># Explicitly stating the default when job should run</span>

<span class="hljs-comment"># Job 3: Manual job for merge requests, allows failure</span>
test_on_merge_request:
  stage: test
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Testing for Merge Request: $CI_MERGE_REQUEST_IID ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Source branch: $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Target branch: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME"</span>
    <span class="hljs-comment"># - exit 1 # Uncomment to simulate a failure</span>
  rules:
    - <span class="hljs-keyword">if</span>: <span class="hljs-string">'$CI_PIPELINE_SOURCE == "merge_request_event"'</span>
      when: manual <span class="hljs-comment"># Job will be created but needs to be started manually from the UI</span>
      allow_failure: <span class="hljs-keyword">true</span> <span class="hljs-comment"># If this job fails, it won't cause the whole pipeline to fail</span>

<span class="hljs-comment"># Job 4: Runs only if files in the 'docs/' directory have changed on a push event</span>
build_docs:
  stage: build
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Building documentation because files in 'docs/' changed ---"</span>
  rules:
    - <span class="hljs-keyword">if</span>: <span class="hljs-string">'$CI_PIPELINE_SOURCE == "push"'</span> <span class="hljs-comment"># Only consider push events for changes</span>
      changes:
        - docs<span class="hljs-comment">/**/</span>* <span class="hljs-comment"># Glob pattern for any file within the docs directory or its subdirectories</span>
        - README.md
      <span class="hljs-comment"># If 'changes' are detected and the 'if' condition is met, the job runs.</span>

<span class="hljs-comment"># Job 5: Runs only if a specific file (e.g., a Dockerfile) exists in the repository</span>
docker_build_if_exists:
  stage: build
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Dockerfile found, proceeding with Docker build ---"</span>
    <span class="hljs-comment"># - docker build -t my-image . # Actual docker build command</span>
  rules:
    - <span class="hljs-keyword">if</span>: <span class="hljs-string">'$CI_COMMIT_BRANCH'</span> <span class="hljs-comment"># Ensure it runs for branch commits, not other events unless specified</span>
      exists:
        - Dockerfile <span class="hljs-comment"># Path to the file to check, relative to project root</span>
        <span class="hljs-comment"># - another-required-file.txt</span>
      <span class="hljs-comment"># If 'Dockerfile' exists and the 'if' condition is met, the job runs.</span>

<span class="hljs-comment"># Job 6: A job that is explicitly prevented from running in any 'push' pipeline, but could run for other types if rules were added</span>
never_run_on_push:
  stage: report
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This job should not run on push events."</span>
  rules:
    - <span class="hljs-keyword">if</span>: <span class="hljs-string">'$CI_PIPELINE_SOURCE == "push"'</span>
      when: never <span class="hljs-comment"># Explicitly prevents the job from being added to the pipeline for push events</span>
    <span class="hljs-comment"># - if: '$CI_PIPELINE_SOURCE == "schedule"' # Example: but it could run for schedules</span>
    <span class="hljs-comment">#   when: always</span>

<span class="hljs-comment"># Job 7: A job with a delayed execution for non-critical tasks</span>
delayed_notification:
  stage: report
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Sending a delayed notification ---"</span>
  rules:
    - <span class="hljs-keyword">if</span>: <span class="hljs-string">'$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH &amp;&amp; $CI_PIPELINE_SOURCE == "push"'</span>
      when: delayed
      start_in: <span class="hljs-string">'5 minutes'</span> <span class="hljs-comment"># Job will start 5 minutes after the pipeline completes this stage successfully</span>

<span class="hljs-comment"># Job 8: Catch-all rule if no other rules in this job match (optional)</span>
<span class="hljs-comment"># If a job has rules, and none of them match, the job is NOT added to the pipeline by default.</span>
<span class="hljs-comment"># To change this, you can add a final rule without an 'if' clause.</span>
optional_job_always_manual:
  stage: report
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This is an optional manual job."</span>
  rules:
    - <span class="hljs-keyword">if</span>: <span class="hljs-string">'$CI_COMMIT_BRANCH == "feature/special-feature"'</span> <span class="hljs-comment"># Runs normally for this specific branch</span>
    - when: manual <span class="hljs-comment"># For all other cases where the above 'if' didn't match, make it manual</span>

</code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Explanation:</h3>



<ol class="wp-block-list">
<li><strong><code>rules:</code> Keyword:</strong>
<ul class="wp-block-list">
<li>Used within a job definition. It takes an array of rule objects.</li>



<li>Rules are evaluated in the order they are listed. <strong>The first rule that matches determines the job&#8217;s behavior.</strong></li>



<li>If no rules match for a job, the job is <strong>not</strong> added to the pipeline by default.</li>
</ul>
</li>



<li>Structure of a Rule:Each item in the rules array is an object that can contain several clauses:
<ul class="wp-block-list">
<li><strong><code>if:</code></strong>: An expression that is evaluated. If true, this rule matches (unless other conditions like <code>changes</code> or <code>exists</code> are also present and don&#8217;t match). You use CI/CD predefined variables here.
<ul class="wp-block-list">
<li>Operators: <code>==</code> (equals), <code>!=</code> (not equals), <code>=~</code> (regex match), <code>!~</code> (regex no match), <code>&amp;&amp;</code> (AND), <code>||</code> (OR &#8211; though multiple <code>if</code> clauses in separate rules act like OR for the job). Parentheses <code>()</code> can be used for grouping.</li>
</ul>
</li>



<li><strong><code>when:</code></strong>: Defines what to do if the rule matches.
<ul class="wp-block-list">
<li><code>on_success</code> (default if <code>if</code> is present and <code>when</code> is omitted): Run the job automatically if the stage is reached.</li>



<li><code>manual</code>: Add the job to the pipeline, but it requires manual action (clicking a play button) to start.</li>



<li><code>delayed</code>: Run the job automatically after a specified duration once its stage is reached and preceding jobs are complete. Requires <code>start_in</code>.</li>



<li><code>never</code>: Do not add the job to the pipeline if this rule matches.</li>



<li><code>always</code>: Run the job regardless of the status of earlier stage jobs (use with caution, often combined with <code>allow_failure: true</code>).</li>
</ul>
</li>



<li><strong><code>changes:</code></strong>: An array of file paths or glob patterns. The rule matches only if files matching these patterns have changed in the latest push (compared to the previous commit on the same branch, or for MRs, compared to the target branch).</li>



<li><strong><code>exists:</code></strong>: An array of file paths or glob patterns. The rule matches only if all specified files/paths exist in the repository at the commit being processed.</li>



<li><strong><code>allow_failure:</code></strong>: (boolean, defaults to <code>false</code>) If <code>true</code>, the pipeline will continue to the next stage even if this job fails. This can be set per rule.</li>



<li><strong><code>variables:</code></strong>: Define job-specific variables if this rule matches.</li>
</ul>
</li>



<li><strong><code>build_default_branch</code> (Job 1):</strong>
<ul class="wp-block-list">
<li><code>if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH &amp;&amp; $CI_PIPELINE_SOURCE == "push"'</code>: This job runs only if the commit is on the default branch AND the pipeline was triggered by a <code>push</code> event. The <code>when: on_success</code> is implied.</li>
</ul>
</li>



<li><strong><code>deploy_on_tag</code> (Job 2):</strong>
<ul class="wp-block-list">
<li><code>if: '$CI_COMMIT_TAG'</code>: This job runs if the <code>$CI_COMMIT_TAG</code> variable is set (meaning a Git tag was pushed).</li>
</ul>
</li>



<li><strong><code>test_on_merge_request</code> (Job 3):</strong>
<ul class="wp-block-list">
<li><code>if: '$CI_PIPELINE_SOURCE == "merge_request_event"'</code>: Runs for merge request events.</li>



<li><code>when: manual</code>: It will appear in the pipeline but won&#8217;t run automatically.</li>



<li><code>allow_failure: true</code>: If it fails after being run manually, the overall pipeline status won&#8217;t be marked as failed.</li>
</ul>
</li>



<li><strong><code>build_docs</code> (Job 4):</strong>
<ul class="wp-block-list">
<li><code>if: '$CI_PIPELINE_SOURCE == "push"'</code>: Condition based on pipeline source.</li>



<li><code>changes: - docs/**/* - README.md</code>: The job only runs if there are changes in the <code>docs</code> directory or the <code>README.md</code> file for that push event.</li>
</ul>
</li>



<li><strong><code>docker_build_if_exists</code> (Job 5):</strong>
<ul class="wp-block-list">
<li><code>if: '$CI_COMMIT_BRANCH'</code>: A general condition to ensure it runs for branches.</li>



<li><code>exists: - Dockerfile</code>: The job runs only if a <code>Dockerfile</code> exists at the root of the repository for the given commit.</li>
</ul>
</li>



<li><strong><code>never_run_on_push</code> (Job 6):</strong>
<ul class="wp-block-list">
<li><code>if: '$CI_PIPELINE_SOURCE == "push"'</code> combined with <code>when: never</code>: This effectively blocks the job from running on any push event. You could add other rules below it to make it run for other events (e.g., schedules).</li>
</ul>
</li>



<li><strong><code>delayed_notification</code> (Job 7):</strong>
<ul class="wp-block-list">
<li><code>when: delayed</code> and <code>start_in: '5 minutes'</code>: This job will automatically start 5 minutes after its stage (<code>report</code>) is reached and preceding jobs in that stage (if any) are complete, but only for pushes to the default branch.</li>
</ul>
</li>



<li><strong><code>optional_job_always_manual</code> (Job 8):</strong>
<ul class="wp-block-list">
<li>The first rule <code>if: '$CI_COMMIT_BRANCH == "feature/special-feature"'</code> makes the job run normally (auto) for this specific branch.</li>



<li>The second rule <code>when: manual</code> has no <code>if</code>. This acts as a catch-all. If the first rule didn&#8217;t match, this second rule will match, and the job will be added as a manual job.</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Benefits of <code>rules:</code>:</h3>



<ul class="wp-block-list">
<li><strong>Clarity:</strong> Conditions are often easier to read and understand than complex <code>only</code>/<code>except</code> combinations.</li>



<li><strong>Power:</strong> Allows more complex conditions, including checks for file changes (<code>changes</code>), file existence (<code>exists</code>), and variable comparisons with regex.</li>



<li><strong>Control:</strong> Provides fine-grained control over <code>when</code> a job runs (manual, delayed) and <code>allow_failure</code> on a per-rule basis.</li>



<li><strong>Single Source of Truth:</strong> Replaces the need for both <code>only</code> and <code>except</code>.</li>
</ul>



<p class="wp-block-paragraph"><code>rules:</code> is a fundamental concept for modern GitLab CI/CD, allowing you to build highly efficient and precise pipelines.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/gitlab-pipeline-rules-what-is-rules-in-gitlab-ci-cd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Gitlab Pipeline – except – What is except in GitLab CI/CD?</title>
		<link>https://www.bestdevops.com/gitlab-pipeline-stages-what-is-stages-in-gitlab-ci-cd/</link>
					<comments>https://www.bestdevops.com/gitlab-pipeline-stages-what-is-stages-in-gitlab-ci-cd/#respond</comments>
		
		<dc:creator><![CDATA[kumar k]]></dc:creator>
		<pubDate>Tue, 27 May 2025 18:21:50 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=31363</guid>

					<description><![CDATA[The except keyword in a job definition specifies a blacklist of conditions under which that job should not be created [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The <code>except</code> keyword in a job definition specifies a <strong>blacklist of conditions</strong> under which that job should <strong>not</strong> be created and run. If any of the conditions defined in <code>except</code> are met for a given pipeline trigger (like a push to a specific branch, a tag creation, etc.), the job will be skipped. If none of the <code>except</code> conditions are met, the job will be considered for creation (and will run if no <code>only</code> clause prevents it, or if it has no <code>only</code> clause).</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"><strong>Important Note:</strong> Just like with <code>only</code>, while <code>except</code> still functions, GitLab&#8217;s current best practice and strong recommendation is to use the <strong><code>rules:</code> keyword instead</strong>. <code>rules:</code> offer significantly more power, flexibility, and clarity for controlling when jobs run or don&#8217;t run. This example is provided because you specifically asked about <code>except</code>. Please consider using <code>rules:</code> for your future and more complex pipeline configurations.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Example <code>.gitlab-ci.yml</code> with <code>except</code>:</h3>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .gitlab-ci.yml</span>

stages:
  - build
  - test
  - deploy
  - cleanup

<span class="hljs-keyword">default</span>:
  image: alpine:latest

<span class="hljs-comment"># Job 1: Runs on all branches EXCEPT 'main'</span>
build_on_feature_branches:
  stage: build
  except:
    - main <span class="hljs-comment"># Can also be written as refs: - main</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Building on a feature branch (not main) ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Current branch: $CI_COMMIT_REF_NAME"</span>

<span class="hljs-comment"># Job 2: Runs for all pipeline triggers EXCEPT when Git tags are pushed</span>
test_everything_but_tags:
  stage: test
  except:
    - tags <span class="hljs-comment"># Special keyword for any tag</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Running tests (not for a tag) ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Pipeline source: $CI_PIPELINE_SOURCE"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This job does NOT run when a tag is pushed."</span>

<span class="hljs-comment"># Job 3: Runs for all pipeline triggers EXCEPT for merge request events</span>
deploy_to_staging_not_for_mr:
  stage: deploy
  except:
    - merge_requests <span class="hljs-comment"># Special keyword for merge request pipelines</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Deploying to Staging (not for an MR) ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This job runs for direct pushes, tags, schedules, etc., but NOT for merge requests."</span>

<span class="hljs-comment"># Job 4: Runs for all pipeline triggers EXCEPT for scheduled pipelines</span>
manual_cleanup_only:
  stage: cleanup
  except:
    - schedules <span class="hljs-comment"># Special keyword for scheduled pipelines</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Manual Cleanup Task (not for schedules) ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This job does NOT run for scheduled pipelines."</span>

<span class="hljs-comment"># Job 5: Excludes multiple specific branches</span>
<span class="hljs-comment"># This job runs unless the branch is 'develop' OR 'release/v1.0'</span>
build_except_specific_branches:
  stage: build
  except:
    - develop
    - release/v1<span class="hljs-number">.0</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Building (excluding develop and release/v1.0) ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Current branch is $CI_COMMIT_REF_NAME."</span>

<span class="hljs-comment"># Job 6: Runs always (no 'only' or 'except' clause)</span>
<span class="hljs-comment"># This job is included to show the default behavior.</span>
always_run_job_default:
  stage: test
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Always Run Job (Default Behavior) ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This job has no 'only' or 'except', so it runs for any pipeline trigger by default"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"(unless workflow:rules prevent the pipeline itself, or a more specific 'only' restricts it)."</span>

<span class="hljs-comment"># Job 7: Using 'refs' with 'except' (though 'rules' is better for this)</span>
<span class="hljs-comment"># This job does NOT run for branches starting with 'legacy-' OR for the 'archive' branch.</span>
<span class="hljs-comment"># <span class="hljs-doctag">Note:</span> For complex logic, 'rules' is much clearer.</span>
advanced_except_example:
  stage: cleanup
  except:
    refs:
      - /^legacy-.*$/ <span class="hljs-comment"># Regex for branches starting with legacy-</span>
      - archive
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Advanced Except Example ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Running because this is not a legacy or archive branch."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Branch: $CI_COMMIT_BRANCH"</span>

</code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Explanation:</h3>



<ol class="wp-block-list">
<li><strong><code>except:</code> Keyword:</strong>
<ul class="wp-block-list">
<li>Used within a job definition to specify conditions under which the job should <strong>not</strong> run. It acts as a blacklist.</li>



<li>The job will be skipped if <strong>any</strong> of the conditions listed under <code>except</code> are met for the event that triggered the pipeline.</li>
</ul>
</li>



<li><strong><code>build_on_feature_branches</code> Job:</strong>
<ul class="wp-block-list">
<li><code>except: - main</code>: This job will be created and run for any branch push, <em>unless</em> the push is to the <code>main</code> branch.</li>
</ul>
</li>



<li><strong><code>test_everything_but_tags</code> Job:</strong>
<ul class="wp-block-list">
<li><code>except: - tags</code>: This job will run for any pipeline trigger (branch pushes, merge requests, schedules, etc.) <em>except</em> when a Git tag is pushed.</li>
</ul>
</li>



<li><strong><code>deploy_to_staging_not_for_mr</code> Job:</strong>
<ul class="wp-block-list">
<li><code>except: - merge_requests</code>: This job will run for any pipeline trigger <em>except</em> for pipelines associated with merge request events.</li>
</ul>
</li>



<li><strong><code>manual_cleanup_only</code> Job:</strong>
<ul class="wp-block-list">
<li><code>except: - schedules</code>: This job will run for any pipeline trigger <em>except</em> when the pipeline is triggered by a predefined schedule.</li>
</ul>
</li>



<li><strong><code>build_except_specific_branches</code> Job:</strong>
<ul class="wp-block-list">
<li><code>except: - develop - release/v1.0</code>: This job will be skipped if the pipeline is for the <code>develop</code> branch OR for the <code>release/v1.0</code> branch. For all other branches/events, it will run.</li>
</ul>
</li>



<li><strong><code>always_run_job_default</code> Job:</strong>
<ul class="wp-block-list">
<li>This job has no <code>except</code> (or <code>only</code> or <code>rules</code>) clause. By default, such a job is included in all pipelines (unless a global <code>workflow:rules</code> configuration prevents the pipeline itself from running).</li>
</ul>
</li>



<li><strong><code>advanced_except_example</code> Job:</strong>
<ul class="wp-block-list">
<li>This demonstrates the <code>refs</code> keyword within <code>except</code>.</li>



<li><code>refs: - /^legacy-.*$/ - archive</code>: The job will be skipped if the ref is a branch starting with &#8220;legacy-&#8221; (regex match) OR if it&#8217;s the <code>archive</code> branch.</li>



<li><strong>Complexity Note:</strong> As with <code>only</code>, when you start combining conditions or using regex with <code>except</code>, the <code>rules:</code> syntax often provides a clearer and more maintainable way to express the logic.</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Key Concepts and Behavior:</h3>



<ul class="wp-block-list">
<li><strong>Blacklist:</strong> <code>except</code> defines when a job <em>should not</em> run. If any condition in <code>except</code> is met, the job is skipped.</li>



<li><strong>Multiple Conditions:</strong> If you list multiple items in the <code>except</code> array (e.g., <code>except: [main, develop]</code>), the job is skipped if the pipeline event matches <em>any</em> of those items (logical OR).</li>



<li><strong>Precedence:</strong> Similar to <code>only</code>, job-level <code>except</code> is evaluated after global <code>workflow:rules</code>.</li>



<li><strong>Counterpart <code>only</code>:</strong> <code>only</code> is a whitelist. You can use <code>only</code> and <code>except</code> together in the same job definition, but this is <strong>strongly discouraged</strong> as it can lead to very complex and hard-to-understand logic. <code>rules:</code> handles these scenarios much better.</li>



<li><strong>Special Keywords:</strong> The same special keywords available for <code>only</code> (like <code>tags</code>, <code>merge_requests</code>, <code>schedules</code>, <code>branches</code>, <code>web</code>, <code>api</code>, etc.) can also be used with <code>except</code>.</li>
</ul>



<h3 class="wp-block-heading"><strong>Recommendation: Use <code>rules:</code> Instead</strong></h3>



<p class="wp-block-paragraph">It&#8217;s worth reiterating: GitLab now strongly recommends using <code>rules:</code> for controlling job execution due to its superior clarity and power.</p>



<p class="wp-block-paragraph">Here&#8217;s a quick example of how <code>build_on_feature_branches</code> might look with <code>rules</code>:</p>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php">build_on_feature_branches_with_rules:
  stage: build
  rules:
    - <span class="hljs-keyword">if</span>: <span class="hljs-string">'$CI_COMMIT_BRANCH == "main"'</span>
      when: never <span class="hljs-comment"># Don't run if it's the main branch</span>
    - when: on_success <span class="hljs-comment"># Run in all other cases (e.g., feature branches)</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Building on a feature branch (using rules)"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Current branch: $CI_COMMIT_REF_NAME"</span>
</code></span></pre>


<p class="wp-block-paragraph"><code>rules:</code> allow for more complex <code>if</code> conditions using CI/CD variables, support <code>when: manual</code>, <code>when: delayed</code>, <code>allow_failure</code>, <code>exists</code> (for checking file existence), and generally make your pipeline&#8217;s conditional logic much more explicit and maintainable.</p>



<p class="wp-block-paragraph">While understanding <code>except</code> is useful, especially if you encounter it in older GitLab CI configurations, aim to use <code>rules:</code> for any new CI/CD pipeline development or when refactoring existing ones.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/gitlab-pipeline-stages-what-is-stages-in-gitlab-ci-cd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Gitlab Pipeline – stage – What is stage in GitLab CI/CD?</title>
		<link>https://www.bestdevops.com/gitlab-pipeline-stage-what-is-stage-in-gitlab-ci-cd/</link>
					<comments>https://www.bestdevops.com/gitlab-pipeline-stage-what-is-stage-in-gitlab-ci-cd/#respond</comments>
		
		<dc:creator><![CDATA[kumar k]]></dc:creator>
		<pubDate>Tue, 27 May 2025 10:10:12 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=31351</guid>

					<description><![CDATA[These keywords are fundamental for defining the structure and execution order of your CI/CD pipeline. Example .gitlab-ci.yml with stages and [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">These keywords are fundamental for defining the structure and execution order of your CI/CD pipeline.</p>



<ul class="wp-block-list">
<li><strong><code>stages</code> (Global):</strong> A top-level keyword that defines all possible stages in your pipeline and their order of execution.</li>



<li><strong><code>stage</code> (Job-level):</strong> A keyword used within a job definition to assign that job to one of the globally defined stages.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Example <code>.gitlab-ci.yml</code> with <code>stages</code> and <code>stage</code>:</h3>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .gitlab-ci.yml</span>

<span class="hljs-comment"># 1. Global 'stages' definition:</span>
<span class="hljs-comment"># Defines the sequence of stages in the pipeline.</span>
<span class="hljs-comment"># Jobs in earlier stages must complete successfully before jobs in later stages can start.</span>
stages:
  - build_assets  <span class="hljs-comment"># First stage</span>
  - run_tests     <span class="hljs-comment"># Second stage</span>
  - deploy_app    <span class="hljs-comment"># Third stage</span>

<span class="hljs-keyword">default</span>:
  image: alpine:latest <span class="hljs-comment"># Using a lightweight default image for our jobs</span>

<span class="hljs-comment"># --- Jobs for the 'build_assets' stage ---</span>
compile_code:
  stage: build_assets <span class="hljs-comment"># 2. Assigning this job to the 'build_assets' stage</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Compiling Code (Stage: build_assets) ---"</span>
    - sleep <span class="hljs-number">5</span> <span class="hljs-comment"># Simulate work</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Code compilation complete."</span>

package_application:
  stage: build_assets <span class="hljs-comment"># This job is also in the 'build_assets' stage</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Packaging Application (Stage: build_assets) ---"</span>
    - sleep <span class="hljs-number">7</span> <span class="hljs-comment"># Simulate work</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Application packaging complete."</span>

<span class="hljs-comment"># --- Jobs for the 'run_tests' stage ---</span>
unit_tests:
  stage: run_tests <span class="hljs-comment"># Assigning this job to the 'run_tests' stage</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Running Unit Tests (Stage: run_tests) ---"</span>
    - sleep <span class="hljs-number">10</span> <span class="hljs-comment"># Simulate work</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Unit tests PASSED."</span>

integration_tests:
  stage: run_tests <span class="hljs-comment"># This job is also in the 'run_tests' stage</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Running Integration Tests (Stage: run_tests) ---"</span>
    - sleep <span class="hljs-number">12</span> <span class="hljs-comment"># Simulate work</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Integration tests PASSED."</span>
    <span class="hljs-comment"># - exit 1 # Uncomment this line to simulate a test failure and see subsequent stages not run</span>

<span class="hljs-comment"># --- Job for the 'deploy_app' stage ---</span>
deploy_to_production:
  stage: deploy_app <span class="hljs-comment"># Assigning this job to the 'deploy_app' stage</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Deploying to Production (Stage: deploy_app) ---"</span>
    - sleep <span class="hljs-number">8</span> <span class="hljs-comment"># Simulate work</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Deployment to production successful!"</span>
  when: on_success <span class="hljs-comment"># Default, but good to be explicit for deploy jobs</span>

</code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Explanation:</h3>



<ol class="wp-block-list">
<li><strong>Global <code>stages</code> Definition:</strong>
<ul class="wp-block-list">
<li><code>stages:</code> at the top level of your <code>.gitlab-ci.yml</code> file lists all the stages your pipeline will have.</li>



<li><strong>Order Matters:</strong> The order in which you list the stages here dictates the sequence of execution for the entire pipeline.
<ul class="wp-block-list">
<li>In this example: <code>build_assets</code> will run first, then <code>run_tests</code>, and finally <code>deploy_app</code>.</li>
</ul>
</li>



<li>If this global <code>stages</code> list is not defined, GitLab CI defaults to a set of predefined stages (<code>build</code>, <code>test</code>, <code>deploy</code>), and if a job doesn&#8217;t specify a <code>stage</code>, it defaults to <code>test</code>. However, it&#8217;s a <strong>strong best practice to always define your <code>stages</code> explicitly</strong> for clarity and control.</li>
</ul>
</li>



<li><strong>Job-Level <code>stage:</code> Keyword:</strong>
<ul class="wp-block-list">
<li>Inside each job definition (e.g., <code>compile_code</code>, <code>unit_tests</code>), the <code>stage:</code> keyword assigns that job to one of the stages previously listed in the global <code>stages</code> definition.</li>



<li>A job <strong>must</strong> belong to a stage that is defined in the global <code>stages</code> list. If you assign a job to a stage not listed globally, you&#8217;ll get a linting error.</li>
</ul>
</li>



<li><strong>Execution Flow:</strong>
<ul class="wp-block-list">
<li><strong>Within a Stage (Parallel Execution):</strong>
<ul class="wp-block-list">
<li>All jobs belonging to the <em>same stage</em> can run in parallel if enough GitLab Runners are available.</li>



<li>For example, <code>compile_code</code> and <code>package_application</code> are both in the <code>build_assets</code> stage. They can start simultaneously.</li>



<li>Similarly, <code>unit_tests</code> and <code>integration_tests</code> (both in <code>run_tests</code>) can run in parallel.</li>
</ul>
</li>



<li><strong>Between Stages (Sequential Execution):</strong>
<ul class="wp-block-list">
<li>A stage will only start after <strong>all jobs in the preceding stage have completed successfully</strong>.</li>



<li>The <code>run_tests</code> stage (containing <code>unit_tests</code> and <code>integration_tests</code>) will only begin after <em>both</em> <code>compile_code</code> AND <code>package_application</code> from the <code>build_assets</code> stage have finished successfully.</li>



<li>The <code>deploy_app</code> stage (with <code>deploy_to_production</code>) will only begin after <em>both</em> <code>unit_tests</code> AND <code>integration_tests</code> from the <code>run_tests</code> stage have finished successfully.</li>
</ul>
</li>



<li><strong>Job Failure Impact:</strong>
<ul class="wp-block-list">
<li>If any job in a stage fails, by default:
<ul class="wp-block-list">
<li>No new jobs will start in that stage (though currently running parallel jobs in the same stage will continue unless <code>interruptible</code> is used or they depend on the failed job via <code>needs</code>).</li>



<li><strong>All subsequent stages will be skipped</strong>, and the pipeline will be marked as failed.</li>



<li>In the example, if <code>integration_tests</code> fails (e.g., by uncommenting <code>exit 1</code>), the <code>deploy_to_production</code> job in the <code>deploy_app</code> stage will not run.</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>



<li><strong><code>default:</code> Section:</strong>
<ul class="wp-block-list">
<li><code>default: image: alpine:latest</code> is just setting a default Docker image for all jobs to keep the example concise. It&#8217;s not directly related to staging but is good practice.</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Benefits of Using Stages:</h3>



<ul class="wp-block-list">
<li><strong>Control Flow:</strong> Clearly defines the order of operations in your CI/CD process.</li>



<li><strong>Logical Grouping:</strong> Groups related tasks together (e.g., all build activities, all testing activities).</li>



<li><strong>Efficiency:</strong> Allows for parallel execution of independent tasks within the same phase of your pipeline.</li>



<li><strong>Failure Management:</strong> Prevents later stages (like deployment) from running if earlier critical stages (like testing) fail.</li>



<li><strong>Readability:</strong> Makes the pipeline structure easier to understand.</li>
</ul>



<p class="wp-block-paragraph">By defining <code>stages</code> and assigning jobs to them using <code>stage:</code>, you create a structured, ordered, and manageable workflow for your GitLab CI/CD pipelines.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/gitlab-pipeline-stage-what-is-stage-in-gitlab-ci-cd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Gitlab Pipeline – script – What is script in GitLab CI/CD?</title>
		<link>https://www.bestdevops.com/gitlab-pipeline-script-what-is-script-in-gitlab-ci-cd/</link>
					<comments>https://www.bestdevops.com/gitlab-pipeline-script-what-is-script-in-gitlab-ci-cd/#respond</comments>
		
		<dc:creator><![CDATA[kumar k]]></dc:creator>
		<pubDate>Tue, 27 May 2025 10:04:43 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=31349</guid>

					<description><![CDATA[The script keyword is one of the most fundamental parts of a GitLab CI/CD job. It defines the actual shell [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The <code>script</code> keyword is one of the most fundamental parts of a GitLab CI/CD job. It defines the <strong>actual shell commands that the GitLab Runner will execute</strong> to perform the job&#8217;s tasks. This is where you put the core logic of your CI/CD process, like compiling code, running tests, building Docker images, or deploying applications.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Example <code>.gitlab-ci.yml</code> with <code>script</code>:</h3>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .gitlab-ci.yml</span>

<span class="hljs-keyword">default</span>:
  image: alpine:latest <span class="hljs-comment"># Using a lightweight default image for our jobs</span>

stages:
  - build
  - test
  - report

<span class="hljs-comment"># Job 1: Demonstrates basic single-line commands</span>
build_project:
  stage: build
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Starting Project Build ---"</span> <span class="hljs-comment"># Simple command to print a message</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Current directory:"</span>
    - ls -la <span class="hljs-comment"># Lists files in the current directory</span>
    - mkdir build_output <span class="hljs-comment"># Creates a directory</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Build files would be generated here."</span> &gt; build_output/info.txt
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Project build process finished."</span>

<span class="hljs-comment"># Job 2: Demonstrates a sequence of commands and a multi-line command</span>
run_tests:
  stage: test
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Running Tests ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Setting up test environment..."</span>
    - sleep <span class="hljs-number">2</span> <span class="hljs-comment"># Simulate some setup time</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Running test suite 1..."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Test 1.1: PASSED"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Test 1.2: PASSED"</span>
    - | <span class="hljs-comment"># This is a YAML block scalar, allowing for a multi-line script block</span>
      <span class="hljs-keyword">echo</span> <span class="hljs-string">"Running a multi-line command or a series of commands as one script step:"</span>
      <span class="hljs-keyword">echo</span> <span class="hljs-string">"  Detail 1: Checking component A"</span>
      <span class="hljs-keyword">echo</span> <span class="hljs-string">"  Detail 2: Verifying integration B"</span>
      <span class="hljs-keyword">echo</span> <span class="hljs-string">"Test suite 2 completed."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"All tests finished."</span>

<span class="hljs-comment"># Job 3: Demonstrates a script that might fail</span>
generate_report:
  stage: report
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Generating Report ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Creating report data..."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This is a report"</span> &gt; report.txt
    - cat report.txt
    <span class="hljs-comment"># - cat non_existent_file.txt # Uncomment this line to see the job fail</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Report generation successful (unless a command above failed)."</span>

</code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Explanation:</h3>



<ol class="wp-block-list">
<li><strong><code>script:</code> Keyword:</strong>
<ul class="wp-block-list">
<li>The <code>script</code> keyword is <strong>required</strong> for any job that needs to execute commands. If a job definition doesn&#8217;t have a <code>script</code> section, it might be considered a &#8220;no-op&#8221; job or a configuration error depending on other settings.</li>



<li>It takes an <strong>array of strings</strong>, where each string is a shell command.</li>
</ul>
</li>



<li><strong>Execution Environment:</strong>
<ul class="wp-block-list">
<li>The commands in the <code>script</code> section are executed by a shell (like <code>sh</code>, <code>bash</code>, or PowerShell depending on the GitLab Runner&#8217;s configuration and the specified Docker image&#8217;s default shell).</li>



<li>In this example, <code>default:image: alpine:latest</code> means all jobs will run inside a Docker container based on the <code>alpine:latest</code> image, and the commands will be run by Alpine&#8217;s <code>sh</code>.</li>
</ul>
</li>



<li><strong><code>build_project</code> Job:</strong>
<ul class="wp-block-list">
<li><strong><code>echo "--- Starting Project Build ---"</code></strong>: A simple command to print a message to the job log.</li>



<li><strong><code>ls -la</code></strong>: Lists files and directories in the job&#8217;s working directory.</li>



<li><strong><code>mkdir build_output</code></strong>: Creates a new directory.</li>



<li><strong><code>echo "Build files..." > build_output/info.txt</code></strong>: Creates a file with some content.</li>



<li><strong>Sequential Execution:</strong> The commands are executed one after the other, in the order they are listed.</li>
</ul>
</li>



<li><strong><code>run_tests</code> Job:</strong>
<ul class="wp-block-list">
<li>This job also shows a sequence of <code>echo</code> commands.</li>



<li><strong><code>|</code> (YAML Literal Block Scalar):</strong>
<ul class="wp-block-list">
<li>The <code>|</code> character at the start of the script block allows you to write multi-line strings more easily. Each line under it (preserving indentation) is treated as part of the same script command or a sequence of commands passed to the shell.</li>



<li>In this case, it&#8217;s used to group several <code>echo</code> statements that logically belong together for readability. Each of these <code>echo</code> commands is still executed individually by the shell.</li>



<li>You could also write a long single command that spans multiple lines in your YAML editor, and as long as it&#8217;s a valid shell command, it will work.</li>
</ul>
</li>
</ul>
</li>



<li><strong><code>generate_report</code> Job:</strong>
<ul class="wp-block-list">
<li>This job demonstrates a typical sequence.</li>



<li><strong>Failure Handling:</strong> If any command in a <code>script</code> block exits with a non-zero status code (which typically indicates an error), GitLab CI will, by default:
<ul class="wp-block-list">
<li>Stop executing subsequent commands in that <code>script</code> block.</li>



<li>Mark the job as <strong>failed</strong>.</li>



<li>The pipeline might stop at that point, depending on its configuration (e.g., <code>allow_failure</code> settings on the job or stage configurations).</li>
</ul>
</li>



<li>If you uncomment <code>- cat non_existent_file.txt</code>, the <code>cat</code> command will fail because the file doesn&#8217;t exist, causing the <code>generate_report</code> job to fail.</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Key Concepts and Behavior:</h3>



<ul class="wp-block-list">
<li><strong>Heart of the Job:</strong> The <code>script</code> section defines the primary actions the job performs.</li>



<li><strong>Array of Commands:</strong> Always an array, even if there&#8217;s only one command. YAML<code>my_job: script: "echo 'Single command still needs to be in an array or be the only item'" # Or more commonly: my_job: script: - "echo 'Single command'"</code></li>



<li><strong>Working Directory:</strong> Commands are executed in the context of the cloned repository, specifically <code>$CI_PROJECT_DIR</code>.</li>



<li><strong>Shell Interpreter:</strong> The specific shell used depends on the Docker image and the GitLab Runner configuration. You can often find out which shell is used by adding <code>echo $SHELL</code> or <code>ps -p $$</code> to your script.</li>



<li><strong>Exit Codes:</strong> The success or failure of each command (and thus the job) is determined by its exit code. <code>0</code> usually means success, and any non-zero value means failure.</li>



<li><strong>Environment Variables:</strong> You can use predefined CI/CD variables (like <code>$CI_PROJECT_DIR</code>, <code>$CI_COMMIT_SHA</code>) and user-defined variables within your script commands.</li>
</ul>



<p class="wp-block-paragraph">The <code>script</code> section is where you&#8217;ll spend most of your time defining the logic for your CI/CD jobs, whether it&#8217;s building, testing, deploying, or automating any other task.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/gitlab-pipeline-script-what-is-script-in-gitlab-ci-cd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Gitlab Pipeline – pages – What is pages in GitLab CI/CD?</title>
		<link>https://www.bestdevops.com/gitlab-pipeline-pages-what-is-pages-in-gitlab-ci-cd/</link>
					<comments>https://www.bestdevops.com/gitlab-pipeline-pages-what-is-pages-in-gitlab-ci-cd/#respond</comments>
		
		<dc:creator><![CDATA[kumar k]]></dc:creator>
		<pubDate>Tue, 27 May 2025 09:54:41 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=31346</guid>

					<description><![CDATA[GitLab Pages allows you to publish static websites directly from a GitLab repository. The content for these sites is generated [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">GitLab Pages allows you to publish static websites directly from a GitLab repository. The content for these sites is generated and deployed via a specific CI/CD job conventionally named <code>pages</code>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Example <code>.gitlab-ci.yml</code> for GitLab Pages:</h3>



<p class="wp-block-paragraph">This example will create a very simple static HTML page and deploy it.</p>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .gitlab-ci.yml</span>

stages:
  - deploy <span class="hljs-comment"># A stage for the pages deployment job</span>

<span class="hljs-comment"># This is the special job that GitLab Pages looks for.</span>
<span class="hljs-comment"># It must be named 'pages'.</span>
pages:
  stage: deploy
  image: alpine:latest <span class="hljs-comment"># A lightweight image is sufficient for this simple example</span>

  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Generating static site for GitLab Pages ---"</span>
    <span class="hljs-comment"># 1. Create the directory GitLab Pages expects for site content</span>
    <span class="hljs-comment">#    This directory MUST be named 'public'.</span>
    - mkdir -p <span class="hljs-keyword">public</span>

    <span class="hljs-comment"># 2. Create some static content.</span>
    <span class="hljs-comment">#    In a real project, this step would involve running a static site generator</span>
    <span class="hljs-comment">#    (like Jekyll, Hugo, MkDocs, VuePress, Gatsby, or just copying HTML/CSS/JS files).</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">'&lt;!DOCTYPE html&gt;'</span> &gt; <span class="hljs-keyword">public</span>/index.html
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">'&lt;html lang="en"&gt;'</span> &gt;&gt; <span class="hljs-keyword">public</span>/index.html
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">'  &lt;head&gt;'</span> &gt;&gt; <span class="hljs-keyword">public</span>/index.html
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">'    &lt;meta charset="UTF-8"&gt;'</span> &gt;&gt; <span class="hljs-keyword">public</span>/index.html
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">'    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;'</span> &gt;&gt; <span class="hljs-keyword">public</span>/index.html
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">'    &lt;title&gt;My GitLab Pages Site&lt;/title&gt;'</span> &gt;&gt; <span class="hljs-keyword">public</span>/index.html
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">'    &lt;style&gt;'</span> &gt;&gt; <span class="hljs-keyword">public</span>/index.html
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">'      body { font-family: sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background-color: #f0f0f0; }'</span> &gt;&gt; <span class="hljs-keyword">public</span>/index.html
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">'      .container { text-align: center; padding: 20px; background-color: white; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1); }'</span> &gt;&gt; <span class="hljs-keyword">public</span>/index.html
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">'      h1 { color: #333; }'</span> &gt;&gt; <span class="hljs-keyword">public</span>/index.html
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">'      p { color: #555; }'</span> &gt;&gt; <span class="hljs-keyword">public</span>/index.html
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">'    &lt;/style&gt;'</span> &gt;&gt; <span class="hljs-keyword">public</span>/index.html
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">'  &lt;/head&gt;'</span> &gt;&gt; <span class="hljs-keyword">public</span>/index.html
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">'  &lt;body&gt;'</span> &gt;&gt; <span class="hljs-keyword">public</span>/index.html
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">'    &lt;div class="container"&gt;'</span> &gt;&gt; <span class="hljs-keyword">public</span>/index.html
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">'      &lt;h1&gt;Hello from GitLab Pages!&lt;/h1&gt;'</span> &gt;&gt; <span class="hljs-keyword">public</span>/index.html
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"      &lt;p&gt;This site was deployed on: $(date)&lt;/p&gt;"</span> &gt;&gt; <span class="hljs-keyword">public</span>/index.html
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">'      &lt;p&gt;Deployed from commit: &lt;a href="${CI_PROJECT_URL}/-/commit/${CI_COMMIT_SHA}"&gt;${CI_COMMIT_SHORT_SHA}&lt;/a&gt; on branch &lt;em&gt;${CI_COMMIT_REF_NAME}&lt;/em&gt;.&lt;/p&gt;'</span> &gt;&gt; <span class="hljs-keyword">public</span>/index.html
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">'    &lt;/div&gt;'</span> &gt;&gt; <span class="hljs-keyword">public</span>/index.html
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">'  &lt;/body&gt;'</span> &gt;&gt; <span class="hljs-keyword">public</span>/index.html
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">'&lt;/html&gt;'</span> &gt;&gt; <span class="hljs-keyword">public</span>/index.html

    <span class="hljs-comment"># You can create more files and subdirectories within 'public/'</span>
    - mkdir -p <span class="hljs-keyword">public</span>/about
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"&lt;h1&gt;About Us&lt;/h1&gt;&lt;p&gt;This is the about page.&lt;/p&gt;&lt;a href='../'&gt;Home&lt;/a&gt;"</span> &gt; <span class="hljs-keyword">public</span>/about/index.html

    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Static site content generated in 'public/' directory."</span>

  artifacts:
    paths:
      <span class="hljs-comment"># 3. This path MUST be 'public'. GitLab Pages serves files from this directory.</span>
      - <span class="hljs-keyword">public</span>
    expire_in: <span class="hljs-number">1</span> week <span class="hljs-comment"># Optional: How long to keep the job artifacts</span>

  rules:
    <span class="hljs-comment"># 4. Deploy GitLab Pages only when pushing to the default branch (e.g., main or master)</span>
    <span class="hljs-comment">#    Adjust $CI_DEFAULT_BRANCH if your default branch has a different name.</span>
    - <span class="hljs-keyword">if</span>: <span class="hljs-string">'$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'</span>
      when: on_success <span class="hljs-comment"># Run only if the script succeeds</span>

</code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Explanation:</h3>



<ol class="wp-block-list">
<li><strong>Job Naming (<code>pages</code>):</strong>
<ul class="wp-block-list">
<li>The job responsible for deploying to GitLab Pages <strong>must be named <code>pages</code></strong>. This is a special convention that GitLab recognizes.</li>
</ul>
</li>



<li><strong><code>stage: deploy</code></strong>:
<ul class="wp-block-list">
<li>While you can name your stage anything, <code>deploy</code> is a common and logical choice for a job that deploys a website.</li>
</ul>
</li>



<li><strong><code>image: alpine:latest</code></strong>:
<ul class="wp-block-list">
<li>For this very simple example of echoing HTML content, a lightweight image like <code>alpine</code> is sufficient.</li>



<li>In real-world scenarios, you would use an image that contains your static site generator (e.g., <code>ruby</code> for Jekyll, an image with Node.js for Gatsby/VuePress, <code>python</code> for MkDocs, or a specific image like <code>klakegg/hugo</code>).</li>
</ul>
</li>



<li><strong><code>script:</code> Section:</strong>
<ul class="wp-block-list">
<li><strong><code>mkdir -p public</code></strong>: This command creates a directory named <code>public</code>. All the static content (HTML, CSS, JavaScript, images, etc.) that you want to publish <strong>must</strong> be placed inside this <code>public</code> directory.</li>



<li><strong><code>echo ... > public/index.html</code></strong>: These lines are a simple way to create a basic <code>index.html</code> file inside the <code>public</code> directory. In a real project, this section would contain commands to:
<ul class="wp-block-list">
<li>Install dependencies for your static site generator (e.g., <code>npm install</code>, <code>bundle install</code>, <code>pip install -r requirements.txt</code>).</li>



<li>Run the build command of your static site generator (e.g., <code>hugo</code>, <code>jekyll build</code>, <code>npm run build</code>, <code>mkdocs build</code>). This command typically outputs the static site into a specific folder (like <code>_site</code>, <code>dist</code>, <code>build</code>, <code>site</code>), which you would then need to copy or move into the <code>public</code> directory.</li>



<li>Example for a hypothetical generator: YAML<code># script: # - npm install # - npm run build # Assume this outputs to a './dist' folder # - rm -rf public # Clean up previous content if any # - mv dist public # Move the generated site to 'public'</code></li>
</ul>
</li>
</ul>
</li>



<li><strong><code>artifacts:</code> Section:</strong>
<ul class="wp-block-list">
<li>This is a <strong>critical</strong> part of the <code>pages</code> job.</li>



<li><strong><code>paths: - public</code></strong>: This tells GitLab to take the entire contents of the <code>public</code> directory and save it as job artifacts. GitLab Pages then uses these specific artifacts from the latest successful <code>pages</code> job on the appropriate branch to serve your website.</li>



<li><strong><code>expire_in: 1 week</code></strong>: (Optional) Specifies how long the job artifacts should be kept. For GitLab Pages, the artifacts are used for deployment and are not typically needed for long-term storage in the job artifacts section itself, as the deployed site persists.</li>
</ul>
</li>



<li><strong><code>rules:</code> Section:</strong>
<ul class="wp-block-list">
<li><strong><code>- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'</code></strong>: This rule ensures that the <code>pages</code> job (and thus the website deployment) only runs when changes are pushed or merged to the default branch of your repository (commonly <code>main</code> or <code>master</code>). This prevents deploying every commit from feature branches.</li>



<li><strong><code>when: on_success</code></strong>: The job will only proceed if the script commands are successful.</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">How GitLab Pages Works with This Job:</h3>



<ol class="wp-block-list">
<li>When you commit changes to your default branch (as defined in the <code>rules</code>), the GitLab CI pipeline triggers.</li>



<li>The <code>pages</code> job runs.</li>



<li>The <code>script</code> section generates your static site content and places it in the <code>public</code> directory.</li>



<li>The <code>artifacts</code> section uploads the <code>public</code> directory.</li>



<li>GitLab takes these artifacts and deploys them to a web server.</li>



<li>Your static site becomes available at a URL typically structured like:
<ul class="wp-block-list">
<li>For projects under your username: <code>https://&lt;username>.gitlab.io/&lt;projectname></code></li>



<li>For projects within a group: <code>https://&lt;groupname>.gitlab.io/&lt;projectname></code></li>



<li>If you&#8217;ve configured a custom domain, it will be available at that domain.</li>
</ul>
</li>
</ol>



<p class="wp-block-paragraph">You can find the exact URL for your GitLab Pages site in your project&#8217;s <strong>Settings &gt; Pages</strong> section after the first successful deployment.</p>



<p class="wp-block-paragraph">This basic example provides the fundamental structure. You would replace the <code>echo</code> commands with the actual build process for your chosen static site generator.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/gitlab-pipeline-pages-what-is-pages-in-gitlab-ci-cd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Gitlab Pipeline – cache – What is cache in GitLab CI/CD?</title>
		<link>https://www.bestdevops.com/gitlab-pipeline-cache-what-is-cache-in-gitlab-ci-cd/</link>
					<comments>https://www.bestdevops.com/gitlab-pipeline-cache-what-is-cache-in-gitlab-ci-cd/#respond</comments>
		
		<dc:creator><![CDATA[kumar k]]></dc:creator>
		<pubDate>Tue, 27 May 2025 09:34:57 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=31343</guid>

					<description><![CDATA[The cache keyword in GitLab CI/CD is used to specify a list of files and directories that should be saved [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The <code>cache</code> keyword in GitLab CI/CD is used to specify a list of files and directories that should be saved (cached) after a job finishes successfully and restored before the next run of that job (or other jobs with the same cache key). This helps to speed up your pipelines by reusing downloaded dependencies or other files that take time to generate, rather than fetching or rebuilding them every time.</p>



<p class="wp-block-paragraph">This example will demonstrate caching <code>node_modules</code> for a Node.js project, which is a very common use case.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Example <code>.gitlab-ci.yml</code> with <code>cache</code>:</h3>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .gitlab-ci.yml</span>

<span class="hljs-comment"># 1. Global Cache Definition (applied to all jobs by default unless overridden)</span>
<span class="hljs-comment">#    Alternatively, you can place this under 'default:cache:'</span>
cache:
  key: <span class="hljs-string">"$CI_COMMIT_REF_SLUG"</span> <span class="hljs-comment"># Creates a cache per branch/tag</span>
  paths:
    - node_modules/ <span class="hljs-comment"># Cache the node_modules directory</span>
  policy: pull-push <span class="hljs-comment"># Default policy: pull the cache at the start, push (update) at the end</span>
  when: on_success <span class="hljs-comment"># Default: save cache only if the job succeeds</span>

stages:
  - setup
  - build
  - test

<span class="hljs-comment"># Job 1: Installs dependencies and builds the project</span>
<span class="hljs-comment"># This job will create and push the cache on its first successful run.</span>
<span class="hljs-comment"># Subsequent runs on the same branch (if node_modules is still valid) will pull the cache.</span>
install_and_build:
  stage: setup
  image: node:<span class="hljs-number">18</span>-alpine
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Install and Build Job ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"CI_COMMIT_REF_SLUG is: $CI_COMMIT_REF_SLUG, this determines cache scope if not overridden by file key."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Checking if node_modules directory exists from a previous cache restore..."</span>
    - <span class="hljs-keyword">if</span> &#91; -d <span class="hljs-string">"node_modules"</span> ]; then <span class="hljs-keyword">echo</span> <span class="hljs-string">"node_modules found, restored from cache."</span>; <span class="hljs-keyword">else</span> <span class="hljs-keyword">echo</span> <span class="hljs-string">"node_modules not found, will run full npm install."</span>; fi
    - npm install <span class="hljs-comment"># This will be faster if node_modules is restored from cache</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Finished npm install."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Running build command..."</span>
    - npm run build <span class="hljs-comment"># Assuming you have a 'build' script in your package.json</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Build complete."</span>

<span class="hljs-comment"># Job 2: Uses the cache created by the 'install_and_build' job (if on the same branch)</span>
<span class="hljs-comment"># This job might run tests and would benefit from not re-installing all dependencies.</span>
run_tests:
  stage: test
  image: node:<span class="hljs-number">18</span>-alpine
  <span class="hljs-comment"># This job will inherit the global cache settings by default.</span>
  <span class="hljs-comment"># It will attempt to 'pull' the cache (including node_modules/) before running.</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Test Job ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Checking if node_modules directory exists from cache..."</span>
    - <span class="hljs-keyword">if</span> &#91; -d <span class="hljs-string">"node_modules"</span> ]; then <span class="hljs-keyword">echo</span> <span class="hljs-string">"node_modules found, restored from cache for testing."</span>; <span class="hljs-keyword">else</span> <span class="hljs-keyword">echo</span> <span class="hljs-string">"node_modules not found for testing. This might happen if 'install_and_build' failed or cache key differs."</span>; fi
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Running tests..."</span>
    - npm test <span class="hljs-comment"># Assuming you have a 'test' script in your package.json</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Tests complete."</span>

<span class="hljs-comment"># Job 3: Demonstrates a more specific cache key based on a dependency file</span>
<span class="hljs-comment"># This is often a better strategy for dependency caching.</span>
lint_code:
  stage: test
  image: node:<span class="hljs-number">18</span>-alpine
  cache: <span class="hljs-comment"># Job-level cache overrides the global cache setting for this job</span>
    key:
      files:
        - package-lock.json <span class="hljs-comment"># Cache is specific to the content of package-lock.json</span>
      prefix: <span class="hljs-string">"$CI_PROJECT_NAME"</span> <span class="hljs-comment"># Optional prefix for the key</span>
    paths:
      - node_modules/
    policy: pull <span class="hljs-comment"># This job only pulls the cache, doesn't update it (useful for linters/tests)</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Lint Job ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Cache key for this job is based on package-lock.json."</span>
    - <span class="hljs-keyword">if</span> &#91; ! -d <span class="hljs-string">"node_modules"</span> ]; then npm install; <span class="hljs-keyword">else</span> <span class="hljs-keyword">echo</span> <span class="hljs-string">"node_modules found from cache."</span>; fi
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Running linter..."</span>
    - npm run lint <span class="hljs-comment"># Assuming you have a 'lint' script</span>

</code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Explanation:</h3>



<ol class="wp-block-list">
<li><strong>Global <code>cache:</code> Block:</strong>
<ul class="wp-block-list">
<li>This top-level <code>cache:</code> definition (or <code>default:cache:</code>) sets default caching behavior for all jobs in the pipeline.</li>



<li><strong><code>key: "$CI_COMMIT_REF_SLUG"</code></strong>:
<ul class="wp-block-list">
<li>The <code>key</code> is crucial. It identifies the cache. Jobs with the same cache key will share the same cache.</li>



<li><code>$CI_COMMIT_REF_SLUG</code> is a predefined GitLab variable representing the branch or tag name in a URL-friendly format. This means each branch will have its own independent cache.</li>



<li>While simple, this key might not be optimal if dependencies don&#8217;t change often within a branch.</li>
</ul>
</li>



<li><strong><code>paths:</code></strong>:
<ul class="wp-block-list">
<li>An array of files or directories to be cached.</li>



<li><code>- node_modules/</code>: This tells GitLab to cache the contents of the <code>node_modules</code> directory.</li>
</ul>
</li>



<li><strong><code>policy: pull-push</code></strong>: (Default behavior if not specified)
<ul class="wp-block-list">
<li><code>pull</code>: At the beginning of the job, GitLab attempts to download and extract the cache.</li>



<li><code>push</code>: At the end of a successful job, GitLab creates a new cache archive with the specified <code>paths</code> and uploads it.</li>
</ul>
</li>



<li><strong><code>when: on_success</code></strong>: (Default behavior if not specified)
<ul class="wp-block-list">
<li>The cache will only be saved (pushed) if the job finishes successfully. Other options include <code>on_failure</code> and <code>always</code>.</li>
</ul>
</li>
</ul>
</li>



<li><strong><code>install_and_build</code> Job:</strong>
<ul class="wp-block-list">
<li>This job inherits the global cache settings.</li>



<li><strong>First Run (or if cache doesn&#8217;t exist/key changes):</strong>
<ul class="wp-block-list">
<li><code>npm install</code> will download all dependencies and create <code>node_modules/</code>.</li>



<li>After the script successfully completes, the <code>node_modules/</code> directory will be archived and uploaded as a cache associated with the key (e.g., <code>main</code> if on the main branch).</li>
</ul>
</li>



<li><strong>Subsequent Runs (on the same branch, with the same cache key):</strong>
<ul class="wp-block-list">
<li>Before the <code>script</code> starts, GitLab will download and extract the <code>node_modules/</code> cache.</li>



<li><code>npm install</code> will then run. It should be much faster because most, if not all, dependencies are already present. It will only fetch updates or new packages.</li>
</ul>
</li>
</ul>
</li>



<li><strong><code>run_tests</code> Job:</strong>
<ul class="wp-block-list">
<li>This job also inherits the global cache settings.</li>



<li>If it runs on the same branch (and thus uses the same cache key) as a previously successful <code>install_and_build</code> job, it will pull the <code>node_modules/</code> cache. This means it doesn&#8217;t need to run <code>npm install</code> from scratch (though the example does it for demonstration, in a real scenario you might skip <code>npm install</code> if <code>node_modules</code> exists and is valid).</li>
</ul>
</li>



<li><strong><code>lint_code</code> Job (Job-Level Cache):</strong>
<ul class="wp-block-list">
<li>This job defines its own <code>cache:</code> block, which <strong>overrides</strong> the global cache settings specifically for this job.</li>



<li><strong><code>key:</code></strong>:
<ul class="wp-block-list">
<li><strong><code>files: - package-lock.json</code></strong>: This is a more robust way to key your dependency cache. The cache key will be generated based on a checksum of the <code>package-lock.json</code> file. This means the cache is only reused if the exact dependencies haven&#8217;t changed. If <code>package-lock.json</code> changes, a new cache is created.</li>



<li><strong><code>prefix: "$CI_PROJECT_NAME"</code></strong>: (Optional) Adds a prefix to the generated key, which can help avoid key collisions if multiple projects share the same cache storage and use similar file names for keys.</li>
</ul>
</li>



<li><strong><code>paths: - node_modules/</code></strong>: Still caching <code>node_modules</code>.</li>



<li><strong><code>policy: pull</code></strong>:
<ul class="wp-block-list">
<li>This job will only attempt to download (<code>pull</code>) an existing cache that matches its key.</li>



<li>It will <strong>not</strong> upload (<code>push</code>) or update the cache, even if its <code>node_modules</code> directory changes. This is often useful for jobs like linters or tests that consume dependencies but don&#8217;t modify them in a way that should update the shared cache.</li>
</ul>
</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Key Concepts and Behavior:</h3>



<ul class="wp-block-list">
<li><strong>Purpose:</strong> To speed up pipeline execution by reducing the need to re-download dependencies or re-generate files on every job run.</li>



<li><strong>How it Works:</strong>
<ol class="wp-block-list">
<li><strong>Restore (Pull):</strong> At the start of a job, GitLab Runner checks for a cache matching the job&#8217;s cache <code>key</code>. If found, it&#8217;s downloaded and extracted into the job&#8217;s working directory <em>before</em> the <code>before_script</code> runs.</li>



<li><strong>Save (Push):</strong> If the job&#8217;s cache <code>policy</code> includes <code>push</code> and the <code>when</code> condition is met (e.g., <code>on_success</code>), after the <code>after_script</code> completes, the runner archives the directories/files specified in <code>paths</code> and uploads them to the cache storage, associated with the cache <code>key</code>.</li>
</ol>
</li>



<li><strong>Cache <code>key</code> is Critical:</strong>
<ul class="wp-block-list">
<li>A good key ensures cache validity and effectiveness.</li>



<li><code>key: files:</code> is highly recommended for dependency caches as it ties the cache to the state of your dependency lock files.</li>



<li>You can also use predefined variables like <code>$CI_COMMIT_REF_SLUG</code>, <code>$CI_JOB_IMAGE</code>, or create composite keys.</li>
</ul>
</li>



<li><strong><code>paths</code>:</strong> Defines what gets cached. These paths are relative to the project directory (<code>$CI_PROJECT_DIR</code>).</li>



<li><strong><code>policy</code>:</strong>
<ul class="wp-block-list">
<li><code>pull-push</code>: Downloads at start, uploads at end.</li>



<li><code>pull</code>: Only downloads at start.</li>



<li><code>push</code>: Only uploads at end (useful for jobs that only produce a cache but don&#8217;t need to download one).</li>
</ul>
</li>



<li><strong><code>when</code>:</strong>
<ul class="wp-block-list">
<li><code>on_success</code>: (Default) Cache is saved only if the job succeeds.</li>



<li><code>on_failure</code>: Cache is saved only if the job fails.</li>



<li><code>always</code>: Cache is saved regardless of job success or failure.</li>
</ul>
</li>



<li><strong>Cache vs. Artifacts:</strong>
<ul class="wp-block-list">
<li><strong>Cache:</strong> Meant for temporary storage to speed up jobs (e.g., <code>node_modules</code>, downloaded libraries). Not guaranteed to be available (runners might clear caches). Shared between subsequent runs of the <em>same job</em> or different jobs sharing the <em>same cache key</em>.</li>



<li><strong>Artifacts:</strong> Meant for passing build outputs between stages/jobs or for downloading after a pipeline completes (e.g., compiled binaries, test reports). Guaranteed to be available for the duration defined by artifact expiry settings.</li>
</ul>
</li>



<li><strong>Cache Scope:</strong>
<ul class="wp-block-list">
<li>By default, caches are stored per GitLab Runner.</li>



<li>For distributed caching (e.g., using S3), an administrator needs to configure it. This allows different runners to share the same cache.</li>
</ul>
</li>



<li><strong>Clearing Cache:</strong> You can clear pipeline caches manually via the GitLab UI (CI/CD settings or on the pipeline view). Changing the cache <code>key</code> also effectively starts a new cache.</li>
</ul>



<p class="wp-block-paragraph">Using <code>cache</code> effectively can significantly reduce the runtime of your GitLab CI/CD pipelines, especially for projects with many dependencies.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/gitlab-pipeline-cache-what-is-cache-in-gitlab-ci-cd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Gitlab Pipeline – after_script – What is after_script in GitLab CI/CD?</title>
		<link>https://www.bestdevops.com/gitlab-pipeline-after_script-what-is-after_script-in-gitlab-ci-cd/</link>
					<comments>https://www.bestdevops.com/gitlab-pipeline-after_script-what-is-after_script-in-gitlab-ci-cd/#respond</comments>
		
		<dc:creator><![CDATA[kumar k]]></dc:creator>
		<pubDate>Tue, 27 May 2025 09:24:18 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=31340</guid>

					<description><![CDATA[The after_script keyword in GitLab CI/CD allows you to define a list of shell commands that should be executed after [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The <code>after_script</code> keyword in GitLab CI/CD allows you to define a list of shell commands that should be executed <strong>after</strong> the main <code>script</code> commands of a job. A crucial characteristic of <code>after_script</code> is that its commands are <strong>executed regardless of the success or failure of the job&#8217;s <code>script</code> or <code>before_script</code> sections.</strong></p>



<p class="wp-block-paragraph">This makes <code>after_script</code> ideal for tasks like:</p>



<ul class="wp-block-list">
<li>Cleaning up temporary files or resources.</li>



<li>Logging final status or collecting diagnostic information.</li>



<li>De-authenticating from services.</li>



<li>Uploading artifacts even if the job failed.</li>
</ul>



<p class="wp-block-paragraph">You can define <code>after_script</code> at two main levels:</p>



<ol class="wp-block-list">
<li><strong>Globally (as a default):</strong> Using <code>default:after_script:</code>. These commands will run after every job unless a job overrides it.</li>



<li><strong>Job-level:</strong> Defined within a specific job. This overrides any global <code>after_script</code> for that particular job.</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Example <code>.gitlab-ci.yml</code> with <code>after_script</code>:</h3>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .gitlab-ci.yml</span>

<span class="hljs-comment"># 1. Default after_script: Applied to all jobs unless overridden</span>
<span class="hljs-keyword">default</span>:
  image: alpine:latest <span class="hljs-comment"># Using a common default image</span>
  after_script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Default after_script (Global) ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Job finished at: $(date)"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Job status was: $CI_JOB_STATUS"</span> <span class="hljs-comment"># CI_JOB_STATUS reflects the script's outcome</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Cleaning up default resources..."</span>

stages:
  - build
  - test
  - cleanup_test

<span class="hljs-comment"># Job 1: Successful job that uses the default after_script</span>
successful_job:
  stage: build
  before_script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Before script for successful_job"</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Main script for successful_job ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This job will succeed."</span>
    - <span class="hljs-keyword">exit</span> <span class="hljs-number">0</span> <span class="hljs-comment"># Explicitly succeed</span>

<span class="hljs-comment"># Job 2: Failing job that also uses the default after_script</span>
failing_job:
  stage: test
  before_script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Before script for failing_job"</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Main script for failing_job ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This job will intentionally fail."</span>
    - <span class="hljs-keyword">exit</span> <span class="hljs-number">1</span> <span class="hljs-comment"># Explicitly fail</span>

<span class="hljs-comment"># Job 3: Job with a custom after_script (overrides the default)</span>
job_with_custom_after_script:
  stage: cleanup_test
  after_script: <span class="hljs-comment"># Job-level after_script overrides the default one</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Custom after_script for job_with_custom_after_script ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Performing specific cleanup for this job."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Job status was: $CI_JOB_STATUS"</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Main script for job_with_custom_after_script ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This job uses its own custom after_script."</span>

<span class="hljs-comment"># Job 4: Job that disables after_script (even the default one)</span>
job_without_any_after_script:
  stage: cleanup_test
  after_script: &#91;] <span class="hljs-comment"># Explicitly set to an empty array to disable</span>
  <span class="hljs-comment"># You could also use `after_script: null` in some GitLab versions.</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Main script for job_without_any_after_script ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"No after_script (neither default nor custom) will be executed for this job."</span>

</code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Explanation:</h3>



<ol class="wp-block-list">
<li><strong><code>default:after_script:</code></strong>
<ul class="wp-block-list">
<li>The <code>default:</code> block allows setting default configurations.</li>



<li><code>after_script:</code> within <code>default:</code> defines commands that execute after <em>every job</em>, regardless of whether the job passed or failed (unless the job has its own <code>after_script</code> or disables it).</li>



<li>In this example:
<ul class="wp-block-list">
<li>It prints introductory lines and the finish time.</li>



<li>It prints the <code>CI_JOB_STATUS</code> (a predefined variable indicating if the job&#8217;s main script succeeded, failed, etc.).</li>



<li>It simulates a default cleanup.</li>
</ul>
</li>
</ul>
</li>



<li><strong><code>successful_job:</code></strong>
<ul class="wp-block-list">
<li>This job completes its <code>script</code> section successfully (<code>exit 0</code>).</li>



<li>It does <strong>not</strong> have its own <code>after_script</code>.</li>



<li>Therefore, it <strong>inherits and executes the commands</strong> from the <code>default:after_script:</code> section after its <code>script</code> block. The <code>CI_JOB_STATUS</code> will likely be <code>success</code>.</li>
</ul>
</li>



<li><strong><code>failing_job:</code></strong>
<ul class="wp-block-list">
<li>This job intentionally fails in its <code>script</code> section (<code>exit 1</code>).</li>



<li>It also does <strong>not</strong> have its own <code>after_script</code>.</li>



<li>Despite the failure, it will <strong>still inherit and execute the commands</strong> from the <code>default:after_script:</code> section. This demonstrates the key behavior of <code>after_script</code>. The <code>CI_JOB_STATUS</code> will likely be <code>failed</code>.</li>
</ul>
</li>



<li><strong><code>job_with_custom_after_script:</code></strong>
<ul class="wp-block-list">
<li>This job defines its own <code>after_script:</code> block.</li>



<li>This job-level <code>after_script</code> <strong>completely overrides</strong> (replaces) the <code>default:after_script:</code>. The commands from <code>default:after_script:</code> will <strong>not</strong> run for this job.</li>



<li>Only the commands listed in this job&#8217;s <code>after_script</code> will execute after its main <code>script</code>, regardless of the main script&#8217;s outcome.</li>
</ul>
</li>



<li><strong><code>job_without_any_after_script:</code></strong>
<ul class="wp-block-list">
<li>This job explicitly sets <code>after_script: []</code> (an empty array).</li>



<li>This tells GitLab CI <strong>not to run any <code>after_script</code> commands for this job</strong>, not even the ones defined in the <code>default:after_script:</code> section.</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Key Concepts and Behavior:</h3>



<ul class="wp-block-list">
<li><strong>Purpose:</strong> <code>after_script</code> is intended for cleanup, final logging, or any actions that must occur regardless of the job&#8217;s outcome.</li>



<li><strong>Execution Order:</strong> For any given job:
<ol class="wp-block-list">
<li><code>before_script</code> (if any) runs.</li>



<li>Main <code>script</code> runs.</li>



<li><code>after_script</code> (if any) runs.</li>
</ol>
</li>



<li><strong>Runs on Success or Failure:</strong> This is the most important characteristic. Commands in <code>after_script</code> are executed even if the <code>before_script</code> or <code>script</code> sections fail.</li>



<li><strong>Failure Handling in <code>after_script</code>:</strong>
<ul class="wp-block-list">
<li>The exit code of commands in <code>after_script</code> <strong>does not affect the overall job status</strong>. The job&#8217;s status is determined by the <code>before_script</code> and <code>script</code> sections.</li>



<li>However, if a command in <code>after_script</code> fails, you might see errors in the job log for the <code>after_script</code> phase.</li>
</ul>
</li>



<li><strong>Array of Commands:</strong> <code>after_script</code> takes an array of strings, where each string is a shell command executed sequentially.</li>



<li><strong>Inheritance and Overriding:</strong>
<ul class="wp-block-list">
<li>Job-level <code>after_script</code> overrides <code>default:after_script</code>.</li>



<li>To prevent any <code>after_script</code> (including a global one) from running for a specific job, set <code>after_script: []</code> or <code>after_script: null</code>.</li>
</ul>
</li>



<li><strong>Execution Context:</strong>
<ul class="wp-block-list">
<li><code>after_script</code> commands run on the same GitLab Runner that executed the job.</li>



<li>They generally have access to the same environment variables, files in the workspace (unless cleaned up by the job&#8217;s script), and services as the main <code>script</code>.</li>



<li>The <code>CI_JOB_STATUS</code> predefined variable is particularly useful in <code>after_script</code> to know the outcome of the job&#8217;s main execution.</li>
</ul>
</li>



<li><strong>Timeout:</strong> <code>after_script</code> has its own separate timeout, which is configured by the GitLab administrator (usually shorter than the main job timeout).</li>



<li><strong>Common Use Cases:</strong>
<ul class="wp-block-list">
<li>Removing temporary files or directories.</li>



<li>Stopping services started during the job.</li>



<li>Logging out from authenticated sessions.</li>



<li>Uploading test reports or logs, especially if the job failed and artifacts wouldn&#8217;t be uploaded otherwise (though <code>artifacts:when:always</code> is often preferred for artifact uploading).</li>



<li>Sending notifications.</li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph">Using <code>after_script</code> ensures that critical cleanup and finalization steps are performed consistently, contributing to a more robust and manageable CI/CD pipeline.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/gitlab-pipeline-after_script-what-is-after_script-in-gitlab-ci-cd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Gitlab Pipeline – before_script – What is before_script in GitLab CI/CD?</title>
		<link>https://www.bestdevops.com/gitlab-pipeline-before_script-what-is-before_script-in-gitlab-ci-cd/</link>
					<comments>https://www.bestdevops.com/gitlab-pipeline-before_script-what-is-before_script-in-gitlab-ci-cd/#respond</comments>
		
		<dc:creator><![CDATA[kumar k]]></dc:creator>
		<pubDate>Tue, 27 May 2025 09:18:19 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=31337</guid>

					<description><![CDATA[The before_script keyword in GitLab CI/CD allows you to define a list of shell commands that should be executed before [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The <code>before_script</code> keyword in GitLab CI/CD allows you to define a list of shell commands that should be executed <strong>before</strong> the main <code>script</code> commands of a job. This is commonly used for setup tasks like:</p>



<ul class="wp-block-list">
<li>Logging information.</li>



<li>Setting up environment variables.</li>



<li>Installing dependencies.</li>



<li>Authenticating to services.</li>
</ul>



<p class="wp-block-paragraph">You can define <code>before_script</code> at two main levels:</p>



<ol class="wp-block-list">
<li><strong>Globally (as a default):</strong> Using <code>default:before_script:</code>. These commands will run before every job unless a job overrides it.</li>



<li><strong>Job-level:</strong> Defined within a specific job. This overrides any global <code>before_script</code> for that particular job.</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Example <code>.gitlab-ci.yml</code> with <code>before_script</code>:</h3>



<p class="wp-block-paragraph">YAML</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># .gitlab-ci.yml</span>

<span class="hljs-comment"># 1. Default before_script: Applied to all jobs unless overridden</span>
<span class="hljs-keyword">default</span>:
  image: alpine:latest <span class="hljs-comment"># Using a common default image</span>
  before_script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Default before_script (Global) ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Current date: $(date)"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Setting up common environment..."</span>
    - export COMMON_SETUP_VAR=<span class="hljs-string">"Set by default before_script"</span>

stages:
  - setup
  - build
  - test

<span class="hljs-comment"># Job 1: Uses the default before_script</span>
job_with_default_before_script:
  stage: setup
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Main script for job_with_default_before_script ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"COMMON_SETUP_VAR is: $COMMON_SETUP_VAR"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This job used the global before_script."</span>

<span class="hljs-comment"># Job 2: Overrides the default before_script with its own</span>
job_with_custom_before_script:
  stage: build
  before_script: <span class="hljs-comment"># Job-level before_script overrides the default one</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Custom before_script for job_with_custom_before_script ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"Performing specific setup for this job..."</span>
    - apk add --no-cache curl <span class="hljs-comment"># Example: installing a tool</span>
    - curl --version
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Main script for job_with_custom_before_script ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"This job used its own custom before_script."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"COMMON_SETUP_VAR is: $COMMON_SETUP_VAR (This will be empty as default before_script didn't run)"</span>

<span class="hljs-comment"># Job 3: Disables before_script (even the default one)</span>
job_without_any_before_script:
  stage: test
  before_script: &#91;] <span class="hljs-comment"># Explicitly set to an empty array to disable</span>
  <span class="hljs-comment"># You could also use `before_script: null` in some GitLab versions, but `&#91;]` is safer.</span>
  script:
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"--- Main script for job_without_any_before_script ---"</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"No before_script (neither default nor custom) was executed for this job."</span>
    - <span class="hljs-keyword">echo</span> <span class="hljs-string">"COMMON_SETUP_VAR is: $COMMON_SETUP_VAR (This will be empty)"</span>

</code></span></pre>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Explanation:</h3>



<ol class="wp-block-list">
<li><strong><code>default:before_script:</code></strong>
<ul class="wp-block-list">
<li>The <code>default:</code> block allows you to set default configurations for all jobs.</li>



<li><code>before_script:</code> within <code>default:</code> defines a list of commands that will be executed before the main <code>script</code> of <em>every job</em> in the pipeline, provided the job doesn&#8217;t have its own <code>before_script</code> or explicitly disables it.</li>



<li>In this example:
<ul class="wp-block-list">
<li>It prints some introductory lines.</li>



<li>It prints the current date.</li>



<li>It simulates setting up a common environment variable <code>COMMON_SETUP_VAR</code>.</li>
</ul>
</li>
</ul>
</li>



<li><strong><code>job_with_default_before_script:</code></strong>
<ul class="wp-block-list">
<li>This job does <strong>not</strong> have its own <code>before_script</code> keyword.</li>



<li>Therefore, it <strong>inherits and executes the commands</strong> from the <code>default:before_script:</code> section before its own <code>script</code> block runs.</li>



<li>You&#8217;ll see the output from the default <code>before_script</code>, and the <code>COMMON_SETUP_VAR</code> will be available in its main script.</li>
</ul>
</li>



<li><strong><code>job_with_custom_before_script:</code></strong>
<ul class="wp-block-list">
<li>This job <strong>defines its own <code>before_script:</code> block</strong>.</li>



<li>This job-level <code>before_script</code> <strong>completely overrides</strong> (replaces) the <code>default:before_script:</code>. The commands from <code>default:before_script:</code> will <strong>not</strong> run for this job.</li>



<li>Only the commands listed in this job&#8217;s <code>before_script</code> (e.g., installing <code>curl</code>) will execute before its main <code>script</code>.</li>



<li>Consequently, <code>COMMON_SETUP_VAR</code> (set in the default <code>before_script</code>) will not be defined or will be empty when this job&#8217;s main script runs.</li>
</ul>
</li>



<li><strong><code>job_without_any_before_script:</code></strong>
<ul class="wp-block-list">
<li>This job explicitly sets <code>before_script: []</code> (an empty array).</li>



<li>This tells GitLab CI <strong>not to run any <code>before_script</code> commands for this job</strong>, not even the ones defined in the <code>default:before_script:</code> section.</li>



<li>The job will proceed directly to its <code>script</code> block.</li>



<li><code>COMMON_SETUP_VAR</code> will be undefined or empty.</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Key Concepts and Behavior:</h3>



<ul class="wp-block-list">
<li><strong>Purpose:</strong> <code>before_script</code> is intended for setup tasks that prepare the environment for the main <code>script</code>. It&#8217;s not for the core logic of your job.</li>



<li><strong>Execution Order:</strong> For any given job, if a <code>before_script</code> is active (either default or job-specific), its commands run first. If all commands in <code>before_script</code> succeed, then the commands in the job&#8217;s <code>script</code> section are executed.</li>



<li><strong>Failure Handling:</strong> If any command in <code>before_script</code> fails (exits with a non-zero status), the job is typically marked as failed immediately. The main <code>script</code> section for that job will <strong>not</strong> be executed.</li>



<li><strong>Array of Commands:</strong> <code>before_script</code> takes an array of strings, where each string is a shell command to be executed sequentially.</li>



<li><strong>Inheritance and Overriding:</strong>
<ul class="wp-block-list">
<li>Job-level <code>before_script</code> overrides <code>default:before_script</code>.</li>



<li>To prevent any <code>before_script</code> (including a global one) from running for a specific job, set <code>before_script: []</code> or <code>before_script: null</code> (though <code>[]</code> is generally preferred for clarity and consistency).</li>
</ul>
</li>



<li><strong>Common Use Cases:</strong>
<ul class="wp-block-list">
<li>Printing debug information (versions of tools, environment variables).</li>



<li>Logging into private repositories or services.</li>



<li>Installing required software packages or dependencies that are not part of the Docker image.</li>



<li>Setting dynamic environment variables needed by the main <code>script</code>.</li>



<li>Fetching configuration files.</li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph">Using <code>before_script</code> helps keep your main <code>script</code> section clean and focused on the primary task of the job, while common or job-specific setup steps are neatly organized.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/gitlab-pipeline-before_script-what-is-before_script-in-gitlab-ci-cd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
