bryanbcook
bryanbcook

Reputation: 18328

Include multiple versions of an azure devops custom task without duplicating source code

I am developing a custom Azure DevOps extension that contains a custom pipeline task written in TypeScript. The source code when compiled produces JavaScript files in place next to their TypeScript equivalents.

The folder structure looks like:

 /docs
   /img
     icon.png
 /MyTaskNameV1
   /node_modules
   index.ts
   index.js

My vss-extension.json includes the source folder and the contribution name:

{
  // snip
  "files": [
    {
      "path": "MyTaskNameV1"
    },
    {
      "path": "docs/img",
      "addressable": "true"
    }
  ],
  "contributions": [
    {
      "id": "mytaskname",
      "type": "ms.vss-distributed-task.task",
      "targets": [
        "ms.vss-distributed-task.tasks"
      ],
      "properties": {
        "name": "MyTaskNameV1"
      }
    }
  ]
}

My task.json includes the version and execution entrypoint:

{
    "$schema": "https://raw.githubusercontent.com/Microsoft/azure-pipelines-task-lib/master/tasks.schema.json",
    "id": "...",
    "name": "MyTaskName",
   
    "version": {
        "Major": 1,
        "Minor": 0,
        "Patch": 0
    },
    
    // snip
    "execution": {
        "Node16": {
            "target": "index.js",
            "argumentFormat": ""
        }
    }
}

I'd like to include a second version of the Task that includes newer input options in the task.json but I don't want to duplicate the source or increase the size of the extension. Ideally, I'd want one copy of the source code but use conditional logic in the task to activate newer features based on the version.

Something like:

import tl = require("azure-pipelines-task-lib/task");

async function run() {

    // get version of the task
    let version = ?

    if (version == 1) {
      // get v1 task inputs
    } else  {
      // get additional v2 inputs
    }

}

run();

My current tsconfig.json looks like this:

{
  "compilerOptions": {
    /* Language and Environment */
    "target": "es2022",    /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */

    /* Modules */
    "module": "commonjs",  /* Specify what module code is generated. */

    /* Emit */
    "sourceMap": true,     /* Create source map files for emitted JavaScript files. */
    // "outFile": "./",    /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
    // "outDir": "./",     /* Specify an output folder for all emitted files. */

    /* Type Checking */
    "strict": true,        /* Enable all strict type-checking options. */

    /* Completeness */
    "skipLibCheck": true   /* Skip type checking all .d.ts files. */
  }
}

My question is in two parts:

  1. How can my task determine which version of the task is running? Are there additional properties that I can pass in the contribution that I can discover at runtime? Is there a runtime variable that would contain my task's version?
  2. What changes do I need to introduce so that I can have two task.json files?

Upvotes: 0

Views: 57

Answers (1)

Bright Ran-MSFT
Bright Ran-MSFT

Reputation: 13944

I'm afraid that you demand is not possible to satisfy.

When you want to release a new version of the extension (or the pipeline tasks contained in the extension) with some updates, it is recommended:

  1. Create a git tag for the new version in the source code repository. The tag name can be defined as the new version number.

  2. Build and package the new version extension from the git tag.

  3. Publish the new version extension to Marketplace.

If you had published multiple versions of the pipeline tasks to Marketplace, you should be able to switch between these versions when using and editing the tasks in your pipelines.


EDIT:

Normally, one extension version should contain one version of each task. It is not recommended to contain multiple versions of the same task into one extension version.

When you make any updates on code of a task, you should increase a new version of the task, and also a new version of the extension. Each task can have different version number than others and the extension. Then build and publish the new extension version which contains the new task version.

For example: There is an extension with version 1.0.3, and it contains two tasks:

  • Task1 with version 1.0.2, one task.json file and some other code files for it.
  • Task2 with version 1.0.1, one task.json file and some other code files for it.

Assume you make some minor (or patch) updates on Task1 and increase a new minor (or patch) version for it (e.g., 1.0.3), you also should increase a new minor (or patch) version for the extension (e.g., 1.0.4). At this time, the new extension version should contain:

  • Task1: one task.json file with version 1.0.3 defined, and some other code files for it.
  • Task2: one task.json file with version 1.0.1 defined, and some other code files for it.

Build and publish the new extension version, then install/upgrade the published new extension version into your Azure DevOps organization. After that, the pipelines in your organization can use [email protected] and [email protected].

If you make some major updates on the tasks and the whole extension, normally, you will increase the major version of each task and the extension. For example, make major updates to increase the versions of both Task1 and Task2 from version 1 (1.xx) to version 2 (2.xx), and also increase version of extension to 2.xx. At this time, the new extension version should contain:

  • Task1: one task.json file with a detailed number of version 2 (2.xx) defined, and some other code files for it.
  • Task2: one task.json file with a detailed number of version 2 (2.xx) defined, and some other code files for it.

Build and publish the new extension version, then install/upgrade the published new extension version into your Azure DevOps organization. After that, the pipelines in your organization can use both version 1 and version 2 of Task1 and Task2. That means you can switch between @1 and @2 versions of the two tasks in your pipelines.

Upvotes: 1

Related Questions