diff --git a/package-lock.json b/package-lock.json index 86cd4f68..966b7975 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,7 +5,7 @@ "packages": { "": { "dependencies": { - "@octopusdeploy/api-client": "^3.4.1", + "@octopusdeploy/api-client": "^3.5.1", "azure-devops-node-api": "11.2.0", "azure-pipelines-task-lib": "3.3.1", "azure-pipelines-tool-lib": "1.3.2", @@ -1131,9 +1131,9 @@ } }, "node_modules/@octopusdeploy/api-client": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/@octopusdeploy/api-client/-/api-client-3.4.1.tgz", - "integrity": "sha512-j6FRgDNzc6AQoT3CAguYLWxoMR4W5TKCT1BCPpqjEN9mknmdMSKfYORs3djn/Yj/BhqtITTydDpBoREbzKY5+g==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@octopusdeploy/api-client/-/api-client-3.5.1.tgz", + "integrity": "sha512-JKPx+L1QNjtX1txpj+0+JJR3Q5D/IwKdocih8WTGXGYNYC8jdEDgaTkPb701gD/Jzu14foNn67W4CDDBvyPZeA==", "license": "Apache-2.0", "dependencies": { "adm-zip": "^0.5.9", @@ -7918,9 +7918,9 @@ } }, "@octopusdeploy/api-client": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/@octopusdeploy/api-client/-/api-client-3.4.1.tgz", - "integrity": "sha512-j6FRgDNzc6AQoT3CAguYLWxoMR4W5TKCT1BCPpqjEN9mknmdMSKfYORs3djn/Yj/BhqtITTydDpBoREbzKY5+g==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@octopusdeploy/api-client/-/api-client-3.5.1.tgz", + "integrity": "sha512-JKPx+L1QNjtX1txpj+0+JJR3Q5D/IwKdocih8WTGXGYNYC8jdEDgaTkPb701gD/Jzu14foNn67W4CDDBvyPZeA==", "requires": { "adm-zip": "^0.5.9", "axios": "^1.2.1", diff --git a/package.json b/package.json index eafbb6ab..721a1550 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "yargs": "^17.5.1" }, "dependencies": { - "@octopusdeploy/api-client": "^3.4.1", + "@octopusdeploy/api-client": "^3.5.1", "azure-devops-node-api": "11.2.0", "azure-pipelines-task-lib": "3.3.1", "azure-pipelines-tool-lib": "1.3.2", diff --git a/source/tasks/RunRunbook/RunRunbookV6/inputCommandBuilder.test.ts b/source/tasks/RunRunbook/RunRunbookV6/inputCommandBuilder.test.ts index 75b0d592..aeb6e80f 100644 --- a/source/tasks/RunRunbook/RunRunbookV6/inputCommandBuilder.test.ts +++ b/source/tasks/RunRunbook/RunRunbookV6/inputCommandBuilder.test.ts @@ -1,5 +1,5 @@ import { Logger } from "@octopusdeploy/api-client"; -import { createCommandFromInputs } from "./inputCommandBuilder"; +import { createCommandFromInputs, CreateGitRunbookRunCommandV1, isCreateGitRunbookRunCommand } from "./inputCommandBuilder"; import { MockTaskWrapper } from "../../Utils/MockTaskWrapper"; describe("getInputCommand", () => { @@ -20,6 +20,7 @@ describe("getInputCommand", () => { task.addVariableString("Variables", "var1: value1\nvar2: value2"); const command = createCommandFromInputs(logger, task); + expect(isCreateGitRunbookRunCommand(command)).toBe(false); expect(command.spaceName).toBe("Default"); expect(command.ProjectName).toBe("Awesome project"); expect(command.RunbookName).toBe("A runbook"); @@ -32,4 +33,30 @@ describe("getInputCommand", () => { expect(task.lastResultMessage).toBeUndefined(); expect(task.lastResultDone).toBeUndefined(); }); + + test("when gitRef is supplied, the command contains the ref plus all regular fields supplied", () => { + task.addVariableString("Space", "Default"); + task.addVariableString("Project", "Awesome project"); + task.addVariableString("Runbook", "A runbook"); + task.addVariableString("Environments", "dev\nStaging"); + task.addVariableString("Tenants", "Tenant 1\nTenant 2"); + task.addVariableString("TenantTags", "tag set 1/tag 1\ntag set 1/tag 2"); + task.addVariableString("Variables", "var1: value1\nvar2: value2"); + task.addVariableString("GitRef", "some-ref"); + + const command = createCommandFromInputs(logger, task); + expect(isCreateGitRunbookRunCommand(command)).toBe(true); + expect(command.spaceName).toBe("Default"); + expect(command.ProjectName).toBe("Awesome project"); + expect(command.RunbookName).toBe("A runbook"); + expect(command.EnvironmentNames).toStrictEqual(["dev", "Staging"]); + expect(command.Tenants).toStrictEqual(["Tenant 1", "Tenant 2"]); + expect(command.TenantTags).toStrictEqual(["tag set 1/tag 1", "tag set 1/tag 2"]); + expect(command.Variables).toStrictEqual({ var1: "value1", var2: "value2" }); + expect((command as CreateGitRunbookRunCommandV1).GitRef).toBe("some-ref"); + + expect(task.lastResult).toBeUndefined(); + expect(task.lastResultMessage).toBeUndefined(); + expect(task.lastResultDone).toBeUndefined(); + }); }); diff --git a/source/tasks/RunRunbook/RunRunbookV6/inputCommandBuilder.ts b/source/tasks/RunRunbook/RunRunbookV6/inputCommandBuilder.ts index 7e9b82be..0835d872 100644 --- a/source/tasks/RunRunbook/RunRunbookV6/inputCommandBuilder.ts +++ b/source/tasks/RunRunbook/RunRunbookV6/inputCommandBuilder.ts @@ -1,8 +1,19 @@ import { getLineSeparatedItems } from "../../Utils/inputs"; import { CreateRunbookRunCommandV1, Logger, PromptedVariableValues } from "@octopusdeploy/api-client"; +import { RunGitRunbookCommand } from "@octopusdeploy/api-client/dist/features/projects/runbooks/runs/RunGitRunbookCommand"; import { TaskWrapper } from "tasks/Utils/taskInput"; -export function createCommandFromInputs(logger: Logger, task: TaskWrapper): CreateRunbookRunCommandV1 { +// The api-client doesn't have a type for this command that we can differentiate from CreateRunbookRunCommandV1 +// so we'll wrap it to make things easier. +export type CreateGitRunbookRunCommandV1 = RunGitRunbookCommand & { + GitRef: string; +}; + +export function isCreateGitRunbookRunCommand(command: CreateRunbookRunCommandV1 | CreateGitRunbookRunCommandV1): command is CreateGitRunbookRunCommandV1 { + return (command as CreateGitRunbookRunCommandV1).GitRef !== undefined; +} + +export function createCommandFromInputs(logger: Logger, task: TaskWrapper): CreateRunbookRunCommandV1 | CreateGitRunbookRunCommandV1 { const variablesMap: PromptedVariableValues | undefined = {}; const variablesField = task.getInput("Variables"); @@ -25,6 +36,27 @@ export function createCommandFromInputs(logger: Logger, task: TaskWrapper): Crea logger.debug?.("Tenant Tags: " + tagsField); const tags = getLineSeparatedItems(tagsField || "")?.map((t: string) => t.trim()) || []; + const gitRef = task.getInput("GitRef"); + logger.debug?.("GitRef: " + gitRef); + + if (gitRef) { + const command: CreateGitRunbookRunCommandV1 = { + spaceName: task.getInput("Space") || "", + ProjectName: task.getInput("Project", true) || "", + RunbookName: task.getInput("Runbook", true) || "", + EnvironmentNames: getLineSeparatedItems(environmentsField || "")?.map((t: string) => t.trim()) || [], + Tenants: getLineSeparatedItems(tenantsField || "")?.map((t: string) => t.trim()) || [], + TenantTags: tags, + UseGuidedFailure: task.getBoolean("UseGuidedFailure") || undefined, + Variables: variablesMap || undefined, + GitRef: gitRef, + }; + + logger.debug?.(JSON.stringify(command)); + + return command; + } + const command: CreateRunbookRunCommandV1 = { spaceName: task.getInput("Space") || "", ProjectName: task.getInput("Project", true) || "", diff --git a/source/tasks/RunRunbook/RunRunbookV6/runRunbook.ts b/source/tasks/RunRunbook/RunRunbookV6/runRunbook.ts index a050f7dc..564e4082 100644 --- a/source/tasks/RunRunbook/RunRunbookV6/runRunbook.ts +++ b/source/tasks/RunRunbook/RunRunbookV6/runRunbook.ts @@ -1,14 +1,17 @@ -import { Client, CreateRunbookRunCommandV1, RunbookRunRepository, Logger, TenantRepository, EnvironmentRepository } from "@octopusdeploy/api-client"; +import { Client, CreateRunbookRunCommandV1, RunbookRunRepository, Logger, TenantRepository, EnvironmentRepository, CreateRunbookRunResponseV1 } from "@octopusdeploy/api-client"; import os from "os"; import { TaskWrapper } from "tasks/Utils/taskInput"; import { ExecutionResult } from "../../Utils/executionResult"; +import { CreateGitRunbookRunCommandV1, isCreateGitRunbookRunCommand } from "./inputCommandBuilder"; +import { RunGitRunbookResponse } from "@octopusdeploy/api-client/dist/features/projects/runbooks/runs/RunGitRunbookResponse"; -export async function createRunbookRunFromInputs(client: Client, command: CreateRunbookRunCommandV1, task: TaskWrapper, logger: Logger): Promise { +export async function createRunbookRunFromInputs(client: Client, command: CreateRunbookRunCommandV1 | CreateGitRunbookRunCommandV1, task: TaskWrapper, logger: Logger): Promise { logger.info?.("🐙 Running a Runbook in Octopus Deploy..."); try { const repository = new RunbookRunRepository(client, command.spaceName); - const response = await repository.create(command); + + const response = await createRunbookRun(repository, command); logger.info?.(`🎉 ${response.RunbookRunServerTasks.length} Run${response.RunbookRunServerTasks.length > 1 ? "s" : ""} queued successfully!`); @@ -58,3 +61,10 @@ export async function createRunbookRunFromInputs(client: Client, command: Create throw error; } } + +async function createRunbookRun(repository: RunbookRunRepository, command: CreateRunbookRunCommandV1 | CreateGitRunbookRunCommandV1): Promise { + if (isCreateGitRunbookRunCommand(command)) { + return await repository.createGit(command, command.GitRef); + } + return await repository.create(command); +} diff --git a/source/tasks/RunRunbook/RunRunbookV6/task.json b/source/tasks/RunRunbook/RunRunbookV6/task.json index 52eb55f8..93091225 100644 --- a/source/tasks/RunRunbook/RunRunbookV6/task.json +++ b/source/tasks/RunRunbook/RunRunbookV6/task.json @@ -55,6 +55,14 @@ "required": true, "helpMarkDown": "The environment names to run the runbook for." }, + { + "name": "GitRef", + "type": "string", + "label": "Git Reference", + "defaultValue": "", + "required": false, + "helpMarkDown": "The Git reference to run the runbook for. Only applies when runbooks are stored in a Git repository for config-as-code enabled projects." + }, { "name": "Tenants", "type": "multiLine", diff --git a/source/vsts.md b/source/vsts.md index 4eaaaccb..65444676 100644 --- a/source/vsts.md +++ b/source/vsts.md @@ -273,17 +273,18 @@ From version 6, the deploy release step is split into two seperate functions for #### 📥 Inputs -| Name | Description | -| :------------------------- | :--------------------------------------------------------------------------------------------------------------------------- | -| `OctoConnectedServiceName` | **Required.** Name of the Octopus Server connection. | -| `Space` | **Required.** The Octopus space name the release is in. | -| `Project` | **Required.** The Octopus project name to deploy. | -| `Runbook` | **Required.** Runbook name to run. | -| `Environments` | **Required.** The environment names to run the runbook for. One tenant name per line. | -| `Tenants` | The tenant names to run the runbook for. One tenant name per line. | -| `TenantTags` | Run for all tenants with the given tag(s). One tenant tag per line in the format `tag set name/tag name`. | -| `Variables` | List of prompted variable values, one variable-value pair per line. Each variable should be in format `variable name: value` | -| `UseGuidedFailure` | Whether to use guided failure mode if errors occur during the run. | +| Name | Description | +| :------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------- | +| `OctoConnectedServiceName` | **Required.** Name of the Octopus Server connection. | +| `Space` | **Required.** The Octopus space name the release is in. | +| `Project` | **Required.** The Octopus project name to deploy. | +| `Runbook` | **Required.** Runbook name to run. | +| `Environments` | **Required.** The environment names to run the runbook for. One environment name per line. | +| `GitRef` | The Git reference to run the runbook for e.g. `main`. Only applies when runbooks are stored in a Git repository for config-as-code enabled projects. | +| `Tenants` | The tenant names to run the runbook for. One tenant name per line. | +| `TenantTags` | Run for all tenants with the given tag(s). One tenant tag per line in the format `tag set name/tag name`. | +| `Variables` | List of prompted variable values, one variable-value pair per line. Each variable should be in format `variable name: value` | +| `UseGuidedFailure` | Whether to use guided failure mode if errors occur during the run. | #### 📤 Outputs