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).
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.
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.
- Checkout the code (
Line #6-7
) - Fetch full history for versioning (
Line #9-10
) - Install GitVersion tool (
Line #12-19
) - Install node (
Line #29-32
) - Install dependencies defined in
pacakge.json
(Line #34-35
) - Use marketplace action to update version in
package.json
(Line #37-44
) - Use a marketplace action to replace version in
CHANGELOG.md
file. (Line #46-51
) - Compile and create the VSIX file. (
Line #53-54
) - I use a custom npm script frompackage.json
file, which internally uses vsce tool by Microsoft. - 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.
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.
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.