Learn how to deploy web resources with Azure DevOps Pipeline

Before we begin, this topic is similar to what Benedikt Bergmann explains in his blog post. But like always, if I do not yet try it by myself = I do not yet fully understand 😀. The twist will be I will create the web resource project using Dataverse DevTools by Danish Naglekar (TypeScript for the win!) and to deploy and publish to the Dev environment, we will use the SparkleXrm by Scott Durow. What we will accomplish in today’s demonstration is in the below image:

Today's demonstration flow diagram

DevOps is dynamic and depends on Organization/people’s perspective on how to run it. For me, the “truth” source to be considered when deploying and publishing customizations for Plugin or WebResources is the code itself (not from the plugin assembly or web resource deployed in the dev environment). Hence, this process is important to make sure the deployment solutions will be in the correct state (during the deployment process, the environment must be locked).

Prepare the project files

First, we need to create a .NET Library project (using .NET Framework 4.6.2 – to make it the same as the Plugin project) > install spkl via NuGet package:

Install spkl NuGet package

For those who don’t know what is Dataverse DevTools and how to set up the project (including creating a sample web resource), you can read my blog post here. Once you setup the project, I generate sample typing and create a TypeScript file like the one below:

Sample Typescript file

The benefit of using Dataverse DevTools is we can publish all the web resources/single web resource conventionally. Once you finish the changes > run “npm run build” > your file will be generated on the WebResources folder (CSS/HTML/scripts) > right click and then you can choose to “Link to Existing Web Resource” (Update) or “Upload & Publish Web Resource” (New):

Deploy your web resource

Once you deploy, the system will automatically create dvdt.linker.xml which we can use to update spkl.json. Based on the information above, I update my spkl.json as follows (you also need to prepare Dataverse Solution for it):

    "webresources": [
        "profile": "default,debug",
        "root": "Webresources/",
        "solution": "DevopsWebResource",
        "files": [
            "uniquename": "dev_Tmy/Contact",
            "file": "scripts/Contact.js",
            "description": ""

Once you have done this, we can focus on the Azure Pipeline.

Azure Pipeline

Here is the final .yml setup:

- master

  vmImage: 'windows-latest'

  - stage: 
    - job: BuildWebResources
      - task: NuGetToolInstaller@1
          checkLatest: true
      - task: NuGetCommand@2
          command: 'restore'
          restoreSolution: '**/*.sln'
          feedsToUse: 'select'
      - task: NodeTool@0
          versionSpec: '19.x'
          displayName: 'Install Node.js'
      - script: |
          npm install
        workingDirectory: Src/Frontend
        displayName: 'npm install'
      - script: |
          npm run build-dev
        workingDirectory: Src/Frontend
        displayName: 'npm build'
      - task: CopyFiles@2
          sourceFolder: 'Src/Frontend/spkl/'
          contents: 'deploy-webresources-devops.bat' 
          targetFolder: $(Build.ArtifactStagingDirectory)
        displayName: 'Copy spkl.bat'  
      - task: CopyFiles@2
          sourceFolder: 'Src/Frontend/'
          contents: 'spkl.json' 
          targetFolder: $(Build.ArtifactStagingDirectory)
        displayName: 'Copy spkl.json' 
      - task: CopyFiles@2
          sourceFolder: 'Src/Frontend/WebResources'
          contents: '**' 
          targetFolder: $(Build.ArtifactStagingDirectory)/Webresources
        displayName: 'Copy Webresources build files' 
      - task: PublishPipelineArtifact@1
          targetPath: '$(Build.ArtifactStagingDirectory)'
          artifactName: DataverseWebResources
        displayName: 'Publish Dataverse artifact'
      - task: BatchScript@1
        displayName: DeployToDataverseDev
          filename: '$(Build.ArtifactStagingDirectory)/deploy-webresources-devops.bat'
          arguments: '"$(DEVCONNECTION)" "$(DEVPASSWORD)"'
          modifyEnvironment: false
          workingFolder: '$(Build.ArtifactStagingDirectory)'

Here is the steps information:

  1. We need to use a Windows machine to do the build.
  2. Install the NuGet tool and restore the solution (this will ensure to download of the spkl files that are needed to run the publish)
  3. Install Node.js (to get the npm packages needed) and then run “npm run build-dev“. This will instruct the system to rebuild all the files in the WebResources folder.
  4. Copy the necessary files (deploy-webresources-devops.bat, spkl.json, and also all the files in the WebResources folder) to the Azure Artifacts.
  5. The last part is just to run the deploy-webresources-devops.bat and we are done 😎

When creating the pipeline, here are the variables that I created:

Pipeline Variables

For the devConnection variable, the format is similar to what Benedikt provided:

Url=https://<your org>.crm4.dynamics.com/;Username=<your Username>;AuthType=Office365;RequireNewInstance=True;Password=

Then for the deploy-webresources-devops.bat is like below:

@echo off
set connection=%~1
set password=%~2
set package_root=..\..\
REM Find the spkl in the package folder (irrespective of version)
For /R %package_root% %%G IN (spkl.exe) do (
	IF EXIST "%%G" (set spkl_path=%%G
	goto :continue)

@echo Using '%spkl_path%' 
REM spkl webresources [path] [connection-string]
"%spkl_path%" webresources ./ "%connection%%password%"

if errorlevel 1 (
echo Error Code=%errorlevel%
exit /b %errorlevel%


Here is the demo if the master branch is updated and the pipeline triggered:

Pipeline result

Happy DevOps-ing!

Other references:


One thought on “Learn how to deploy web resources with Azure DevOps Pipeline

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.