refactor: replace requireVariable and requireInput with task-lib equivalents and improve error handling
This commit is contained in:
@@ -1,18 +1,26 @@
|
|||||||
|
import * as tl from 'azure-pipelines-task-lib/task';
|
||||||
import {
|
import {
|
||||||
buildOidcUrl,
|
buildOidcUrl,
|
||||||
exchangeOidcForScopedToken,
|
exchangeOidcForScopedToken,
|
||||||
getServiceConnectionMetadata,
|
getServiceConnectionMetadata,
|
||||||
requestOidcToken
|
requestOidcToken
|
||||||
} from './oidc';
|
} from './oidc';
|
||||||
import { requireVariable } from './devops-helpers';
|
|
||||||
|
|
||||||
export const STORAGE_SCOPE = 'https://storage.azure.com/.default';
|
export const STORAGE_SCOPE = 'https://storage.azure.com/.default';
|
||||||
|
|
||||||
export async function requestStorageAccessToken(
|
export async function requestStorageAccessToken(
|
||||||
endpointId: string
|
endpointId: string
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const oidcBaseUrl = requireVariable('System.OidcRequestUri');
|
const oidcBaseUrl = tl.getVariable('System.OidcRequestUri');
|
||||||
const systemAccessToken = requireVariable('System.AccessToken');
|
const systemAccessToken = tl.getVariable('System.AccessToken');
|
||||||
|
|
||||||
|
if (oidcBaseUrl === undefined) {
|
||||||
|
throw new Error('Missing required pipeline variable: System.OidcRequestUri.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (systemAccessToken === undefined) {
|
||||||
|
throw new Error('Missing required pipeline variable: System.AccessToken.');
|
||||||
|
}
|
||||||
|
|
||||||
const metadata = getServiceConnectionMetadata(endpointId);
|
const metadata = getServiceConnectionMetadata(endpointId);
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
type TaskLibBridge = {
|
|
||||||
getInput: (name: string, required?: boolean) => string | undefined;
|
|
||||||
getVariable: (name: string) => string | undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
function getTaskLibBridge(): TaskLibBridge {
|
|
||||||
return require('azure-pipelines-task-lib/task') as TaskLibBridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function requireInput(name: string): string {
|
|
||||||
const taskLib = getTaskLibBridge();
|
|
||||||
const value = taskLib.getInput(name, true);
|
|
||||||
if (!value) {
|
|
||||||
throw new Error(`Task input ${name} is required.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return value.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function requireVariable(name: string): string {
|
|
||||||
const taskLib = getTaskLibBridge();
|
|
||||||
const value = taskLib.getVariable(name);
|
|
||||||
if (!value) {
|
|
||||||
throw new Error(`Missing required pipeline variable: ${name}.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return value.trim();
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,2 @@
|
|||||||
export * from './devops-helpers';
|
|
||||||
export * from './oidc';
|
export * from './oidc';
|
||||||
export * from './blob';
|
export * from './blob';
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import * as tl from 'azure-pipelines-task-lib/task';
|
||||||
|
|
||||||
export type ServiceConnectionMetadata = {
|
export type ServiceConnectionMetadata = {
|
||||||
tenantId: string;
|
tenantId: string;
|
||||||
clientId: string;
|
clientId: string;
|
||||||
@@ -11,40 +13,25 @@ export type TokenResponse = {
|
|||||||
|
|
||||||
export const CLIENT_ASSERTION_TYPE = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer';
|
export const CLIENT_ASSERTION_TYPE = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer';
|
||||||
|
|
||||||
type TaskLibEndpointBridge = {
|
|
||||||
getEndpointAuthorizationParameter: (
|
|
||||||
endpointId: string,
|
|
||||||
key: string,
|
|
||||||
optional: boolean
|
|
||||||
) => string | undefined;
|
|
||||||
getEndpointDataParameter: (endpointId: string, key: string, optional: boolean) => string | undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
type OidcResponse = {
|
type OidcResponse = {
|
||||||
oidcToken?: string;
|
oidcToken?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
function getTaskLibEndpointBridge(): TaskLibEndpointBridge {
|
|
||||||
return require('azure-pipelines-task-lib/task') as TaskLibEndpointBridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getServiceConnectionMetadata(endpointId: string): ServiceConnectionMetadata {
|
export function getServiceConnectionMetadata(endpointId: string): ServiceConnectionMetadata {
|
||||||
const taskLib = getTaskLibEndpointBridge();
|
|
||||||
|
|
||||||
const tenantId =
|
const tenantId =
|
||||||
taskLib.getEndpointAuthorizationParameter(endpointId, 'tenantid', true) ||
|
tl.getEndpointAuthorizationParameter(endpointId, 'tenantid', true) ||
|
||||||
taskLib.getEndpointDataParameter(endpointId, 'tenantid', true);
|
tl.getEndpointDataParameter(endpointId, 'tenantid', true);
|
||||||
|
|
||||||
const clientId =
|
const clientId =
|
||||||
taskLib.getEndpointAuthorizationParameter(endpointId, 'serviceprincipalid', true) ||
|
tl.getEndpointAuthorizationParameter(endpointId, 'serviceprincipalid', true) ||
|
||||||
taskLib.getEndpointAuthorizationParameter(endpointId, 'clientid', true) ||
|
tl.getEndpointAuthorizationParameter(endpointId, 'clientid', true) ||
|
||||||
taskLib.getEndpointDataParameter(endpointId, 'serviceprincipalid', true);
|
tl.getEndpointDataParameter(endpointId, 'serviceprincipalid', true);
|
||||||
|
|
||||||
if (!tenantId) {
|
if (tenantId === undefined) {
|
||||||
throw new Error('Could not resolve tenant ID from the selected AzureRM service connection.');
|
throw new Error('Could not resolve tenant ID from the selected AzureRM service connection.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!clientId) {
|
if (clientId === undefined) {
|
||||||
throw new Error('Could not resolve client ID from the selected AzureRM service connection.');
|
throw new Error('Could not resolve client ID from the selected AzureRM service connection.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,21 +4,27 @@ import {
|
|||||||
buildOidcUrl,
|
buildOidcUrl,
|
||||||
exchangeOidcForScopedToken,
|
exchangeOidcForScopedToken,
|
||||||
getServiceConnectionMetadata,
|
getServiceConnectionMetadata,
|
||||||
requestOidcToken,
|
requestOidcToken
|
||||||
requireInput,
|
|
||||||
requireVariable
|
|
||||||
} from '@skoszewski/ado-sk-toolkit-shared';
|
} from '@skoszewski/ado-sk-toolkit-shared';
|
||||||
|
|
||||||
const AZDO_APP_SCOPE = '499b84ac-1321-427f-aa17-267ca6975798/.default';
|
const AZDO_APP_SCOPE = '499b84ac-1321-427f-aa17-267ca6975798/.default';
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const endpointId = requireInput('serviceConnectionARM');
|
const endpointId = tl.getInputRequired('serviceConnectionARM');
|
||||||
const setGitAccessToken = tl.getBoolInput('setGitAccessToken', false);
|
const setGitAccessToken = tl.getBoolInput('setGitAccessToken', false);
|
||||||
const printTokenHashes = tl.getBoolInput('printTokenHashes', false);
|
const printTokenHashes = tl.getBoolInput('printTokenHashes', false);
|
||||||
|
|
||||||
const oidcBaseUrl = requireVariable('System.OidcRequestUri');
|
const oidcBaseUrl = tl.getVariable('System.OidcRequestUri');
|
||||||
const accessToken = requireVariable('System.AccessToken');
|
const accessToken = tl.getVariable('System.AccessToken');
|
||||||
|
|
||||||
|
if (oidcBaseUrl === undefined) {
|
||||||
|
throw new Error('Missing required pipeline variable: System.OidcRequestUri.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accessToken === undefined) {
|
||||||
|
throw new Error('Missing required pipeline variable: System.AccessToken.');
|
||||||
|
}
|
||||||
|
|
||||||
console.log('Requesting OIDC token for ARM authentication...');
|
console.log('Requesting OIDC token for ARM authentication...');
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import * as tl from 'azure-pipelines-task-lib/task';
|
import * as tl from 'azure-pipelines-task-lib/task';
|
||||||
import {
|
import {
|
||||||
buildBlobUrl,
|
buildBlobUrl,
|
||||||
requestStorageAccessToken,
|
requestStorageAccessToken
|
||||||
requireInput
|
|
||||||
} from '@skoszewski/ado-sk-toolkit-shared';
|
} from '@skoszewski/ado-sk-toolkit-shared';
|
||||||
|
|
||||||
async function copyBlob(
|
async function copyBlob(
|
||||||
@@ -38,12 +37,12 @@ async function copyBlob(
|
|||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const endpointId = requireInput('serviceConnectionARM');
|
const endpointId = tl.getInputRequired('serviceConnectionARM');
|
||||||
const srcStorageAccountName = requireInput('srcStorageAccountName');
|
const srcStorageAccountName = tl.getInputRequired('srcStorageAccountName');
|
||||||
const dstStorageAccountName = requireInput('dstStorageAccountName');
|
const dstStorageAccountName = tl.getInputRequired('dstStorageAccountName');
|
||||||
const srcContainerName = requireInput('srcContainerName');
|
const srcContainerName = tl.getInputRequired('srcContainerName');
|
||||||
const dstContainerNameInput = tl.getInput('dstContainerName', false)?.trim() || '';
|
const dstContainerNameInput = tl.getInput('dstContainerName', false) || '';
|
||||||
const blobName = requireInput('blobName');
|
const blobName = tl.getInputRequired('blobName');
|
||||||
|
|
||||||
console.log('Requesting storage access token from Microsoft Entra ID...');
|
console.log('Requesting storage access token from Microsoft Entra ID...');
|
||||||
const accessToken = await requestStorageAccessToken(endpointId);
|
const accessToken = await requestStorageAccessToken(endpointId);
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ import * as path from 'node:path';
|
|||||||
import * as tl from 'azure-pipelines-task-lib/task';
|
import * as tl from 'azure-pipelines-task-lib/task';
|
||||||
import {
|
import {
|
||||||
buildBlobUrl,
|
buildBlobUrl,
|
||||||
requestStorageAccessToken,
|
requestStorageAccessToken
|
||||||
requireInput
|
|
||||||
} from '@skoszewski/ado-sk-toolkit-shared';
|
} from '@skoszewski/ado-sk-toolkit-shared';
|
||||||
|
|
||||||
async function downloadBlob(blobUrl: string, bearerToken: string): Promise<Buffer> {
|
async function downloadBlob(blobUrl: string, bearerToken: string): Promise<Buffer> {
|
||||||
@@ -28,11 +27,11 @@ async function downloadBlob(blobUrl: string, bearerToken: string): Promise<Buffe
|
|||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const endpointId = requireInput('serviceConnectionARM');
|
const endpointId = tl.getInputRequired('serviceConnectionARM');
|
||||||
const storageAccountName = requireInput('storageAccountName');
|
const storageAccountName = tl.getInputRequired('storageAccountName');
|
||||||
const containerName = requireInput('containerName');
|
const containerName = tl.getInputRequired('containerName');
|
||||||
const blobName = requireInput('blobName');
|
const blobName = tl.getInputRequired('blobName');
|
||||||
const destinationPath = requireInput('destinationPath');
|
const destinationPath = tl.getInputRequired('destinationPath');
|
||||||
|
|
||||||
console.log('Requesting storage access token from Microsoft Entra ID...');
|
console.log('Requesting storage access token from Microsoft Entra ID...');
|
||||||
const accessToken = await requestStorageAccessToken(endpointId);
|
const accessToken = await requestStorageAccessToken(endpointId);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import * as tl from 'azure-pipelines-task-lib/task';
|
import * as tl from 'azure-pipelines-task-lib/task';
|
||||||
import {
|
import {
|
||||||
requestStorageAccessToken,
|
requestStorageAccessToken
|
||||||
requireInput
|
|
||||||
} from '@skoszewski/ado-sk-toolkit-shared';
|
} from '@skoszewski/ado-sk-toolkit-shared';
|
||||||
|
|
||||||
function decodeXmlValue(value: string): string {
|
function decodeXmlValue(value: string): string {
|
||||||
@@ -60,11 +59,11 @@ async function listBlobs(listUrl: string, bearerToken: string): Promise<string[]
|
|||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const endpointId = requireInput('serviceConnectionARM');
|
const endpointId = tl.getInputRequired('serviceConnectionARM');
|
||||||
const storageAccountName = requireInput('storageAccountName');
|
const storageAccountName = tl.getInputRequired('storageAccountName');
|
||||||
const containerName = requireInput('containerName');
|
const containerName = tl.getInputRequired('containerName');
|
||||||
const prefix = tl.getInput('prefix', false)?.trim() || '';
|
const prefix = tl.getInput('prefix', false) || '';
|
||||||
const maxResultsRaw = tl.getInput('maxResults', false)?.trim() || '1000';
|
const maxResultsRaw = tl.getInput('maxResults', false) || '1000';
|
||||||
const maxResults = Number.parseInt(maxResultsRaw, 10);
|
const maxResults = Number.parseInt(maxResultsRaw, 10);
|
||||||
|
|
||||||
if (!Number.isInteger(maxResults) || maxResults <= 0) {
|
if (!Number.isInteger(maxResults) || maxResults <= 0) {
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ import * as fs from 'node:fs/promises';
|
|||||||
import * as tl from 'azure-pipelines-task-lib/task';
|
import * as tl from 'azure-pipelines-task-lib/task';
|
||||||
import {
|
import {
|
||||||
buildBlobUrl,
|
buildBlobUrl,
|
||||||
requestStorageAccessToken,
|
requestStorageAccessToken
|
||||||
requireInput
|
|
||||||
} from '@skoszewski/ado-sk-toolkit-shared';
|
} from '@skoszewski/ado-sk-toolkit-shared';
|
||||||
|
|
||||||
async function uploadBlob(
|
async function uploadBlob(
|
||||||
@@ -35,12 +34,12 @@ async function uploadBlob(
|
|||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const endpointId = requireInput('serviceConnectionARM');
|
const endpointId = tl.getInputRequired('serviceConnectionARM');
|
||||||
const storageAccountName = requireInput('storageAccountName');
|
const storageAccountName = tl.getInputRequired('storageAccountName');
|
||||||
const containerName = requireInput('containerName');
|
const containerName = tl.getInputRequired('containerName');
|
||||||
const blobName = requireInput('blobName');
|
const blobName = tl.getInputRequired('blobName');
|
||||||
const sourcePath = requireInput('sourcePath');
|
const sourcePath = tl.getInputRequired('sourcePath');
|
||||||
const contentType = tl.getInput('contentType', false)?.trim() || 'application/octet-stream';
|
const contentType = tl.getInput('contentType', false) || 'application/octet-stream';
|
||||||
|
|
||||||
console.log('Requesting storage access token from Microsoft Entra ID...');
|
console.log('Requesting storage access token from Microsoft Entra ID...');
|
||||||
const accessToken = await requestStorageAccessToken(endpointId);
|
const accessToken = await requestStorageAccessToken(endpointId);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"manifestVersion": 1,
|
"manifestVersion": 1,
|
||||||
"id": "sk-azure-devops-toolkit",
|
"id": "sk-azure-devops-toolkit",
|
||||||
"name": "SK Azure DevOps Toolkit",
|
"name": "SK Azure DevOps Toolkit",
|
||||||
"version": "1.0.5",
|
"version": "1.1.0",
|
||||||
"publisher": "skoszewski-lab",
|
"publisher": "skoszewski-lab",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user