<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Utkarsh Shigihalli</title>
    <description>The latest articles on DEV Community by Utkarsh Shigihalli (@onlyutkarsh).</description>
    <link>https://dev.to/onlyutkarsh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F146259%2F5aa8d5c6-7e4f-43a5-ba21-372958f5fb06.jpg</url>
      <title>DEV Community: Utkarsh Shigihalli</title>
      <link>https://dev.to/onlyutkarsh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/onlyutkarsh"/>
    <language>en</language>
    <item>
      <title>Use a single repository for multiple wikis in Azure DevOps</title>
      <dc:creator>Utkarsh Shigihalli</dc:creator>
      <pubDate>Thu, 07 Dec 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/onlyutkarsh/use-a-single-repository-for-multiple-wikis-in-azure-devops-2lm0</link>
      <guid>https://dev.to/onlyutkarsh/use-a-single-repository-for-multiple-wikis-in-azure-devops-2lm0</guid>
      <description>&lt;p&gt;This is a quick post to share how you can use a single Azure DevOps repository for multiple wikis in Azure DevOps. This approach will help you avoid creating multiple repositories for each wiki and manage them in a single repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a new repo for wiki
&lt;/h2&gt;

&lt;p&gt;Firs lets create a separate repository for the wiki.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ji05JIoz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2023-12-07-using-single-azdo-repo-for-multiple-wikis/create-repo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ji05JIoz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2023-12-07-using-single-azdo-repo-for-multiple-wikis/create-repo.png" alt="Create Repository" width="618" height="454"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Create a repository&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I want to create two wiki for two teams in my project. So I have created subfolders for each team in the repository and have placed sample markdown files in each folder. The idea is that each team will place their wiki content in their respective folder.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t6UKCto_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2023-12-07-using-single-azdo-repo-for-multiple-wikis/repo-folder-structure.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t6UKCto_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2023-12-07-using-single-azdo-repo-for-multiple-wikis/repo-folder-structure.png" alt="Folder Structure" width="800" height="537"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Folder structure&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Publish code as a new wiki
&lt;/h2&gt;

&lt;p&gt;Now let us create a new wiki in Azure DevOps. Go to the project settings and click on the Wiki tab. We will publish a new code wiki.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VXsJj7Mq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2023-12-07-using-single-azdo-repo-for-multiple-wikis/publish-code-as-wiki.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VXsJj7Mq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2023-12-07-using-single-azdo-repo-for-multiple-wikis/publish-code-as-wiki.png" alt="Publish code as wiki" width="800" height="318"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Publish code as wiki&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Do the same for the second wiki.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bWeuKjSF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2023-12-07-using-single-azdo-repo-for-multiple-wikis/publish-code-as-wiki-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bWeuKjSF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2023-12-07-using-single-azdo-repo-for-multiple-wikis/publish-code-as-wiki-2.png" alt="Publish code as wiki" width="800" height="328"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Publish code as wiki&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This will create two wikis in the project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B-Y8FYQ2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2023-12-07-using-single-azdo-repo-for-multiple-wikis/show-wikis.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B-Y8FYQ2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2023-12-07-using-single-azdo-repo-for-multiple-wikis/show-wikis.png" alt="show-wikis" width="800" height="564"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure the wiki
&lt;/h2&gt;

&lt;p&gt;As you can see that was easy. However, at it stands now, both the wikis are open for edits from all the team members. We need to restrict the access to the wiki content based on the team. We will make use of branch policies to achieve this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7qLPu6qE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2023-12-07-using-single-azdo-repo-for-multiple-wikis/branch-policy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7qLPu6qE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2023-12-07-using-single-azdo-repo-for-multiple-wikis/branch-policy.png" alt="Set the branch policy" width="800" height="414"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Set the branch policy&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now, when any time changes are made to the wiki under &lt;code&gt;01-team-infra/*&lt;/code&gt; folder and a PR is created, Infra team will automatically be included as reviewers. Similarly, for the &lt;code&gt;02-team-app/*&lt;/code&gt; folder, App team will be included as reviewers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x96n87qY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2023-12-07-using-single-azdo-repo-for-multiple-wikis/pull-request.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x96n87qY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2023-12-07-using-single-azdo-repo-for-multiple-wikis/pull-request.png" alt="pull-request" width="800" height="451"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Pull request showing automatic reviewers added&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That is it for this post. You can now use a single Azure DevOps repository for multiple wikis in Azure DevOps. As mentioned above, this approach will help you avoid creating multiple repositories for each wiki and manage them in a single repository.&lt;/p&gt;

&lt;p&gt;Hope you enjoyed reading this.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>.env Manager — Quick way to create Environment Variables</title>
      <dc:creator>Utkarsh Shigihalli</dc:creator>
      <pubDate>Thu, 30 Jun 2022 22:40:30 +0000</pubDate>
      <link>https://dev.to/onlyutkarsh/env-manager-quick-way-to-create-environment-variables-29a</link>
      <guid>https://dev.to/onlyutkarsh/env-manager-quick-way-to-create-environment-variables-29a</guid>
      <description>&lt;p&gt;Do you use .env files to manage your environment variables in your local dev environment? .env Manager is a small VSCode extension to quickly add values to .env file, either selecting a text or running the command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=onlyutkarsh.envmanager"&gt;https://marketplace.visualstudio.com/items?itemName=onlyutkarsh.envmanager&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Checkout the quick demo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XP0s7Dzo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h4dgv0mt0elhijkxfcxv.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XP0s7Dzo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h4dgv0mt0elhijkxfcxv.gif" alt="demo" width="799" height="591"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;The extension exposes a command called .env Manager: Add to .env. The command is available in VS Code "Command Palette" which you can also access using shortcut Cmd + Shift + P on Mac.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dy1Bk6z1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/35trwxbtcouukz9i7tcj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dy1Bk6z1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/35trwxbtcouukz9i7tcj.jpg" alt="command" width="543" height="161"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alternatively you can also right click on any active editor and select &lt;code&gt;.env Manager: Add to .env&lt;/code&gt; from the context menu.&lt;/p&gt;

&lt;p&gt;If the folder does not contain .env file at the root, the extension attempts to create it before adding the line.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make sure you backup your .env file if you have very important secrets in the .env file.&lt;/p&gt;

&lt;p&gt;Never commit your .env file in to source control.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>vscode</category>
      <category>extension</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Trigger a Netlify build every day using GitHub Actions</title>
      <dc:creator>Utkarsh Shigihalli</dc:creator>
      <pubDate>Sun, 20 Feb 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/onlyutkarsh/trigger-a-netlify-build-every-day-using-github-actions-1dk6</link>
      <guid>https://dev.to/onlyutkarsh/trigger-a-netlify-build-every-day-using-github-actions-1dk6</guid>
      <description>&lt;p&gt;I host this blog on Netlify and source control is managed using GitHub. Often, I end up writing few blog posts together, but not necessarily want all of them published together. Jekyll allows to put future date in the post and it will not be published until that date. This lets me write blog posts on same day but end up publishing them later based on the date set for the post. However, this means that when you run &lt;code&gt;jekyll build&lt;/code&gt; posts with future dates will be skipped and I will need to run &lt;code&gt;jekyll build&lt;/code&gt; again on the post date to publish the blog posts. Same applies to Netlify. Curious how we can solve this by triggering scheduled deploys on Netlify?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B6KoRwlw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2022/feb/trigger-netlify-build-everyday-using-github-actions/jekyll-skip.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B6KoRwlw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2022/feb/trigger-netlify-build-everyday-using-github-actions/jekyll-skip.png" alt="Jekyll skips posts with future dates" width="880" height="228"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Jekyll skipping posts with future date&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Create Netlify build hook
&lt;/h2&gt;

&lt;p&gt;Netlify supports &lt;a href="https://docs.netlify.com/configure-builds/build-hooks/"&gt;build hooks&lt;/a&gt;, which lets you trigger new builds and deploys by making a request to a URL.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OI7xbi1v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2022/feb/trigger-netlify-build-everyday-using-github-actions/configure-builds-build-hooks.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OI7xbi1v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2022/feb/trigger-netlify-build-everyday-using-github-actions/configure-builds-build-hooks.png" alt="Configure build hooks in netlify" width="880" height="260"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Configure build hooks&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Go to &lt;code&gt;Site Settings&lt;/code&gt; and &lt;code&gt;Build Hooks&lt;/code&gt; section and click &lt;code&gt;Add Build Hook&lt;/code&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q5VAR8S5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2022/feb/trigger-netlify-build-everyday-using-github-actions/add-build-hook.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q5VAR8S5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2022/feb/trigger-netlify-build-everyday-using-github-actions/add-build-hook.jpg" alt="Add build hook" width="804" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Add build hook&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Give a name and select a branch to trigger the build and click &lt;code&gt;Save&lt;/code&gt;. You will see the URL which you can use to trigger the build.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3NwUr4O3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2022/feb/trigger-netlify-build-everyday-using-github-actions/build-hook.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3NwUr4O3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2022/feb/trigger-netlify-build-everyday-using-github-actions/build-hook.jpg" alt="Save build hook" width="880" height="244"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;URL of the build hook&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Create GitHub Actions workflow
&lt;/h2&gt;

&lt;p&gt;Go to GitHub repo and create a actions yaml file under &lt;code&gt;.github\workflows&lt;/code&gt; folder. GitHub Actions supports scheduled jobs, which lets you run a job at a specific time. See the below example. I am using cron expression to run the build every day at 04:00 AM UTC timezone.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: nightly-netlify-build

on:
  schedule:
    - cron: "1 4 * * *"

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: trigger netlify build
        run: |
          curl -X POST -d '{}' https://api.netlify.com/build_hooks/2eae8d5c79506d0213a38be0e

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file and push the changes. That is it, you have created a GitHub Actions workflow which can trigger nightly build of the blog. Go to Netlify and see the &lt;code&gt;Deploys&lt;/code&gt; tab. You will see the deploys triggered by the build hook.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T3uw4WUx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2022/feb/trigger-netlify-build-everyday-using-github-actions/verify-netlify.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T3uw4WUx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2022/feb/trigger-netlify-build-everyday-using-github-actions/verify-netlify.jpg" alt="GitHub tooltip" width="665" height="300"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Deploys triggered by the build hook&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Isn’t that cool? If you liked the post, do share it in your social channels. Thanks for reading.&lt;/p&gt;

</description>
      <category>github</category>
      <category>actions</category>
      <category>netlify</category>
    </item>
    <item>
      <title>Policy enforced deployments for your Kubernetes resources</title>
      <dc:creator>Utkarsh Shigihalli</dc:creator>
      <pubDate>Sun, 13 Feb 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/onlyutkarsh/policy-enforced-deployments-for-your-kubernetes-resources-387p</link>
      <guid>https://dev.to/onlyutkarsh/policy-enforced-deployments-for-your-kubernetes-resources-387p</guid>
      <description>&lt;p&gt;As your team starts to deploy resources to Kubernetes regularly, it becomes necessary for you as a cluster administrator to maintain good standards and consistency of the Kubernetes resources. Be it, ensuring all the resources have set of labels, or ensuring you only pull images from your enterprise container registry. &lt;a href="https://github.com/open-policy-agent/gatekeeper" rel="noopener noreferrer"&gt;Gatekeeper&lt;/a&gt; is a well known policy enforcement tool using &lt;a href="https://www.openpolicyagent.org" rel="noopener noreferrer"&gt;Open Policy Agent (OPA)&lt;/a&gt; - which is a opensource, Cloud Native Computing Foundation (CNCF) project.&lt;/p&gt;

&lt;p&gt;However, Gatekeeper is installed on the cluster and thus ensures no policy is broken at deployment time. This means that any validation of policies happen only when you are trying to deploy resources to cluster. While this ensures that no resource violates the policy, you would like to know about these policies much earlier in your CI/CD pipeline. Doing policy validations much to the left of your deployment pipeline ensures your deployment going smooth when necessary.&lt;/p&gt;

&lt;p&gt;This is where &lt;a href="https://www.conftest.dev" rel="noopener noreferrer"&gt;Conftest&lt;/a&gt; helps. Conftest relies on OPA and policies are written using &lt;a href="https://www.openpolicyagent.org/docs/latest/#rego" rel="noopener noreferrer"&gt;Rego&lt;/a&gt; - thus the policies you write for Gatekeeper will be compatible with Conftest. But more importantly &lt;strong&gt;with Conftest, you can validate your local manifests against OPA policies locally and ensure your resources are compliant before you deploy them&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Installation is really easy if you are on Mac - For other platforms refer to the &lt;a href="https://www.conftest.dev/install/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install conftest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Folder structure
&lt;/h2&gt;

&lt;p&gt;By default, Conftest expects you to maintain your policies under &lt;code&gt;policy&lt;/code&gt; folder at the same location as your Kubernetes resources. If you prefer a different path, you will want to pass it using CLI or set environment variable &lt;code&gt;CONFTEST_POLICY&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;📂 src
    📂 k8s
        📄 deployment.yml
        📄 service.yml
        📁 policy
            📄 replica.rego
            📄 labels.rego
    📂 app
        📄 main.ts
        📄 package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Writing Policies
&lt;/h2&gt;

&lt;p&gt;As mentioned previously, policies are written in &lt;a href="https://www.openpolicyagent.org/docs/latest/#rego" rel="noopener noreferrer"&gt;Rego&lt;/a&gt;. I struggled to write policies initially and constantly went back to documentation. However, once you write couple of policies, you will get a hang of it. Take a look at the simple policy to &lt;em&gt;check every deployment has at least 2 replicas&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

deny_replicas[msg] {
    input.kind == "Deployment" # check if it is a Deployment
    input.spec.replicas &amp;lt; 2 # And the replicas are &amp;lt; 2
    msg := "Deployments must have 2 or more replicas" # show the error message and fail the test
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;input&lt;/code&gt; is the complete yaml document from our deployment yaml (see below) and we we are checking if &lt;code&gt;kind&lt;/code&gt; is equal to &lt;code&gt;Deployment&lt;/code&gt;. If its deployment, we move to next line in the constraint and check if &lt;code&gt;spec.replicas&lt;/code&gt; is less that 2.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: mynodeapi-dep
  labels:
    app: dep-k8s-nodejs-api
spec:
  replicas: 1
  selector:
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lets see how we can test our &lt;code&gt;Deployment&lt;/code&gt; resource using Conftest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;The command to test resources using Conftest is &lt;code&gt;conftest test &amp;lt;PATH&amp;gt;&lt;/code&gt;. Since I would like to test all resources under &lt;code&gt;k8s&lt;/code&gt; folder, I pass folder path as below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;conftest test ./k8s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running this you will see the output as below (ignore other errors as I have other policies). The test failed because we have set &lt;code&gt;deny&lt;/code&gt; rule if &lt;code&gt;spect.replicas &amp;lt; 2&lt;/code&gt; and in our case our deployment yaml has &lt;code&gt;replicas: 1&lt;/code&gt; (see &lt;code&gt;spec&lt;/code&gt; section in the deployment yaml above).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.visualstudiogeeks.com%2Fimages%2Fscreenshots%2Futkarsh%2F2022%2Ffeb%2Fpolicy-enabled-deployments-for-k8s%2Fconftest-error.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.visualstudiogeeks.com%2Fimages%2Fscreenshots%2Futkarsh%2F2022%2Ffeb%2Fpolicy-enabled-deployments-for-k8s%2Fconftest-error.png" alt="conftest error"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Conftest failing due to policy violation&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Conftest in GitHub Actions
&lt;/h2&gt;

&lt;p&gt;Making Conftest work in your Continuous Integration (CI) process is simple. For demo purposes, I am using GitHub Actions in my repo &lt;a href="https://github.com/onlyutkarsh/k8s-nodejs-api" rel="noopener noreferrer"&gt;here&lt;/a&gt;. If you run the tests, you will see the action fails with errors - &lt;a href="https://github.com/onlyutkarsh/k8s-nodejs-api/runs/5173696729?check_suite_focus=true#step:4:6" rel="noopener noreferrer"&gt;see the output&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As you can see, Conftest lets you validate and govern your Kubernetes resources efficiently and can easily be integrated with your CI workflows. This lets your team standardise the common practices, go through PR review process before eventually deploying to the cluster. Once deployed to cluster, you can use Gatekeeper to validate as well to full proof your workloads.&lt;/p&gt;

</description>
      <category>conftest</category>
      <category>kubernetes</category>
      <category>github</category>
    </item>
    <item>
      <title>Keep your workflow actions up to date using GitHub Dependabot</title>
      <dc:creator>Utkarsh Shigihalli</dc:creator>
      <pubDate>Fri, 28 Jan 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/onlyutkarsh/keep-your-workflow-actions-up-to-date-using-github-dependabot-1i29</link>
      <guid>https://dev.to/onlyutkarsh/keep-your-workflow-actions-up-to-date-using-github-dependabot-1i29</guid>
      <description>&lt;p&gt;GitHub Actions is great in automating your workflows. However, as you start using various actions from GitHub Marketplace in your workflow, it will soon become necessary for you to keep the actions up-to-date. Actions might contain security fixes, bug fixes etc and manually keeping track of updates or updating them when a newer version is available is a lot of hassle. This is where we can use Depndabot can help is by automatically raising PR’s whenever there is a newer version of action is available used in the workflow. In this post, we will see quick way to keep the actions up-to-date using GitHub Dependabot.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For this post, I am using my &lt;a href="https://github.com/onlyutkarsh/git-config-user-profiles"&gt;Git Config User Profiles&lt;/a&gt; repository. I have workflow setup which builds and releases the VS Code extension to VS Marketplace.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Create dependabot.yml file
&lt;/h2&gt;

&lt;p&gt;To set up Dependabot scan, first got to &lt;code&gt;.github&lt;/code&gt; folder in your root and create a &lt;code&gt;depndabot.yml&lt;/code&gt; file. Then add the following content. This will ensure GitHub Dependabot raise a PR whenever there is a newer version of action is available&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;span class="na"&gt;updates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;package-ecosystem&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;github-actions"&lt;/span&gt; &lt;span class="c1"&gt;# search for actions - there are other options available&lt;/span&gt;
    &lt;span class="na"&gt;directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/"&lt;/span&gt; &lt;span class="c1"&gt;# search in .github/workflows under root `/`&lt;/span&gt;
    &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;weekly"&lt;/span&gt; &lt;span class="c1"&gt;# check for action update every week&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Commit the file
&lt;/h2&gt;

&lt;p&gt;Commit the file created above and wait for few seconds. Based on your workflow, you will see a bunch of PR’s raised.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ncADPpZc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2022/jan/dependabot-to-update-actions/dependabot-alerts.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ncADPpZc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2022/jan/dependabot-to-update-actions/dependabot-alerts.png" alt="Dependabot PR" width="739" height="316"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Dependabot Alerts as PR&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you look at the PR, you will be able to see the change and take a decision whether you want to upgrade the specific action or not. If you decide to accept the change, merge the PR and the changes on the workflow file will be made.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aUKGZZj0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2022/jan/dependabot-to-update-actions/commit-detail.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aUKGZZj0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2022/jan/dependabot-to-update-actions/commit-detail.png" alt="Commit Details" width="880" height="290"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Commit Details&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Isn’t it cool? This saves a lot of time, if you have a number of workflows and don’t want to keep checking the latest versions of actions. BTW, not only GitHub actions, you can use same approach to update &lt;code&gt;npm&lt;/code&gt;, &lt;code&gt;docker&lt;/code&gt; and many more using various &lt;a href="https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/about-dependabot-version-updates#supported-repositories-and-ecosystems"&gt;package ecosystems&lt;/a&gt;. Do check it out!&lt;/p&gt;

</description>
      <category>github</category>
      <category>actions</category>
      <category>dependabot</category>
    </item>
    <item>
      <title>Setting up Azure Cosmos DB Emulator on Synology NAS</title>
      <dc:creator>Utkarsh Shigihalli</dc:creator>
      <pubDate>Mon, 26 Jul 2021 23:00:00 +0000</pubDate>
      <link>https://dev.to/onlyutkarsh/setting-up-azure-cosmos-db-emulator-on-synology-nas-56ei</link>
      <guid>https://dev.to/onlyutkarsh/setting-up-azure-cosmos-db-emulator-on-synology-nas-56ei</guid>
      <description>&lt;p&gt;Cosmos DB Emulator is great for developing against Azure Cosmos DB in your local environment. If you want to run the emulator on Mac/Linux though, the emulator is now in preview mode at the time of writing this and uses Docker to make it available.&lt;/p&gt;

&lt;p&gt;Recently I wanted to setup Cosmos DB Emulator on Mac, but I did not want to set it up such that I keep it running always on my Mac. Instead, I decided to use my Synology NAS to host the emulator directly on my NAS as it is built on Linux and also because it allows the emulator running and available for me all the time.&lt;/p&gt;

&lt;p&gt;In this post we will see how to set it up on Synology NAS.&lt;/p&gt;

&lt;p&gt;The goal is to run Cosmos DB emulator as a Docker container on Synology.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enabling SSH on Synology
&lt;/h2&gt;

&lt;p&gt;Since Cosmos DB Emulator image is hosted on Microsoft Registry (&lt;code&gt;mcr.microsoft.com&lt;/code&gt;) which does not provide UI/discovery service, Synology’s Docker app, cannot pull images from Microsoft Registry. For this purpose we need to enable SSH on Synology so that we can SSH to Synology and run docker commands directly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kjuT8h4E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/jul/setting-up-cosmos-emulator-on-synology/ssh-on-synology.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kjuT8h4E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/jul/setting-up-cosmos-emulator-on-synology/ssh-on-synology.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have firewall enabled on Synology, you must also &lt;code&gt;Allow&lt;/code&gt; port &lt;code&gt;22&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Rn-uVDOU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/jul/setting-up-cosmos-emulator-on-synology/firewall-synology.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Rn-uVDOU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/jul/setting-up-cosmos-emulator-on-synology/firewall-synology.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pulling the docker image
&lt;/h2&gt;

&lt;p&gt;After enabling SSH on SYnology, you can SSH on to Synology and run the below command to pull the Docker image of Cosmos Emulator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo docker pull mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see Cosmos DB Emulator image available in Syonology’s Docker app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5BUvqS4O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/jul/setting-up-cosmos-emulator-on-synology/image-downloaded.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5BUvqS4O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/jul/setting-up-cosmos-emulator-on-synology/image-downloaded.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting the Container
&lt;/h2&gt;

&lt;p&gt;You can now create a container using the docker image you just pulled. Before we start, as per the Microsoft documentation for the Emulator, we need to ensure we have setup few environment variables for the container. They are&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AZURE_COSMOS_EMULATOR_IP_ADDRESS_OVERRIDE = &amp;lt;&amp;lt;SYNOLOGY_IP_ADDRESS&amp;gt;&amp;gt;
AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE = true
AZURE_COSMOS_EMULATOR_PARTITION_COUNT = 10

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LlcJY7jF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/jul/setting-up-cosmos-emulator-on-synology/env-variables.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LlcJY7jF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/jul/setting-up-cosmos-emulator-on-synology/env-variables.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, you will need to ensure you have mapped these ports for the container. &lt;strong&gt;Ensure you have opened these below ports on the Synology’s Firewall as well&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BipGZg3l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/jul/setting-up-cosmos-emulator-on-synology/container-ports.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BipGZg3l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/jul/setting-up-cosmos-emulator-on-synology/container-ports.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For more information on creating container from docker image, see Synology’s &lt;a href="https://kb.synology.com/en-us/DSM/help/Docker/docker_container?version=7"&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Install the certificate on your machine
&lt;/h2&gt;

&lt;p&gt;To avoid errors due to certificate, you need to download the self-signed certificate for the emulator and install it on your machine. To download the certificate for the emulator run below command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -k https://&amp;lt;&amp;lt;SYNOLOGY_IP_ADDRESS&amp;gt;&amp;gt;:8081/_explorer/emulator.pem &amp;gt; emulatorcert.crt

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On my Mac, I had to &lt;a href="https://docs.microsoft.com/en-us/azure/cosmos-db/linux-emulator?tabs=ssl-netstd21#consume-endpoint-ui"&gt;install it on Keychain Access App&lt;/a&gt; and set it as &lt;code&gt;Always Trust&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once done you should be able to browse the Cosmos Emulator UI using &lt;code&gt;https://&amp;lt;&amp;lt;SYNOLOGY_IP_ADDRESS&amp;gt;&amp;gt;:8081/_explorer/index.html&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--moW_vAOh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/jul/setting-up-cosmos-emulator-on-synology/cosmos-ui.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--moW_vAOh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/jul/setting-up-cosmos-emulator-on-synology/cosmos-ui.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That is it! Your Cosmos Emulator is now available to use all the time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/cosmos-db/linux-emulator?tabs=ssl-netstd21"&gt;Microsoft documentation on Cosmos DB Emulator on Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wundertech.net/how-to-install-portainer-on-a-synology-nas/"&gt;Enabling SSH on Synology&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How to publish HELM 3 charts to GitHub Container Registry</title>
      <dc:creator>Utkarsh Shigihalli</dc:creator>
      <pubDate>Fri, 09 Apr 2021 23:00:00 +0000</pubDate>
      <link>https://dev.to/onlyutkarsh/how-to-publish-helm-3-charts-to-github-container-registry-4ojh</link>
      <guid>https://dev.to/onlyutkarsh/how-to-publish-helm-3-charts-to-github-container-registry-4ojh</guid>
      <description>&lt;p&gt;I have already written how to publish HELM chart to ACR using &lt;a href="https://dev.to/devops/helm/deploying-helm-chart-with-azdo"&gt;Azure DevOps&lt;/a&gt; and &lt;a href="https://dev.to/helm/devops/publish-helm-charts-to-acr-using-github-actions"&gt;GitHub actions&lt;/a&gt;. But did you know you can also publish HELM3 charts (or any OCI compliant package) to &lt;a href="https://github.blog/2020-09-01-introducing-github-container-registry/" rel="noopener noreferrer"&gt;GitHub Container Registry(GCR)&lt;/a&gt;? In this post we will see how to do that. &lt;/p&gt;

&lt;h2&gt;
  
  
  Enable improved container support
&lt;/h2&gt;

&lt;p&gt;GitHub Container Registry is currently in public beta. So, the first step is to ensure that you have enabled the GitHub Container Registry for your account. If you have GitHub personal account, you can do that from &lt;code&gt;Feature Preview&lt;/code&gt; window.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.visualstudiogeeks.com%2Fimages%2Fscreenshots%2Futkarsh%2F2021%2Fapr%2Fpublish-helm-3-charts-to-gcr%2Fimproved-container-support.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.visualstudiogeeks.com%2Fimages%2Fscreenshots%2Futkarsh%2F2021%2Fapr%2Fpublish-helm-3-charts-to-gcr%2Fimproved-container-support.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have a Enterprise account, you can do that going to &lt;code&gt;Settings&lt;/code&gt; page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.visualstudiogeeks.com%2Fimages%2Fscreenshots%2Futkarsh%2F2021%2Fapr%2Fpublish-helm-3-charts-to-gcr%2Fimproved-container-support-ent.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.visualstudiogeeks.com%2Fimages%2Fscreenshots%2Futkarsh%2F2021%2Fapr%2Fpublish-helm-3-charts-to-gcr%2Fimproved-container-support-ent.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub documentation has step-by-step guide of enabling &lt;strong&gt;improved container support&lt;/strong&gt; &lt;a href="https://docs.github.com/en/packages/guides/enabling-improved-container-support" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Publishing HELM 3 charts using GitHub Actions
&lt;/h2&gt;

&lt;p&gt;It really takes only couple of steps to do it using GitHub Actions. Like any other action, you start by creating &lt;code&gt;.github\workflow&lt;/code&gt; folder and create an &lt;code&gt;yml&lt;/code&gt; file in your repository.&lt;/p&gt;

&lt;p&gt;Excluding the &lt;code&gt;name&lt;/code&gt; and trigger part, first step in the YAML is to define few necessary variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;env:
  HELM_EXPERIMENTAL_OCI: 1 #enable OCI support
  HELM_VERSION_TO_INSTALL: 3.5.0 # version of HEL to install
  GCR_IMAGE: ghcr.io/$/vote-app

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First variable &lt;a href="https://helm.sh/docs/topics/registries/#enabling-oci-support" rel="noopener noreferrer"&gt;enables the OCI support&lt;/a&gt; for the HELM commands we are going to run later in the YAML.&lt;/p&gt;

&lt;p&gt;Next variable &lt;code&gt;HELM_VERSION_TO_INSTALL&lt;/code&gt; is used later in the workflow to install specific version of the HELM. For this workflow, we need &lt;code&gt;3.5.0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Last variable &lt;code&gt;GCR_IMAGE&lt;/code&gt; is constructing the chart name for the publication.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The GitHub Container Registry hosts containers at &lt;code&gt;ghcr.io/OWNER/IMAGE-NAME&lt;/code&gt;. I get the &lt;code&gt;OWNER&lt;/code&gt; of the repository using &lt;code&gt;github.repository_owner&lt;/code&gt; from &lt;a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" rel="noopener noreferrer"&gt;&lt;code&gt;github&lt;/code&gt; context&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next steps are defining the &lt;code&gt;job&lt;/code&gt; with steps to download the code (where we have HELM chart) and install the specific HELM tool on the runner/agent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jobs:
  build:
    name: publish gcr
    runs-on: ubuntu-latest
    environment: prod
    steps:
      - uses: actions/checkout@v2
        name: checkout repo

      - name: install helm
        uses: Azure/setup-helm@v1
        with:
          # Version of helm
          version: ${{ env.HELM_VERSION_TO_INSTALL }} # default is latest

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above steps setup the agent machine with the required HELM tool.&lt;/p&gt;

&lt;p&gt;Next, we need to run few &lt;code&gt;helm&lt;/code&gt; commands to login to GCR (GitHub Container Registry) and finally publish the chart.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We login to GCR using &lt;code&gt;${{ secrets.GITHUB_TOKEN }}&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;GitHub Container Registry only &lt;a href="https://github.blog/changelog/2021-03-24-packages-container-registry-now-supports-github_token/" rel="noopener noreferrer"&gt;recently&lt;/a&gt; started supporting &lt;code&gt;GITHUB_TOKEN&lt;/code&gt;. Previously you had to create a separate PAT token with specific permissions to GCR.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Next two steps in the workflow will be to save the chart and publish. We do that using &lt;code&gt;helm chart save&lt;/code&gt; and &lt;code&gt;help chart push&lt;/code&gt; commands as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: login to acr using helm
  run: |
    echo ${{ secrets.GITHUB_TOKEN }} | helm registry login ${{ env.GCR_IMAGE }} --username ${{ github.repository_owner }} --password-stdin

- name: save helm chart to local registry
  run: |
    helm chart save ${{ github.workspace }}/src/azure-vote-helm-chart/ ${{ env.GCR_IMAGE }}:${{ github.sha }}

- name: publish chart to acr
  run: |
    helm chart push ${{ env.GCR_IMAGE }}:${{ github.sha }}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is it, if all worked successfully for you, you should see the chart in the GCR.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.visualstudiogeeks.com%2Fimages%2Fscreenshots%2Futkarsh%2F2021%2Fapr%2Fpublish-helm-3-charts-to-gcr%2Fpublished-chart.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.visualstudiogeeks.com%2Fimages%2Fscreenshots%2Futkarsh%2F2021%2Fapr%2Fpublish-helm-3-charts-to-gcr%2Fpublished-chart.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>container</category>
      <category>helm</category>
    </item>
    <item>
      <title>Publish HELM 3 charts to Azure Container Registry (ACR) using GitHub Actions</title>
      <dc:creator>Utkarsh Shigihalli</dc:creator>
      <pubDate>Thu, 01 Apr 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/onlyutkarsh/publish-helm-3-charts-to-azure-container-registry-acr-using-github-actions-10e7</link>
      <guid>https://dev.to/onlyutkarsh/publish-helm-3-charts-to-azure-container-registry-acr-using-github-actions-10e7</guid>
      <description>&lt;p&gt;In my &lt;a href="https://dev.to/onlyutkarsh/helm-3-ci-cd-with-azure-devops-using-azure-container-registry-acr-and-azure-kubernetes-service-aks-im8"&gt;previous&lt;/a&gt; post, we briefly covered how to publish a HELM chart to ACR using Azure DevOps. In this post we will use GitHub actions to build and publish HELM chart to ACR using GitHub Actions. We will also take a sneak peak how GitHub environments work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Kauvfn_h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/apr/publish-helm-acr-github-actions/github-helm-acr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Kauvfn_h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/apr/publish-helm-acr-github-actions/github-helm-acr.jpg" alt="" width="512" height="142"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-requisites
&lt;/h2&gt;

&lt;p&gt;I am going to assume ACR instance is setup using repository scoped tokens. Since we already covered setting up of ACR this way in the &lt;a href="https://www.visualstudiogeeks.com/devops/helm/deploying-helm-chart-with-azdo#setting-up-the-acr-to-use-repository-scoped-tokens"&gt;earlier post&lt;/a&gt;, I will not include the steps here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up secrets at GitHub
&lt;/h2&gt;

&lt;p&gt;We would like store Azure Container Registry’s tokens as GitHub repository level secrets. To do that, click on &lt;code&gt;Settings&lt;/code&gt; on the repository page and head to &lt;code&gt;Secrets&lt;/code&gt; tab. Finally click on &lt;code&gt;New repository secret&lt;/code&gt; and add the token name and the password. I have stored token name as &lt;code&gt;ACR_PUSH_USER&lt;/code&gt; and token password as &lt;code&gt;ACR_PUSH_TOKEN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xFWQL-fC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/apr/publish-helm-acr-github-actions/add-secret.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xFWQL-fC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/apr/publish-helm-acr-github-actions/add-secret.jpg" alt="" width="880" height="500"&gt;&lt;/a&gt;Add repository secrets&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the workflow in GitHub Actions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Publish chart to ACR
&lt;/h3&gt;

&lt;p&gt;The first step is to create an yaml file under &lt;code&gt;.github\workflows&lt;/code&gt; folder and setup a basic structure. The first things (see the yaml below) are defining name for the action, currently set to trigger via manual trigger using &lt;code&gt;workflow_dispatch&lt;/code&gt; and define few environment variables which we are going to use later in the action.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: ci

on: 
  workflow_dispatch:

env:
  HELM_EXPERIMENTAL_OCI: 1
  HELM_VERSION_TO_INSTALL: 3.5.0
  ACR_NAME: acrdemoutkarsh
  ACR_REPO_NAME: helmdemo/vote-app

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first environment variable conveys to ACR that we are going to publish a &lt;a href="https://helm.sh/docs/topics/registries/"&gt;OCI package&lt;/a&gt;. Next couple of variables just define version of HELM we need on the runner, our ACR name to which we are going to publish this chart and finally to the repository we are publishing this chart to (used in below sections).&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing Helm 3 on the agent
&lt;/h3&gt;

&lt;p&gt;Now that we have all the variables defined, we need add jobs and steps to build our workflow to publish charts to ACR. We then need to install HELM tool on the agent before we can run the HELM commands. We do that using yaml below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jobs:
  build:
    name: publish acr
    runs-on: ubuntu-latest
    environment: prod
    steps:
      - uses: actions/checkout@v2
        name: checkout repo

      - name: install helm
        uses: Azure/setup-helm@v1
        with:
          version: ${{ env.HELM_VERSION_TO_INSTALL }}# default is latest

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we have one job named &lt;code&gt;build&lt;/code&gt; (which will be displayed as &lt;code&gt;publish acr&lt;/code&gt; - see screenshot below) which runs on &lt;code&gt;ubuntu-latest&lt;/code&gt; agent. We also are targeting our deployment to an environment &lt;code&gt;prod&lt;/code&gt;. &lt;a href="https://docs.github.com/en/actions/reference/environments"&gt;Environments&lt;/a&gt; in GitHub are cool because you can have approvers, additional protection rules for environments and environment specific secrets. In the screenshot below, notice how the flow is waiting for review.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AGFhX_XJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/apr/publish-helm-acr-github-actions/environment-approvers.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AGFhX_XJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/apr/publish-helm-acr-github-actions/environment-approvers.jpg" alt="" width="880" height="326"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we checkout the repository and using &lt;code&gt;setup-helm&lt;/code&gt; task from Azure repo we install the specific version (&lt;code&gt;3.5.0&lt;/code&gt;) of HELM.&lt;/p&gt;

&lt;h3&gt;
  
  
  Login to the ACR using Helm
&lt;/h3&gt;

&lt;p&gt;Next, we need to login to ACR registry using HELM tool.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: login to acr using helm
  run: |
    echo $ | helm registry login $.azurecr.io --username $ --password-stdin 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Save and push the chart to ACR
&lt;/h3&gt;

&lt;p&gt;Next we need to save the chart directory to local cache and publish it to ACR.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: save helm chart to local registry
  run: |
    helm chart save $/src/azure-vote-helm-chart/ $.azurecr.io/$:latest

- name: publish chart to acr
  run: |
    helm chart push $.azurecr.io/$:latest

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the workflow, and you will see output as below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8pDwY25r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/apr/publish-helm-acr-github-actions/run.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8pDwY25r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/apr/publish-helm-acr-github-actions/run.jpg" alt="" width="878" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go to ACR and you will see char correctly published to &lt;code&gt;helmdemo/vote-app&lt;/code&gt; repository as declared in the &lt;code&gt;env&lt;/code&gt; section above.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SX05LRsU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/apr/publish-helm-acr-github-actions/acr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SX05LRsU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021/apr/publish-helm-acr-github-actions/acr.jpg" alt="" width="880" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this post, you saw how easily we can deploy a OCI package (helm3 chart) to ACR using GitHub actions. We also saw how GitHub environments help you approve changes to the environment. Hope you enjoyed reading this post.&lt;/p&gt;

</description>
      <category>github</category>
      <category>actions</category>
      <category>acr</category>
      <category>azure</category>
    </item>
    <item>
      <title>Helm 3 - CI/CD with Azure DevOps using Azure Container Registry (ACR) and Azure Kubernetes Service (AKS)</title>
      <dc:creator>Utkarsh Shigihalli</dc:creator>
      <pubDate>Sat, 30 Jan 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/onlyutkarsh/helm-3-ci-cd-with-azure-devops-using-azure-container-registry-acr-and-azure-kubernetes-service-aks-im8</link>
      <guid>https://dev.to/onlyutkarsh/helm-3-ci-cd-with-azure-devops-using-azure-container-registry-acr-and-azure-kubernetes-service-aks-im8</guid>
      <description>&lt;p&gt;I have been bit late to Kubernetes world, but ever since I have started using it, I have been part of a great teams building awesome applications and using Helm package manager. With Helm, you package your Kubernetes application as charts, which are then stored in Helm chart repo. Helm also has a templating engine allowing you to set values in your charts dynamically allowing you to manage your applications more easily. Azure Container Registry (ACR) currently supports publishing Helm 3 charts to ACR and it is currently in preview.&lt;/p&gt;

&lt;p&gt;In this post we will see how we can publish a sample Helm chart to ACR and also deploy the application to Azure Kubernetes Service (AKS) by consuming the published chart from ACR. We will also use ACR’s repository scoped tokens - a preview feature which offer great benefits.&amp;lt;!--more--&amp;gt;&lt;/p&gt;

&lt;p&gt;We will cover following things in this post.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1) Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ACR 

&lt;ul&gt;
&lt;li&gt;Setting up the ACR to use repository scoped tokens&lt;/li&gt;
&lt;li&gt;Create scope-maps&lt;/li&gt;
&lt;li&gt;Create a token&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;AKS 

&lt;ul&gt;
&lt;li&gt;Create AKS instance on Azure&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For CI and CD, I am going to use Azure DevOps YAML multi-stage pipelines in this post and our pipeline will be divided as below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2) CI Stage&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get the latest chart from GitHub&lt;/li&gt;
&lt;li&gt;Publish to ACR&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3) CD Stage&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pull the latest version of chart from ACR&lt;/li&gt;
&lt;li&gt;Deploy the pulled to AKS&lt;/li&gt;
&lt;li&gt;View the deployed service in Azure DevOps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OtX-MGcF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/featureimage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OtX-MGcF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/featureimage.png" alt="" width="880" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code I am using is on &lt;a href="https://github.com/utkarshpoc/azure-vote-helm-chart"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6DVM7nE1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/github-azure--vote--helm--chart-brightgreen%3Flogo%3Dgithub%2Cgithub-actions" alt="GitHub User" width="180" height="20"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Prerequisites
&lt;/h2&gt;

&lt;p&gt;You can authenticate with ACR in multiple ways.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Using a service principal&lt;/strong&gt; - You can create separate service principals. This gives access to whole ACR and all the repositories inside that ACR instance. More info &lt;a href="https://docs.microsoft.com/en-gb/azure/container-registry/container-registry-auth-service-principal"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Using managed identity&lt;/strong&gt; - Using user-assigned or system-assigned managed identity for easily consuming charts on an Azure VM. More info &lt;a href="https://docs.microsoft.com/en-gb/azure/container-registry/container-registry-authentication-managed-identity"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Using image pull secret&lt;/strong&gt; - For your Kubernetes (K8s) cluster (including unmanaged AKS instance), you can also define a image pull secret, which then lets K8s cluster do pull images and run the application. More info on how you can do this with AKS is &lt;a href="https://docs.microsoft.com/en-gb/azure/container-registry/container-registry-auth-kubernetes"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Using a repository scoped token&lt;/strong&gt; - This feature of ACR is currently in &lt;em&gt;preview&lt;/em&gt; and only available on &lt;strong&gt;Premium&lt;/strong&gt; container registry service tier. This allows you to define scope maps and repository specific tokens for your ACR.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Setting up the ACR to use repository scoped tokens
&lt;/h3&gt;

&lt;p&gt;I am going to use &lt;strong&gt;Tokens&lt;/strong&gt; to authenticate ourselves with ACR. The biggest advantage is that, as a registry owner, you can have a single instance of ACR across your organisation and provide access to certain teams only selected repositories. There are other interesting scenarios highlighted in the &lt;a href="https://docs.microsoft.com/en-gb/azure/container-registry/container-registry-repository-scoped-permissions"&gt;documentation&lt;/a&gt;, mainly…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow IoT devices with individual tokens to pull an image from a repository&lt;/li&gt;
&lt;li&gt;Provide an external organisation with permissions to a specific repository&lt;/li&gt;
&lt;li&gt;Limit repository access to different user groups in your organisation. For example, provide write and read access to developers who build images that target specific repositories, and read access to teams that deploy from those repositories.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have an existing ACR instance (which in my case I do), the first step is to upgrade your ACR instance to use &lt;code&gt;Premium&lt;/code&gt; tier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q6rQ8KV5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/acr-upgrade.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q6rQ8KV5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/acr-upgrade.jpg" alt="" width="583" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then select &lt;code&gt;Premium&lt;/code&gt; and click &lt;code&gt;Save&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4P1KRJRA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/acr-upgrade-premium.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4P1KRJRA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/acr-upgrade-premium.jpg" alt="" width="620" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating scope maps
&lt;/h3&gt;

&lt;p&gt;Once, you are on Premium tier, you will be able to to create a tokens. But before we can create tokens, let us define two scope maps. Scope maps when associated with tokens sets permissions on what can be done on ACR.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;chartpull&lt;/strong&gt; - a scope limiting read permission to &lt;code&gt;helmdemo/vote-app&lt;/code&gt; repo. I am using &lt;code&gt;content/read&lt;/code&gt; and &lt;code&gt;metadata/read&lt;/code&gt; permissions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;chartpush&lt;/strong&gt; - a scope limiting write permission inside &lt;code&gt;helmdemo/vote-app&lt;/code&gt; repo. I am using &lt;code&gt;content/write&lt;/code&gt; and &lt;code&gt;content/read&lt;/code&gt; permissions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The idea here is that, development team pushes the charts to ACR and some other team is consuming the charts/application. But you can extend this idea to let users external to your organisation to pull images only from specific repositories.&lt;/p&gt;

&lt;p&gt;So to create scope map, go to &lt;code&gt;Scope maps&lt;/code&gt; under &lt;code&gt;Repository permissions&lt;/code&gt; sections and then click &lt;code&gt;+ Add&lt;/code&gt;. In my case, I am limiting these scopes only to &lt;code&gt;helmdemo&lt;/code&gt; repo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cJgsDvKC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/scope-map.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cJgsDvKC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/scope-map.jpg" alt="" width="747" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I follow the same process to create another scope named &lt;code&gt;chartpull&lt;/code&gt; scope with &lt;code&gt;content/read&lt;/code&gt;, &lt;code&gt;metadata/read&lt;/code&gt; scopes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Notice that in &lt;code&gt;chartpush&lt;/code&gt; scope we also allow &lt;code&gt;content/read&lt;/code&gt; permission. This is because, you need &lt;code&gt;content/read&lt;/code&gt; scope along with &lt;code&gt;content/write&lt;/code&gt; scope if you are going to push charts to ACR (for the repo defined in the scope).&lt;/li&gt;
&lt;li&gt;You can also use Azure CLI to do the same. Use &lt;code&gt;az acr token&lt;/code&gt; command. Refer the &lt;a href="https://docs.microsoft.com/en-us/cli/azure/acr/token?view=azure-cli-latest"&gt;documentation&lt;/a&gt; for more information.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Creating token
&lt;/h3&gt;

&lt;p&gt;Once you defined scopes, you are ready to create tokens. Go to &lt;code&gt;Tokens&lt;/code&gt; in &lt;code&gt;Repository permissions&lt;/code&gt; section and click &lt;code&gt;+ Add&lt;/code&gt;. Then name the token (e.g. &lt;code&gt;helmdemopull&lt;/code&gt;) and select the scope map you created above. In my case I am creating two tokens, one for pull and another one for push.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0vY8OUGc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/create-token.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0vY8OUGc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/create-token.jpg" alt="" width="755" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can repeat the process to create another token. Refreshing the screen you will see something like this below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VdsblGqf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/tokens.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VdsblGqf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/tokens.jpg" alt="" width="880" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will notice that these tokens (&lt;code&gt;helmdemopull&lt;/code&gt; and &lt;code&gt;helmdemopush&lt;/code&gt;) do not yet have passwords generated. Lets create passwords. Click on the token, click the icon under &lt;code&gt;Actions&lt;/code&gt; column for either &lt;code&gt;password1&lt;/code&gt; or &lt;code&gt;password2&lt;/code&gt;. You will also have an option to set an expiration date for the password if you planning to allow token to be valid only for specific days.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aX-kCVoR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/password1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aX-kCVoR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/password1.jpg" alt="" width="567" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. CI Stage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Get the latest chart from GitHub
&lt;/h3&gt;

&lt;p&gt;To get the latest source from the GitHub repo, in our YAML pipeline we add a &lt;code&gt;resources&lt;/code&gt; section and point to the repo on GitHub. We will also need to pass the &lt;code&gt;endpoint&lt;/code&gt; parameter with the name of the GitHub service connection. More info about how to do this is &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=azure-devops&amp;amp;tabs=schema,parameter-schema#repository-resource"&gt;here&lt;/a&gt; and &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=azure-devops&amp;amp;tabs=schema,parameter-schema#repository-resource"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;repositories&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;helmrepo&lt;/span&gt;
     &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github&lt;/span&gt;
     &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;utkarshpoc/azure-vote-helm-chart&lt;/span&gt;
     &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Publish chart to ACR
&lt;/h3&gt;

&lt;p&gt;Before we write steps to publish to ACR, we need to ensure we store the tokens we generated in the pipeline as variables. Here I am adding tokens as variables using the variables UI of the pipeline and marking passwords as secret.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WICnZSaI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/add-variables.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WICnZSaI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/add-variables.jpg" alt="" width="341" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can also define these in Azure Pipelines &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/library/?view=azure-devops"&gt;Library&lt;/a&gt; if you intend to use these tokens in multiple pipelines.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I also have few static and non-secret variables in YAML itself so that they are source controlled using &lt;code&gt;variables&lt;/code&gt; as below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;acr.name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;acrdemoutkarsh&lt;/span&gt;
  &lt;span class="na"&gt;acr.repo.name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;helmdemo/vote-app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The steps involved for publishing our Helm chart are simple.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Installing Helm 3 on the agent&lt;/li&gt;
&lt;li&gt;Login to the ACR using Helm&lt;/li&gt;
&lt;li&gt;Save and push the chart&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  1. Installing Helm 3 on the agent
&lt;/h4&gt;

&lt;p&gt;You can do this using OOB &lt;code&gt;HelmInstaller&lt;/code&gt; task. The YAML is as below. Here I am using &lt;code&gt;latest&lt;/code&gt; for &lt;code&gt;helmVersion&lt;/code&gt;, but you can stick specific to a version (3.x and above).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HelmInstaller@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;install helm&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;helmVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;latest'&lt;/span&gt;
    &lt;span class="na"&gt;installKubectl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Login to the ACR using Helm
&lt;/h3&gt;

&lt;p&gt;We can use simple &lt;code&gt;script&lt;/code&gt; step to login to the registry.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;helm registry login $(acr.name).azurecr.io --username $(acr.push.username) --password $(acr.push.password)&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;login to acr using helm&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But if you run this, at the time of writing you will get an error as below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error: this feature has been marked as experimental and is not enabled by default. 
Please set HELM_EXPERIMENTAL_OCI=1 in your environment to use this feature
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the error states, this is because, publishing Helm charts which follow Open Container Initiative (OCI) standard is experimental and you are required to set &lt;code&gt;HELM_EXPERIMENTAL_OCI&lt;/code&gt; to &lt;code&gt;1&lt;/code&gt;. We can do this by updating our &lt;code&gt;variables&lt;/code&gt; section in the YAML. The updated yaml looks as below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;acr.name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;acrdemoutkarsh&lt;/span&gt;
  &lt;span class="na"&gt;acr.repo.name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;helmdemo/vote-app&lt;/span&gt;
  &lt;span class="na"&gt;HELM_EXPERIMENTAL_OCI&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Save and push the chart to ACR
&lt;/h4&gt;

&lt;p&gt;Next step is to save this chart locally and create an alias for the chart with our ACR registry URL. So our YAML looks as below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;helm chart save $(build.sourcesdirectory)/src/azure-vote-helm-chart/ $(acr.name).azurecr.io/$(acr.repo.name):latest&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;save the chart and set the alias&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, we push the Helm chart to ACR using &lt;code&gt;helm chart push&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;helm chart push $(acr.name).azurecr.io/$(acr.repo.name):latest&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;push the chart to acr&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So our CI stage is now complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. CD Stage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pull the latest version of chart from ACR
&lt;/h3&gt;

&lt;p&gt;The first step is to pull the latest version of the chart (one with tag &lt;code&gt;latest&lt;/code&gt;) to our agent machine and extract it in a folder. We can do that in pipeline as below. Notice I have added a new stage name &lt;code&gt;cd&lt;/code&gt; and its dependent of stage &lt;code&gt;ci&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cd&lt;/span&gt;
    &lt;span class="s"&gt;displayName&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CD&lt;/span&gt;
    &lt;span class="s"&gt;dependsOn&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ci&lt;/span&gt;
    &lt;span class="s"&gt;jobs&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;deployment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;helm_publish_aks&lt;/span&gt;
      &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy to aks&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PROD&lt;/span&gt;
        &lt;span class="na"&gt;resourceName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;helmdemo&lt;/span&gt;
        &lt;span class="na"&gt;resourceType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Kubernetes&lt;/span&gt;
      &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;runOnce&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HelmInstaller@0&lt;/span&gt;
              &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;install helm&lt;/span&gt;
              &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;helmVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;latest'&lt;/span&gt;
                &lt;span class="na"&gt;installKubectl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;

            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
                &lt;span class="s"&gt;echo "$(acr.pull.password)" | helm registry login $(acr.name).azurecr.io --username $(acr.pull.username) --password-stdin&lt;/span&gt;
              &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;login to acr using helm&lt;/span&gt;

            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;bash&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
                  &lt;span class="s"&gt;helm chart pull $(acr.name).azurecr.io/$(acr.repo.name):latest&lt;/span&gt;
              &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;get helm chart on agent&lt;/span&gt;

            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;bash&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
                &lt;span class="s"&gt;helm chart export $(acr.name).azurecr.io/$(acr.repo.name):latest --destination $(build.stagingdirectory)&lt;/span&gt;
              &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;export the chart to folder&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Because each job in Azure DevOps run in a separate agent, I have to ensure agent has Helm tool, so install Helm tool again in the first step. Also, note that I am using token with scope-map permission set only to pull charts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Deploy the chart to AKS
&lt;/h3&gt;

&lt;p&gt;Now that the latest chart is pulled from our ACR and is available on agent, only step remaining is to deploy to AKS. We can do that using &lt;code&gt;HelmDeploy&lt;/code&gt; task.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HelmDeploy@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy chart to aks&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;connectionType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Azure&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Resource&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Manager'&lt;/span&gt;
    &lt;span class="na"&gt;azureSubscription&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(azure.service.connection)'&lt;/span&gt;
    &lt;span class="na"&gt;azureResourceGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;demos'&lt;/span&gt;
    &lt;span class="na"&gt;kubernetesCluster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;aksdemoutkarsh'&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;helmdemo'&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;upgrade'&lt;/span&gt;
    &lt;span class="na"&gt;chartType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;FilePath'&lt;/span&gt;
    &lt;span class="na"&gt;chartPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(build.stagingdirectory)/azure-vote/'&lt;/span&gt;
    &lt;span class="na"&gt;releaseName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;helmdemo'&lt;/span&gt;
    &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--create-namespace&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--install'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  View the deployed service in Azure DevOps
&lt;/h3&gt;

&lt;p&gt;If you have added your &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/environments-kubernetes?view=azure-devops"&gt;Kubernetes cluster as a resource&lt;/a&gt; in Azure DevOps environment, you can now view deployed services directly from Azure DevOps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9ysg4Nq1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/pipeline-env.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9ysg4Nq1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/pipeline-env.jpg" alt="" width="880" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also view deployed services in YAML and also see any ports exposed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i9LCp4w8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/pipeline-service.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i9LCp4w8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/pipeline-service.jpg" alt="" width="880" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Browsing the exposed port, you will see application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9nJuEDV8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/browse-app.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9nJuEDV8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2021-01-30-deploying-helm-chart-with-azdo/browse-app.jpg" alt="" width="674" height="477"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;That is it! If you have read this far, thank you 🙏🏼. As we saw, with the support of tokens and OCI artifacts, ACR is one of the best in class container registry. Also, with deep integration with AKS (features like browsing services, logs, yaml), Azure DevOps brings in lots of productivity for your teams. Hope you found this post informative. If so, please share and tweet!&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>aks</category>
      <category>azuredevops</category>
      <category>helm</category>
    </item>
    <item>
      <title>Quickly switch Kubernetes cluster and namespaces with kubectx and kubens</title>
      <dc:creator>Utkarsh Shigihalli</dc:creator>
      <pubDate>Tue, 29 Dec 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/onlyutkarsh/quickly-switch-kubernetes-cluster-and-namespaces-with-kubectx-and-kubens-384n</link>
      <guid>https://dev.to/onlyutkarsh/quickly-switch-kubernetes-cluster-and-namespaces-with-kubectx-and-kubens-384n</guid>
      <description>&lt;p&gt;Often when working with Kubernetes you might find yourself switching between your clusters or namespaces. I am doing this numerous times lately and I was slow switching using the regular commands. In this post, I would like to highlight two productivity utilities when working with Kubernetes which will make it simple when working with multiple clusters.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Hg5VmSde--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2020-12-30-using-kubectx-kubens/cluster-ns.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Hg5VmSde--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2020-12-30-using-kubectx-kubens/cluster-ns.png" alt="" width="500" height="360"&gt;&lt;/a&gt;Cluster contexts and namespaces&lt;/p&gt;

&lt;p&gt;Kubernetes stores the cluster information in &lt;code&gt;~/.kube/config&lt;/code&gt; file and stores in as a context information. If you are working against multiple clusters ideally you would have different config files and can reference them when running commands with &lt;code&gt;kubectl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, to get pods in different cluster than your default context, you use below command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;--namespace&lt;/span&gt; dev-ns &lt;span class="nt"&gt;--kubeconfig&lt;/span&gt; ~/.kube/devClusterConfig
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, typing namespace information and providing the config for every command is cumbersome.&lt;/p&gt;

&lt;h3&gt;
  
  
  Merging multiple config files in to one
&lt;/h3&gt;

&lt;p&gt;If you already have multiple config files to connect to different clusters, you would like to merge them first. You can merge both the config file using syntax below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Merge ~/.kube/config and ~/.kube/devClusterConfig in to new config /tmp/config&lt;/span&gt;
&lt;span class="nv"&gt;$ KUBECONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/.kube/config:~/.kube/devClusterConfig kubectl config view &lt;span class="nt"&gt;--flatten&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/config

&lt;span class="c"&gt;# Replace old config with new merged config&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mv&lt;/span&gt; /tmp/config ~/.kube/config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Switching the Kubernetes clusters using kubectl commands
&lt;/h3&gt;

&lt;p&gt;Kubernetes already has a concept of contexts and once you merge the config, you will be able to see the contexts information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl config get-contexts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see context information as below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;CURRENT NAME CLUSTER AUTHINFO NAMESPACE
&lt;span class="k"&gt;*&lt;/span&gt; dev-aks-cluster dev-aks-cluster clusterUser_aksdemo_dev-aks-cluster dev-ns
          qa-aks-cluster qa-aks-cluster clusterUser_aksdemo_qa-aks-cluster
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then switch to the different cluster (in my case its &lt;code&gt;qa-aks-cluster&lt;/code&gt;) using below command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl config use-context qa-aks-cluster
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Switching the namespaces using kubectl commands
&lt;/h3&gt;

&lt;p&gt;Now if you do not want to add &lt;code&gt;--namespace &amp;lt;namespace-name&amp;gt;&lt;/code&gt; for every command you type, you can also set it as default namespace for the currently selected context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl config set-context &lt;span class="nt"&gt;--current&lt;/span&gt; &lt;span class="nt"&gt;--namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;insert-namespace-name-here&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using kubectx and kubens
&lt;/h3&gt;

&lt;h4&gt;
  
  
  kubectx
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;kubectx&lt;/code&gt; is a great &lt;a href="https://github.com/ahmetb/kubectx/"&gt;open-source tool&lt;/a&gt; to switch clusters. Just type &lt;code&gt;kubectx&lt;/code&gt; and it lists the contexts you have. Then you can select one by typing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectx dev-aks-cluster
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have &lt;a href="https://github.com/junegunn/fzf"&gt;&lt;code&gt;fzf&lt;/code&gt;&lt;/a&gt; installed, you can also get a nice picker and you can use arrows to select one.&lt;/p&gt;

&lt;p&gt;If you keep alternating between contexts, you can also use &lt;code&gt;kubectx -&lt;/code&gt; to quickly go back to previous context. Isn’t it cool?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BOfwFLY9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2020-12-30-using-kubectx-kubens/kubectx-demo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BOfwFLY9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2020-12-30-using-kubectx-kubens/kubectx-demo.gif" alt="" width="880" height="303"&gt;&lt;/a&gt;kubectx - Source: &lt;a href="https://github.com/ahmetb/kubectx/"&gt;https://github.com/ahmetb/kubectx/&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  kubens
&lt;/h4&gt;

&lt;p&gt;Similar to &lt;code&gt;kubectx&lt;/code&gt;, &lt;code&gt;kubens&lt;/code&gt; is another great utility from the same creator. It performs pretty much similar to &lt;code&gt;kubectx&lt;/code&gt; but lets you switch namespaces. I regularly use this since we have couple of namespaces within our cluster which we deploy to. It has certainly saved me lots of typing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ytGSnnY---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2020-12-30-using-kubectx-kubens/kubens-demo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ytGSnnY---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2020-12-30-using-kubectx-kubens/kubens-demo.gif" alt="" width="880" height="361"&gt;&lt;/a&gt;kubens - Source: &lt;a href="https://github.com/ahmetb/kubectx/"&gt;https://github.com/ahmetb/kubectx/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;If you are into Kubernetes, both &lt;code&gt;kubectx&lt;/code&gt; and &lt;code&gt;kubectl&lt;/code&gt; are great productivity tools and will save you lots of time. I certainly am finding them really useful.&lt;/p&gt;

&lt;p&gt;That’s it for this post, thanks for reading, until next time time 👋🏼&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>tools</category>
      <category>productivity</category>
      <category>k8s</category>
    </item>
    <item>
      <title>Deploying TIBCO Rendezvous on RedHat Enterprise Linux using Azure DevOps</title>
      <dc:creator>Utkarsh Shigihalli</dc:creator>
      <pubDate>Mon, 28 Dec 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/onlyutkarsh/deploying-tibco-rendezvous-on-redhat-enterprise-linux-using-azure-devops-2ako</link>
      <guid>https://dev.to/onlyutkarsh/deploying-tibco-rendezvous-on-redhat-enterprise-linux-using-azure-devops-2ako</guid>
      <description>&lt;p&gt;TIBCO Rendezvous (RDV) is one of the popular messaging product for real-time data processing. Predominantly used in Financial corporations to process real-time trading, market data and efficient information flow between control systems. In this post, we will see how we can deploy this messaging application to RedHat Enterprise Linux (RHEL) 7 (on Azure VM) using Azure DevOps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ms1ySaS6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2020-12-28-deploying-tibco-rdv-using-azure-devops/featureimage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ms1ySaS6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2020-12-28-deploying-tibco-rdv-using-azure-devops/featureimage.png" alt="" width="530" height="294"&gt;&lt;/a&gt;Source: &lt;a href="https://www.tibco.com/products/tibco-rendezvous"&gt;https://www.tibco.com/products/tibco-rendezvous&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this post, we are assuming that we have a RHEL VM provisioned on Azure to which we are going to deploy. Also, the installers are downloaded published to Azure Artifacts as an &lt;a href="https://docs.microsoft.com/en-us/azure/devops/artifacts/quickstarts/universal-packages?view=azure-devops&amp;amp;tabs=azuredevops"&gt;Universal Package&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create SSH service connection in Azure DevOps
&lt;/h3&gt;

&lt;p&gt;The first step is to ensure Azure DevOps can connect to our VM in Azure. For that, we set up a service connection in Azure DevOps. Since its Linux VM, we use SSH connection. Detailed steps of creating the SSH service connection are &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints?view=azure-devops&amp;amp;tabs=yaml#sep-ssh"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EvvzYuji--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2020-12-28-deploying-tibco-rdv-using-azure-devops/service-connection.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EvvzYuji--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2020-12-28-deploying-tibco-rdv-using-azure-devops/service-connection.jpg" alt="" width="880" height="373"&gt;&lt;/a&gt;Service connection in Azure DevOps&lt;/p&gt;

&lt;h3&gt;
  
  
  Create deployment pipeline
&lt;/h3&gt;

&lt;p&gt;To summarize, the steps for deployment are&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download and extract the installer from Azure Artifacts&lt;/li&gt;
&lt;li&gt;Install required pre-requisites&lt;/li&gt;
&lt;li&gt;Copy the installer to VM&lt;/li&gt;
&lt;li&gt;Adjust the install path in TIBCO Rendezvous response file&lt;/li&gt;
&lt;li&gt;Set the execute permission on the installer so that we can run the installer&lt;/li&gt;
&lt;li&gt;Delete any existing instance of the RDV, so that we can trigger this pipeline again without any manual changes.&lt;/li&gt;
&lt;li&gt;Install TIBCO Rendezvous&lt;/li&gt;
&lt;li&gt;Add installer file to &lt;code&gt;~/.bash_profile&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Set execute permissions and start the service.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  1. Download and extract the installer from Azure Artifacts
&lt;/h4&gt;

&lt;p&gt;We use Universal Package task from Azure DevOps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UniversalPackages@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;download rdv package from artifacts&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;download'&lt;/span&gt;
    &lt;span class="na"&gt;downloadDirectory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(system.artifactsdirectory)'&lt;/span&gt;
    &lt;span class="na"&gt;feedsToUse&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;internal'&lt;/span&gt;
    &lt;span class="na"&gt;vstsFeed&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Demo/my-artifacts'&lt;/span&gt;
    &lt;span class="na"&gt;vstsFeedPackage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tibco-rdv'&lt;/span&gt;
    &lt;span class="na"&gt;vstsPackageVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;8.4.5'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Install required pre-requisites
&lt;/h4&gt;

&lt;p&gt;We then install any required pre-requisites needed on the machine. Here we are installing Java 1.8, GNU C Library. Notice that we are using SSH task so that these commands are run on the VM we are deploying to. We use the service connection created above and passing that as a parameter to this pipeline YAML. Azure DevOps has a powerful templating feature for YAML pipelines, and here I am using a template. So I am using &lt;code&gt;${{ }}&lt;/code&gt; syntax. More on this expression is &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops#template-expressions"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SSH@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;prerequisites'&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sshEndpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$'&lt;/span&gt;
    &lt;span class="na"&gt;runOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;commands'&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;sudo yum -y install java-1.8.0-openjdk.x86_64&lt;/span&gt;
        &lt;span class="s"&gt;sudo yum -y install glibc.x86_64&lt;/span&gt;
    &lt;span class="na"&gt;readyTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20000'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Copy the installer to VM
&lt;/h4&gt;

&lt;p&gt;Next we need to copy the installer files to VM. We again do that using &lt;code&gt;CopyFilesOverSSH&lt;/code&gt; task in Azure DevOps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CopyFilesOverSSH@0&lt;/span&gt;
&lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;copy&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tibco&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;rvd&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;installer&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;files&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;machine'&lt;/span&gt;
&lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;sshEndpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$'&lt;/span&gt;
  &lt;span class="na"&gt;sourceFolder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(system.artifactsdirectory)/out'&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;**'&lt;/span&gt;
  &lt;span class="na"&gt;targetFolder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/data/tibco-rdv/'&lt;/span&gt;
  &lt;span class="na"&gt;readyTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20000'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4. Adjust the install path in TIBCO Rendezvous response file
&lt;/h4&gt;

&lt;p&gt;Since we are deploying TIBCO Rendezvous in our CD pipeline, we need to install using non-interactive (or silent) mode. TIBCO provides a response file (&lt;code&gt;TIBCOUniversalInstaller-rv.silent&lt;/code&gt;) along with installer. This response file can be edited to select all the configurations (like Install path, home directory etc) for the installer. We are using simple SSH task and running few &lt;code&gt;sed&lt;/code&gt; commands to replace the path according to our needs in the response file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SSH@0&lt;/span&gt;
&lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;adjust&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;response&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;silent&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;file'&lt;/span&gt;
&lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;sshEndpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$'&lt;/span&gt;
  &lt;span class="na"&gt;runOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;commands'&lt;/span&gt;
  &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;sed -i 's/\/opt\/tibco/\/opt\/tibco\/rdv/g' /data/tibco-rdv/TIBCOUniversalInstaller-rv.silent&lt;/span&gt;
      &lt;span class="s"&gt;sed -i 's/TIBCO-HOME/TIBCO-RDV-HOME/g' /data/tibco-rdv/TIBCOUniversalInstaller-rv.silent&lt;/span&gt;
  &lt;span class="na"&gt;readyTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20000'&lt;/span&gt;  

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  5. Set the execute permission on the installer so that we can run the installer
&lt;/h4&gt;

&lt;p&gt;Before we run the installer, we need to ensure that the user running it (in our case the credentials used while creating the service connection) has execute permissions. So we set the execute permissions for the installer file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SSH@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;set&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;execute&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;permissions'&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sshEndpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$'&lt;/span&gt;
    &lt;span class="na"&gt;runOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;commands'&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;chmod&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a+x&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;/data/tibco-rdv/TIBCOUniversalInstaller-lnx-x86.bin'&lt;/span&gt;
    &lt;span class="na"&gt;readyTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20000'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  6. Delete any existing instance of the RDV
&lt;/h4&gt;

&lt;p&gt;Also, before we install the service, we need to remove any existing services running, This will also enable to run this pipeline again and again without manually configuring something in the VM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SSH@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;delete&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;previous&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;instance'&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sshEndpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$'&lt;/span&gt;
    &lt;span class="na"&gt;runOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;commands'&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;pkill 'rvd64'&lt;/span&gt;
        &lt;span class="s"&gt;sudo rm -rf /opt/tibco/rdv/*&lt;/span&gt;
    &lt;span class="na"&gt;readyTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20000'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  7. Install TIBCO Rendezvous
&lt;/h4&gt;

&lt;p&gt;Next, we start the installation by executing installer file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SSH@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tibco&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;rdv'&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sshEndpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$'&lt;/span&gt;
    &lt;span class="na"&gt;runOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;commands'&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sudo&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;/data/tibco-rdv/TIBCOUniversalInstaller-lnx-x86.bin&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-silent&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-V&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;responseFile=/data/tibco-rdv/TIBCOUniversalInstaller-rv.silent&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-is:javahome&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$(dirname&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$(dirname&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$(readlink&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$(readlink&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$(which&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;java)))))&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-is:log&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"$(build.buildnumber).log"'&lt;/span&gt;
    &lt;span class="na"&gt;readyTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20000'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Notice we pass the modified response file to the installer so that it can without any manual interaction.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  8. Add installer file to &lt;code&gt;~/.bash_profile&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Next, we need to add install path to &lt;code&gt;~/.bash_profile&lt;/code&gt; so that its available from anywhere.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SSH@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;update&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bash&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;profile'&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sshEndpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$'&lt;/span&gt;
    &lt;span class="na"&gt;runOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;commands'&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;cp ~/.bash_profile ~/.bash_profile.tmp&lt;/span&gt;
        &lt;span class="s"&gt;echo 'export PATH=$PATH:/opt/tibco/rdv/tibrv/8.4/bin' &amp;gt;&amp;gt; ~/.bash_profile&lt;/span&gt;
        &lt;span class="s"&gt;echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/tibco/rdv/tibrv/8.4/lib' &amp;gt;&amp;gt; ~/.bash_profile&lt;/span&gt;
    &lt;span class="na"&gt;readyTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20000'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;In the above step, I am just backing up existing &lt;code&gt;~/.bash_profile&lt;/code&gt; file. A better way probably is to find and replace the values (to avoid duplicates) which I am planning to do in the future&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  9. Set execute permissions and start the service.
&lt;/h4&gt;

&lt;p&gt;Final step is to start the Rendezvous service itself. Before that we need to set the execute permissions for the file. So our YAML looks as below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SSH@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;set&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;execute&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;permissions'&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sshEndpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$'&lt;/span&gt;
    &lt;span class="na"&gt;runOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;commands'&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sudo&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;chmod&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a+x&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;/opt/tibco/rdv/tibrv/8.4/bin/rvd64'&lt;/span&gt;
    &lt;span class="na"&gt;readyTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20000'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SSH@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;start the rvd service&lt;/span&gt;
  &lt;span class="na"&gt;timeoutInMinutes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;continueOnError&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sshEndpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$'&lt;/span&gt;
    &lt;span class="na"&gt;runOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;inline'&lt;/span&gt;
    &lt;span class="na"&gt;inline&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;/opt/tibco/rdv/tibrv/8.4/bin/rvd64 -listen 8500&lt;/span&gt;
        &lt;span class="s"&gt;sleep 70&lt;/span&gt;
        &lt;span class="s"&gt;exit&lt;/span&gt;
    &lt;span class="na"&gt;readyTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20000'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Notice in the last step, we have enabled &lt;code&gt;continueOnError: true&lt;/code&gt;. For some reason, when you start the service, its not ending the console. There must be an option in the response file to properly start the service, but I am yet to figure it out.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Final YAML template
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# template file to deploy tibco rendezvous&lt;/span&gt;

&lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sshEndPoint&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;

&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UniversalPackages@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;download rdv package from artifacts&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;download'&lt;/span&gt;
    &lt;span class="na"&gt;downloadDirectory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(system.artifactsdirectory)'&lt;/span&gt;
    &lt;span class="na"&gt;feedsToUse&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;internal'&lt;/span&gt;
    &lt;span class="na"&gt;vstsFeed&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Demo/my-artifacts'&lt;/span&gt;
    &lt;span class="na"&gt;vstsFeedPackage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tibco-rdv'&lt;/span&gt;
    &lt;span class="na"&gt;vstsPackageVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;8.4.5'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;unzip -oq $(system.artifactsdirectory)/TIB_rv_8.4.5_linux_x86.zip -d $(system.artifactsdirectory)/out&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;extract&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;files'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SSH@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;prerequisites'&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sshEndpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$'&lt;/span&gt;
    &lt;span class="na"&gt;runOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;commands'&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;sudo yum -y install java-1.8.0-openjdk.x86_64&lt;/span&gt;
        &lt;span class="s"&gt;sudo yum -y install glibc.x86_64&lt;/span&gt;
    &lt;span class="na"&gt;readyTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20000'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CopyFilesOverSSH@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;copy&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tibco&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;rvd&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;installer&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;files&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;machine'&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sshEndpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$'&lt;/span&gt;
    &lt;span class="na"&gt;sourceFolder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(system.artifactsdirectory)/out'&lt;/span&gt;
    &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;**'&lt;/span&gt;
    &lt;span class="na"&gt;targetFolder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/data/tibco-rdv/'&lt;/span&gt;
    &lt;span class="na"&gt;readyTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20000'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SSH@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;adjust&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;response&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;silent&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;file'&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sshEndpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$'&lt;/span&gt;
    &lt;span class="na"&gt;runOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;commands'&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;sed -i 's/\/opt\/tibco/\/opt\/tibco\/rdv/g' /data/tibco-rdv/TIBCOUniversalInstaller-rv.silent&lt;/span&gt;
        &lt;span class="s"&gt;sed -i 's/TIBCO-HOME/TIBCO-RDV-HOME/g' /data/tibco-rdv/TIBCOUniversalInstaller-rv.silent&lt;/span&gt;
    &lt;span class="na"&gt;readyTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20000'&lt;/span&gt;                

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SSH@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;set&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;execute&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;permissions'&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sshEndpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$'&lt;/span&gt;
    &lt;span class="na"&gt;runOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;commands'&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;chmod&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a+x&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;/data/tibco-rdv/TIBCOUniversalInstaller-lnx-x86.bin'&lt;/span&gt;
    &lt;span class="na"&gt;readyTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20000'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SSH@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;delete&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;previous&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;instance'&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sshEndpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$'&lt;/span&gt;
    &lt;span class="na"&gt;runOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;commands'&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;pkill 'rvd64'&lt;/span&gt;
        &lt;span class="s"&gt;sudo rm -rf /opt/tibco/rdv/*&lt;/span&gt;
    &lt;span class="na"&gt;readyTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20000'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SSH@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tibco&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;rdv'&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sshEndpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$'&lt;/span&gt;
    &lt;span class="na"&gt;runOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;commands'&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sudo&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;/data/tibco-rdv/TIBCOUniversalInstaller-lnx-x86.bin&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-silent&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-V&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;responseFile=/data/tibco-rdv/TIBCOUniversalInstaller-rv.silent&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-is:javahome&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$(dirname&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$(dirname&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$(readlink&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$(readlink&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$(which&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;java)))))&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-is:log&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"$(build.buildnumber).log"'&lt;/span&gt;
    &lt;span class="na"&gt;readyTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20000'&lt;/span&gt;        

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SSH@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;update&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bash&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;profile'&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sshEndpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$'&lt;/span&gt;
    &lt;span class="na"&gt;runOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;commands'&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;cp ~/.bash_profile ~/.bash_profile.tmp&lt;/span&gt;
        &lt;span class="s"&gt;echo 'export PATH=$PATH:/opt/tibco/rdv/tibrv/8.4/bin' &amp;gt;&amp;gt; ~/.bash_profile&lt;/span&gt;
        &lt;span class="s"&gt;echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/tibco/rdv/tibrv/8.4/lib' &amp;gt;&amp;gt; ~/.bash_profile&lt;/span&gt;
    &lt;span class="na"&gt;readyTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20000'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SSH@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;set&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;execute&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;permissions'&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sshEndpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$'&lt;/span&gt;
    &lt;span class="na"&gt;runOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;commands'&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sudo&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;chmod&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a+x&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;/opt/tibco/rdv/tibrv/8.4/bin/rvd64'&lt;/span&gt;
    &lt;span class="na"&gt;readyTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20000'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SSH@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;start the rvd service&lt;/span&gt;
  &lt;span class="na"&gt;timeoutInMinutes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;continueOnError&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sshEndpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$'&lt;/span&gt;
    &lt;span class="na"&gt;runOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;inline'&lt;/span&gt;
    &lt;span class="na"&gt;inline&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;/opt/tibco/rdv/tibrv/8.4/bin/rvd64 -listen 8500&lt;/span&gt;
        &lt;span class="s"&gt;sleep 70&lt;/span&gt;
        &lt;span class="s"&gt;exit&lt;/span&gt;
    &lt;span class="na"&gt;readyTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20000'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;That’s it, you now know how we implemented Azure DevOps pipeline to deploy TIBCO Rendezvous 🥳&lt;/p&gt;

</description>
      <category>tibco</category>
      <category>azuredevops</category>
      <category>devops</category>
    </item>
    <item>
      <title>Publish VSCode extension to VS Marketplace using simplified ChatOps</title>
      <dc:creator>Utkarsh Shigihalli</dc:creator>
      <pubDate>Mon, 10 Aug 2020 23:00:00 +0000</pubDate>
      <link>https://dev.to/onlyutkarsh/publish-vscode-extension-to-vs-marketplace-using-simplified-chatops-4ifc</link>
      <guid>https://dev.to/onlyutkarsh/publish-vscode-extension-to-vs-marketplace-using-simplified-chatops-4ifc</guid>
      <description>&lt;p&gt;I have previously &lt;a href="https://www.visualstudiogeeks.com/github/extensions/publish-vscode-extension-using-github-actions"&gt;blogged&lt;/a&gt; about publishing VSCode extensions to VSMarketplace (using GitHub actions). However, that workflow relied heavily on the branching strategy and was on assumption that anything that is merged to &lt;code&gt;master&lt;/code&gt; is ready for publishing to VSMarketplace. It worked great, but occasionally I felt the need to test the extension from &lt;code&gt;master&lt;/code&gt; and I wanted a way to &lt;strong&gt;approve&lt;/strong&gt; before I decide to publish to marketplace. In this post we will see how I used ChatOps with the help of GitHub actions and Issues to achieve the same.&lt;/p&gt;

&lt;h3&gt;
  
  
  How will it work?
&lt;/h3&gt;

&lt;p&gt;If you are short on time, the workflow I have implemented is as below.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User commits the code in a feature branch&lt;/li&gt;
&lt;li&gt;Commit automatically triggers CI workflow &lt;code&gt;build.yml&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;If trigger is from &lt;code&gt;feature/*&lt;/code&gt; branch, it produces the artifact (.vsix file) and ends the workflow. This allows me to download and test the vsix file.&lt;/li&gt;
&lt;li&gt;If trigger is from &lt;code&gt;master&lt;/code&gt; branch, it creates a GitHub issue to monitor for dispatch comments (&lt;code&gt;/deploy&lt;/code&gt; and &lt;code&gt;/reject&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Workflow &lt;code&gt;dispatch.yml&lt;/code&gt; monitors issue comments for dispatch commands.&lt;/li&gt;
&lt;li&gt;I create a issue comment and type text &lt;code&gt;/deploy&lt;/code&gt; or &lt;code&gt;/reject&lt;/code&gt; to deploy or reject a release to publish it to VS Marketplace.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;/deploy&lt;/code&gt; command is detected, workflow &lt;code&gt;deploy.yml&lt;/code&gt; is triggered.&lt;/li&gt;
&lt;li&gt;If command is instead &lt;code&gt;/reject&lt;/code&gt;, the release is rejected and issue is marked that it can be closed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Curious on how each step is implemented? Read on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Triggering CI build when user commits
&lt;/h3&gt;

&lt;p&gt;The goal of CI is that, with each commit, we can produce shippable &lt;code&gt;.vsix&lt;/code&gt; (packaged extension) file as an artifact for our extension. So we additional triggers in our &lt;code&gt;build.yml&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Trigger build&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ci"&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
  &lt;span class="na"&gt;pull_request_review&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;submitted&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;feature/**&lt;/span&gt; &lt;span class="c1"&gt;# match an pushes on feature/* and feature/&amp;lt;any sub branch&amp;gt;/*&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
    &lt;span class="na"&gt;paths-ignore&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# don't run when changes made to these folders&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.vscode/**"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;workflow_dispatch&lt;/code&gt; trigger lets us manually trigger the workflow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FikkkKri--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2020-08-11-chatops-for-vscode-extension/workflow-dispatch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FikkkKri--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2020-08-11-chatops-for-vscode-extension/workflow-dispatch.png" alt="" width="355" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pull_request&lt;/code&gt; and &lt;code&gt;pull_request_review&lt;/code&gt; triggers allow us to trigger this workflow on PRs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;push&lt;/code&gt; lets our workflow to trigger on actual commits on &lt;code&gt;master&lt;/code&gt; and &lt;code&gt;feature/**&lt;/code&gt; branches.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Creating issue for dispatch events
&lt;/h3&gt;

&lt;p&gt;As part of CI, once we produce artifact, we create the issue so that we can monitor issue for dispatch commands. I have a separate job &lt;code&gt;create-issue&lt;/code&gt; in &lt;code&gt;build.yml&lt;/code&gt; which creates the issue only if CI is running against &lt;code&gt;master&lt;/code&gt; branch.&lt;/p&gt;

&lt;p&gt;You can take a look at the job &lt;a href="https://github.com/onlyutkarsh/git-config-user-profiles/blob/29411fba2bef504e945690f8e02785c616a6ee96/.github/workflows/build.yml#L93-L121"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The output of the job will open an issue something like this (screenshot is from previous release).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Oef_NtxY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2020-08-11-chatops-for-vscode-extension/created-issue.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Oef_NtxY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2020-08-11-chatops-for-vscode-extension/created-issue.png" alt="" width="675" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Monitoring dispatch events in issue comments
&lt;/h3&gt;

&lt;p&gt;The required issue is created and now is the time to monitor for issue comments with specific commands we defined - &lt;code&gt;/dispatch&lt;/code&gt; and &lt;code&gt;/reject&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can do this with &lt;code&gt;issue_comment&lt;/code&gt; trigger as below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;issue_comment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;created&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the above trigger our &lt;code&gt;dispatch.yml&lt;/code&gt; workflow triggers whenever a comment is added on our issue. To dispatch the events I am using action from Peter Evans as below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dispatch command&lt;/span&gt;
  &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.repository_owner == github.event.comment.user.login&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;peter-evans/slash-command-dispatch@v2&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.REPO_ACCESS_TOKEN }}&lt;/span&gt;
    &lt;span class="na"&gt;reaction-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.REPO_ACCESS_TOKEN }}&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy, reject&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/marketplace/actions/slash-command-dispatch"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ahfYjGq1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/github-slash--command--dispatch-brightgreen%3Flogo%3Dgithub-actions%26logoColor%3Dwhite%26label%3DGithub%2520Actions" alt="GitHub Actions" width="257" height="20"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, in the last line (#7), I am supporting only &lt;code&gt;deploy&lt;/code&gt; and &lt;code&gt;reject&lt;/code&gt; commands.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to dispatch events, only if user commenting on the issue is owner of the repository (which is me). This allows me to dispatch events only if I have typed the dispatch command and no on else.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Handling dispatch commands
&lt;/h3&gt;

&lt;p&gt;Now, I want to &lt;strong&gt;deploy&lt;/strong&gt; to marketplace, when I see &lt;code&gt;/deploy&lt;/code&gt;, and &lt;strong&gt;reject&lt;/strong&gt; the deployment when I see &lt;code&gt;/reject&lt;/code&gt; in issue comment.&lt;/p&gt;

&lt;p&gt;For this, I have two workflow files &lt;a href="https://github.com/onlyutkarsh/git-config-user-profiles/blob/master/.github/workflows/deploy.yml"&gt;deploy.yml&lt;/a&gt; and &lt;a href="https://github.com/onlyutkarsh/git-config-user-profiles/blob/master/.github/workflows/reject.yml"&gt;reject.yml&lt;/a&gt; with trigger similar to below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;repository_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deploy-command&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So as soon as the user types &lt;code&gt;/deploy&lt;/code&gt; command as a issue comment, the command is captured and dispatched by &lt;code&gt;dispatch.yml&lt;/code&gt; workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QNs7rwQU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2020-08-11-chatops-for-vscode-extension/deploy-command.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QNs7rwQU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2020-08-11-chatops-for-vscode-extension/deploy-command.png" alt="" width="678" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The dispatched command is captured by our &lt;code&gt;deploy.yml&lt;/code&gt; or &lt;code&gt;reject.yml&lt;/code&gt; which act on &lt;code&gt;repository_dispatch&lt;/code&gt; event of either &lt;code&gt;deploy&lt;/code&gt; or &lt;code&gt;reject&lt;/code&gt; commands. All this work seamlessly with the help of &lt;code&gt;slash-command-dispatch&lt;/code&gt; action and GitHub’s &lt;code&gt;repository_dispatch&lt;/code&gt; events.&lt;/p&gt;

&lt;p&gt;Our deploy workflow just publishes the extension to VS Marketplace and before doing this it also updates the comments to the issue which triggered the workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--btj3fvXx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2020-08-11-chatops-for-vscode-extension/deploy-complete.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--btj3fvXx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.visualstudiogeeks.com/images/screenshots/utkarsh/2020-08-11-chatops-for-vscode-extension/deploy-complete.png" alt="" width="750" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;There you have it! A quick and simple way to have a approval process in GitHub actions using ChatOps. I am confident that GitHub Actions will have OOB approval flows in Actions, but until that time, this is one way to achieve it. Do let me know if you know or have implemented similar things in a better way - I would love to learn about it.&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>extensions</category>
      <category>chatops</category>
    </item>
  </channel>
</rss>
