GitHub Actions allow you to build complex workflows to automate your build and deployment processes. Built on top of Azure Pipelines, Actions allow you to maintain your workflows along with your code. In this post, we will see how we can implement CICD flow for a sample Visual Studio Code extension to deploy it to Visual Studio Marketplace.

Creating workflow file

For this post, I am using my VSIX Viewer extension (link below).

Visual Studio Marketplace Downloads

Okay, In GitHub Actions, Workflows are yaml files in our repository; containing our process for build and deploy. We must store the workflow files in repository root under .github\workflows directory.

Workflow file

For more information GitHub Actions, refer the documentation

Continuous Integration

I would like my action to trigger whenever I commit to any of the feature branches and master branch. I configure that as below in my workflow.yaml file.

on:
  push:
    branches: 
      - 'feature/**' # match an pushes on feature/* and feature/<any sub branch>/*
      - master
    paths-ignore: # dont run when changes made to these folders 
      - '.vscode/**'

I can exclude a folder using paths-ignore

Next, each workflow file will contain one or more jobs. I decided to use single workflow file and for both build and deployment. I am also using single job, and I will control what to execute using conditions.

For building my VSCode extension, I have to do following steps - My workflow file now looks like below.

  1. Checkout the code (Line #6-7)
  2. Fetch full history for versioning (Line #9-10)
  3. Install GitVersion tool (Line #12-19)
  4. Install node (Line #29-32)
  5. Install dependencies defined in pacakge.json (Line #34-35)
  6. Use marketplace action to update version in package.json (Line #37-44)
  7. Use a marketplace action to replace version in CHANGELOG.md file. (Line #46-51)
  8. Compile and create the VSIX file. (Line #53-54) - I use a custom npm script from package.json file, which internally uses vsce tool by Microsoft.
  9. Lastly, make VSIX file available for download in GitHub Artifacts (Line #60-64)
jobs:
  cicd:
    name: cicd
    runs-on: windows-latest
    steps:
      - name: checkout repo
        uses: actions/checkout@v2

      - name: fetch all history and tags from all branches for gitversion
        run: git fetch --prune --unshallow

      - name: install gitversion tool
        uses: gittools/actions/gitversion/[email protected]
        with:
            versionSpec: '5.1.x'
      
      - name: execute gitversion
        id: gitversion # step id used as reference for output values
        uses: gittools/actions/gitversion/[email protected]
        
      - name: print gitversion
        run: |
          echo "Major: ${{ steps.gitversion.outputs.major }}"
          echo "Minor: ${{ steps.gitversion.outputs.minor }}"
          echo "Patch: ${{ steps.gitversion.outputs.patch }}"
          echo "MajorMinorPatch: ${{ steps.gitversion.outputs.majorMinorPatch }}"
          echo "SemVer: ${{ steps.gitversion.outputs.semVer }}"

      - name: setup node
        uses: actions/setup-node@v1
        with:
          node-version: '12.x'
        
      - name: clean install dependencies
        run: npm ci

      - name: update metadata in package.json
        uses: onlyutkarsh/[email protected]
        with:
          files: '${{github.workspace}}/package.json'
          patch-syntax: |
            = /version => "${{ steps.gitversion.outputs.semVer }}"
            = /displayName => "VSIX Viewer"
            = /description => "A simple viewer for VSIX files, which lets you see the contents of VSIX files within Visual Studio Code."
      
      - name: add version in CHANGELOG.md
        uses: cschleiden/[email protected]
        with:
          files: '${{github.workspace}}/CHANGELOG.md'
        env:
          VERSION: "${{ steps.gitversion.outputs.semVer }}"

      - name: compile and create vsix
        run: npm run package

      - name: print vsix path
        run: |
          echo "VSIX Path: ${{ env.vsix_path }}"

      - name: upload vsix as artifact
        uses: actions/upload-artifact@v1
        with:
          name: vsix-viewer-${{steps.gitversion.outputs.semVer}}.vsix
          path: ${{github.workspace}}/vsix-viewer-${{steps.gitversion.outputs.semVer}}.vsix

Once the successful run of action is completed, you will see VSIX file as an artifact.

VSIX published as artifact

Deployment

Deploying a VSCode extension requires us to call vsce publish -p <token> command. Token is Personal Access Token(PAT). I have this command in my package.json file as deploy script. Once the deployment is done, I create a GitHub release (line #5 in code below).

You can read more on how to generate PAT here.

For deployment I could have used another job, but since my deployment steps are simple, I decided to use the same job. The only requirement I had was I wanted these deployment steps to execute only if the branch is master.

This can be achieved using if condition (Line #2 and #6 below), where I am checking if branch name is master.

github.ref is from the github context (one of the many contexts) provided by GitHub Actions. It has additional properties - check the documentation

- name: publish to marketplace
  if: github.ref == 'refs/heads/master'
  run: npm run deploy ${{ env.PAT }}

- name: create a release
  if: github.ref == 'refs/heads/master'
  uses: actions/create-release@v1
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
  with:
    tag_name: v${{ steps.gitversion.outputs.semVer }}
    release_name: v${{ steps.gitversion.outputs.semVer }}

That is it, as soon as a commit is made to master, all the steps in the workflow run including deployment steps. These steps will be ignore if the actions is triggered from any other branch.

Not triggered for feature/* branches

Conclusion

That is it, we used GitHub actions to compile and deploy VSIX to VSMarketplace. If you are interested in the complete workflow file, you can check it in the repo here. While writing this post, I did make lots of silly mistakes and it required multiple tries. If you interested in seeing them, check actions tab.


About author
Utkarsh Shigihalli
Utkarsh Shigihalli
Utkarsh is passionate about software development and has experience in the areas of Azure, Azure DevOps, C# and TypeScript. Over the years he has worked as an architect, independent consultant and manager in many countries including India, United States, Netherlands and United Kingdom. He is a Microsoft MVP and has developed numerous extensions for Visual Studio, Visual Studio Code and Azure DevOps.
We Are
  • onlyutkarsh
    Utkarsh Shigihalli
    Microsoft MVP, Technologist & DevOps Coach


  • arora_tarun
    Tarun Arora
    Microsoft MVP, Author & DevOps Coach at Avanade

Do you like our posts? Subscribe to our newsletter!
Our Book