Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b6ed484

Browse files
committedOct 31, 2024··
initial working solution with sync-fetch
1 parent 7c42d41 commit b6ed484

File tree

4 files changed

+287
-109
lines changed

4 files changed

+287
-109
lines changed
 

‎buildScripts/publish-extension.sh

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/usr/bin/env bash
2+
set -eu
3+
rm -f *.vsix
4+
5+
PUBLISHER="winslowtech"
6+
ORGANIZATION="winslowtech"
7+
EXTENSION_ID="novo-artifactory-setup"
8+
EXTENSION_NAME="Novo Artifactory Setup"
9+
10+
OVERRIDE_JSON=$(
11+
cat <<EOF
12+
{
13+
"id": "$EXTENSION_ID",
14+
"name": "$EXTENSION_NAME",
15+
"public": false,
16+
"description": "work in progress"
17+
}
18+
EOF
19+
)
20+
21+
# Unshare and unpublish the extension if it exists (ignore errors if it doesn't)
22+
tfx extension unshare -t "$WINSLOWTECH_TOKEN" --extension-id $EXTENSION_ID --publisher "$PUBLISHER" --unshare-with "$ORGANIZATION" 2>/dev/null || true
23+
tfx extension unpublish -t "$WINSLOWTECH_TOKEN" --extension-id $EXTENSION_ID --publisher "$PUBLISHER" || true
24+
25+
# Create the VSIX package
26+
tfx extension create --manifests vss-extension.json --publisher "$PUBLISHER" --rev-version --override $OVERRIDE_JSON
27+
28+
vsixSize=$(du -k *.vsix | awk '{sum+=$1} END {print int(sum/1024)}')
29+
echo "Extension VSIX size is ${vsixSize}MB"
30+
31+
# Publish the extension
32+
tfx extension publish -t "$WINSLOWTECH_TOKEN" \
33+
--publisher "$PUBLISHER" \
34+
--manifests vss-extension.json \
35+
--share-with "$ORGANIZATION" \
36+
--override $OVERRIDE_JSON
37+
38+
# Install the extension to your organization
39+
tfx extension install \
40+
--publisher "$PUBLISHER" \
41+
--extension-id $EXTENSION_ID \
42+
--service-url "https://${PUBLISHER}.visualstudio.com" \
43+
-t "$WINSLOWTECH_TOKEN"
44+
45+
rm *.vsix

‎jfrog-tasks-utils/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
"typings": "utils.d.ts",
1010
"dependencies": {
1111
"azure-pipelines-task-lib": "4.5.0",
12-
"azure-pipelines-tool-lib": "2.0.6",
1312
"azure-pipelines-tasks-java-common": "^2.219.1",
13+
"azure-pipelines-tool-lib": "2.0.6",
14+
"sync-fetch": "^0.5.2",
1415
"typed-rest-client": "^1.8.11"
1516
},
1617
"scripts": {

‎jfrog-tasks-utils/utils.js

+84-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ const execSync = require('child_process').execSync;
55
const toolLib = require('azure-pipelines-tool-lib/tool');
66
const credentialsHandler = require('typed-rest-client/Handlers');
77
const findJavaHome = require('azure-pipelines-tasks-java-common/java-common').findJavaHome;
8-
98
const fileName = getCliExecutableName();
109
const jfrogCliToolName = 'jf';
1110
const cliPackage = 'jfrog-cli-' + getArchitecture();
@@ -19,6 +18,7 @@ const buildAgent = 'jfrog-azure-devops-extension';
1918
const customFolderPath = encodePath(join(jfrogFolderPath, 'current'));
2019
const customCliPath = encodePath(join(customFolderPath, fileName)); // Optional - Customized jfrog-cli path.
2120
const jfrogCliReleasesUrl = 'https://releases.jfrog.io/artifactory/jfrog-cli/v2-jf';
21+
const syncFetch = require('sync-fetch');
2222

2323
// Set by Tools Installer Task. This JFrog CLI version will be used in all tasks unless manual installation is used,
2424
// or a specific version was requested in a task. If not set, use the default CLI version.
@@ -160,6 +160,13 @@ function createAuthHandlers(serviceConnection) {
160160
let artifactoryUser = tl.getEndpointAuthorizationParameter(serviceConnection, 'username', true);
161161
let artifactoryPassword = tl.getEndpointAuthorizationParameter(serviceConnection, 'password', true);
162162
let artifactoryAccessToken = tl.getEndpointAuthorizationParameter(serviceConnection, 'apitoken', true);
163+
let oidcProviderName = tl.getEndpointAuthorizationParameter(service, 'oidcProviderName', true);
164+
let jfrogPlatformUrl = tl.getEndpointAuthorizationParameter(service, 'jfrogPlatformUrl', true);
165+
166+
if (oidcProviderName) {
167+
const adoJWT = getADOJWT(serviceConnection);
168+
serviceAccessToken = getArtifactoryAccessToken(adoJWT, oidcProviderName, jfrogPlatformUrl);
169+
}
163170

164171
// Check if Artifactory should be accessed using access-token.
165172
if (artifactoryAccessToken) {
@@ -252,15 +259,91 @@ function configureDistributionCliServer(distributionService, serverId, cliPath,
252259
function configureXrayCliServer(xrayService, serverId, cliPath, buildDir) {
253260
return configureSpecificCliServer(xrayService, '--xray-url', serverId, cliPath, buildDir);
254261
}
262+
function logIDToken(oidcToken) {
263+
const oidcClaims = JSON.parse(Buffer.from(oidcToken.split('.')[1], 'base64').toString());
264+
console.log('OIDC Token Subject: ', oidcClaims.sub);
265+
console.log(`OIDC Token Claims: {"sub": "${oidcClaims.sub}"}`);
266+
console.log('OIDC Token Issuer (Provider URL): ', oidcClaims.iss);
267+
console.log('OIDC Token Audience: ', oidcClaims.aud);
268+
}
269+
270+
function getADOJWT(serviceConnectionID) {
271+
const uri = getValue('System.CollectionUri');
272+
const teamPrjID = getValue('System.TeamProjectId');
273+
const hub = getValue('System.HostType');
274+
const planID = getValue('System.PlanId');
275+
const jobID = getValue('System.JobId');
276+
277+
const url = `${uri}${teamPrjID}/_apis/distributedtask/hubs/${hub}/plans/${planID}/jobs/${jobID}/oidctoken?api-version=7.1-preview.1&serviceConnectionId=${serviceConnectionID}`;
278+
279+
try {
280+
const response = syncFetch(url, {
281+
method: 'POST',
282+
headers: {
283+
'Content-Type': 'application/json',
284+
Authorization: `Bearer ${getValue('System.AccessToken')}`,
285+
},
286+
});
287+
288+
jfrogAccessToken = response.json().oidcToken;
289+
logIDToken(jfrogAccessToken);
290+
return jfrogAccessToken;
291+
} catch (error) {
292+
throw new Error(`Failed to get or parse response: ${error.message}`);
293+
}
294+
}
295+
296+
function getArtifactoryAccessToken(adoJWT, oidcProviderName, jfrogPlatformUrl) {
297+
const payload = {
298+
grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',
299+
subject_token_type: 'urn:ietf:params:oauth:token-type:id_token',
300+
subject_token: adoJWT,
301+
provider_name: oidcProviderName,
302+
};
303+
304+
const url = `${jfrogPlatformUrl}/access/api/v1/oidc/token`;
305+
306+
try {
307+
const res = syncFetch(url, {
308+
method: 'POST',
309+
body: JSON.stringify(payload),
310+
headers: { 'Content-Type': 'application/json' },
311+
});
312+
313+
if (!res.ok) {
314+
throw new Error(`Failed to get the Artifactory access token: ${res.statusText}`);
315+
}
316+
return res.json().access_token;
317+
} catch (err) {
318+
throw new Error(`Failed to get or parse response: ${err.message}`);
319+
}
320+
}
321+
322+
function getValue(key) {
323+
const variable = tl.getVariable(key);
324+
if (!variable) {
325+
throw new Error(`Required variable '${key}' returned undefined!`);
326+
}
327+
328+
return variable;
329+
}
255330

256331
function configureSpecificCliServer(service, urlFlag, serverId, cliPath, buildDir) {
257332
let serviceUrl = tl.getEndpointUrl(service, false);
258333
let serviceUser = tl.getEndpointAuthorizationParameter(service, 'username', true);
259334
let servicePassword = tl.getEndpointAuthorizationParameter(service, 'password', true);
260335
let serviceAccessToken = tl.getEndpointAuthorizationParameter(service, 'apitoken', true);
336+
let oidcProviderName = tl.getEndpointAuthorizationParameter(service, 'oidcProviderName', true);
337+
let jfrogPlatformUrl = tl.getEndpointAuthorizationParameter(service, 'jfrogPlatformUrl', true);
261338
let cliCommand = cliJoin(cliPath, jfrogCliConfigAddCommand, quote(serverId), urlFlag + '=' + quote(serviceUrl), '--interactive=false');
262339
let stdinSecret;
263340
let secretInStdinSupported = isStdinSecretSupported();
341+
342+
if (oidcProviderName) {
343+
const adoJWT = getADOJWT(service);
344+
serviceAccessToken = getArtifactoryAccessToken(adoJWT, oidcProviderName, jfrogPlatformUrl);
345+
}
346+
264347
if (serviceAccessToken) {
265348
// Add access-token if required.
266349
cliCommand = cliJoin(cliCommand, secretInStdinSupported ? '--access-token-stdin' : '--access-token=' + quote(serviceAccessToken));

‎vss-extension.json

+156-107
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"manifestVersion": 1,
33
"public": true,
44
"id": "jfrog-azure-devops-extension",
5-
"version": "2.10.1",
5+
"version": "2.10.4",
66
"name": "JFrog",
77
"description": "Integrate your JFrog Platform with Visual Studio Team Services.",
88
"publisher": "JFrog",
@@ -14,26 +14,9 @@
1414
"icons": {
1515
"default": "images/jfrog-logo-200.png"
1616
},
17-
"scopes": [
18-
"vso.build",
19-
"vso.build_execute"
20-
],
21-
"categories": [
22-
"Azure Pipelines"
23-
],
24-
"tags": [
25-
"JFrog",
26-
"Artifactory",
27-
"Distribution",
28-
"Xray",
29-
"Artifact",
30-
"Build",
31-
"Release",
32-
"Promote",
33-
"Upload",
34-
"Download",
35-
"Repository"
36-
],
17+
"scopes": ["vso.build", "vso.build_execute"],
18+
"categories": ["Azure Pipelines"],
19+
"tags": ["JFrog", "Artifactory", "Distribution", "Xray", "Artifact", "Build", "Release", "Promote", "Upload", "Download", "Repository"],
3720
"content": {
3821
"details": {
3922
"path": "overview.md"
@@ -72,9 +55,7 @@
7255
"id": "jfrog-platform-service",
7356
"description": "Service Endpoint type for JFrog Platform connections. Currently only used by the 'JFrog CLI V2' task.",
7457
"type": "ms.vss-endpoint.service-endpoint-type",
75-
"targets": [
76-
"ms.vss-endpoint.endpoint-types"
77-
],
58+
"targets": ["ms.vss-endpoint.endpoint-types"],
7859
"properties": {
7960
"name": "jfrogPlatformService",
8061
"displayName": "JFrog Platform V2",
@@ -149,6 +130,37 @@
149130
}
150131
}
151132
]
133+
},
134+
{
135+
"type": "ms.vss-endpoint.endpoint-auth-scheme-none",
136+
"displayName": "Azure DevOps OIDC (Services only)",
137+
"properties": {
138+
"isVerifiable": "False"
139+
},
140+
"inputDescriptors": [
141+
{
142+
"id": "oidcProviderName",
143+
"name": "OIDC Provider Name",
144+
"description": "The OIDC \"Provider Name\" configured in JFrog Platform.",
145+
"inputMode": "textbox",
146+
"isConfidential": false,
147+
"validation": {
148+
"isRequired": true,
149+
"dataType": "string"
150+
}
151+
},
152+
{
153+
"id": "jfrogPlatformUrl",
154+
"name": "Platform URL",
155+
"description": "The access token will be obtained from this URL (e.g. https://my.jfrog.com)",
156+
"inputMode": "textbox",
157+
"isConfidential": false,
158+
"validation": {
159+
"isRequired": true,
160+
"dataType": "string"
161+
}
162+
}
163+
]
152164
}
153165
]
154166
}
@@ -157,9 +169,7 @@
157169
"id": "jfrog-artifactory-service",
158170
"description": "Service Endpoint type for Artifactory connections",
159171
"type": "ms.vss-endpoint.service-endpoint-type",
160-
"targets": [
161-
"ms.vss-endpoint.endpoint-types"
162-
],
172+
"targets": ["ms.vss-endpoint.endpoint-types"],
163173
"properties": {
164174
"name": "jfrogArtifactoryService",
165175
"displayName": "JFrog Artifactory V2",
@@ -234,6 +244,37 @@
234244
}
235245
}
236246
]
247+
},
248+
{
249+
"type": "ms.vss-endpoint.endpoint-auth-scheme-none",
250+
"displayName": "Azure DevOps OIDC (Services only)",
251+
"properties": {
252+
"isVerifiable": "False"
253+
},
254+
"inputDescriptors": [
255+
{
256+
"id": "oidcProviderName",
257+
"name": "OIDC Provider Name",
258+
"description": "The OIDC \"Provider Name\" configured in JFrog Platform.",
259+
"inputMode": "textbox",
260+
"isConfidential": false,
261+
"validation": {
262+
"isRequired": true,
263+
"dataType": "string"
264+
}
265+
},
266+
{
267+
"id": "jfrogPlatformUrl",
268+
"name": "Platform URL",
269+
"description": "The access token will be obtained from this URL (e.g. https://my.jfrog.com)",
270+
"inputMode": "textbox",
271+
"isConfidential": false,
272+
"validation": {
273+
"isRequired": true,
274+
"dataType": "string"
275+
}
276+
}
277+
]
237278
}
238279
]
239280
}
@@ -242,9 +283,7 @@
242283
"id": "jfrog-distribution-service",
243284
"description": "Service Endpoint type for Distribution connections",
244285
"type": "ms.vss-endpoint.service-endpoint-type",
245-
"targets": [
246-
"ms.vss-endpoint.endpoint-types"
247-
],
286+
"targets": ["ms.vss-endpoint.endpoint-types"],
248287
"properties": {
249288
"name": "jfrogDistributionService",
250289
"displayName": "JFrog Distribution V2",
@@ -309,6 +348,37 @@
309348
}
310349
}
311350
]
351+
},
352+
{
353+
"type": "ms.vss-endpoint.endpoint-auth-scheme-none",
354+
"displayName": "Azure DevOps OIDC (Services only)",
355+
"properties": {
356+
"isVerifiable": "False"
357+
},
358+
"inputDescriptors": [
359+
{
360+
"id": "oidcProviderName",
361+
"name": "OIDC Provider Name",
362+
"description": "The OIDC \"Provider Name\" configured in JFrog Platform.",
363+
"inputMode": "textbox",
364+
"isConfidential": false,
365+
"validation": {
366+
"isRequired": true,
367+
"dataType": "string"
368+
}
369+
},
370+
{
371+
"id": "jfrogPlatformUrl",
372+
"name": "Platform URL",
373+
"description": "The access token will be obtained from this URL (e.g. https://my.jfrog.com)",
374+
"inputMode": "textbox",
375+
"isConfidential": false,
376+
"validation": {
377+
"isRequired": true,
378+
"dataType": "string"
379+
}
380+
}
381+
]
312382
}
313383
]
314384
}
@@ -317,9 +387,7 @@
317387
"id": "jfrog-xray-service",
318388
"description": "Service Endpoint type for Xray connections",
319389
"type": "ms.vss-endpoint.service-endpoint-type",
320-
"targets": [
321-
"ms.vss-endpoint.endpoint-types"
322-
],
390+
"targets": ["ms.vss-endpoint.endpoint-types"],
323391
"properties": {
324392
"name": "jfrogXrayService",
325393
"displayName": "JFrog Xray V2",
@@ -384,6 +452,37 @@
384452
}
385453
}
386454
]
455+
},
456+
{
457+
"type": "ms.vss-endpoint.endpoint-auth-scheme-none",
458+
"displayName": "Azure DevOps OIDC (Services only)",
459+
"properties": {
460+
"isVerifiable": "False"
461+
},
462+
"inputDescriptors": [
463+
{
464+
"id": "oidcProviderName",
465+
"name": "OIDC Provider Name",
466+
"description": "The OIDC \"Provider Name\" configured in JFrog Platform.",
467+
"inputMode": "textbox",
468+
"isConfidential": false,
469+
"validation": {
470+
"isRequired": true,
471+
"dataType": "string"
472+
}
473+
},
474+
{
475+
"id": "jfrogPlatformUrl",
476+
"name": "Platform URL",
477+
"description": "The access token will be obtained from this URL (e.g. https://my.jfrog.com)",
478+
"inputMode": "textbox",
479+
"isConfidential": false,
480+
"validation": {
481+
"isRequired": true,
482+
"dataType": "string"
483+
}
484+
}
485+
]
387486
}
388487
]
389488
}
@@ -392,9 +491,7 @@
392491
"id": "jfrog-artifactory-release-artifact-type",
393492
"description": "Artifactory",
394493
"type": "ms.vss-releaseartifact.release-artifact-type",
395-
"targets": [
396-
"ms.vss-releaseartifact.artifact-types"
397-
],
494+
"targets": ["ms.vss-releaseartifact.artifact-types"],
398495
"properties": {
399496
"name": "JFrogArtifactory",
400497
"displayName": "Artifactory V2",
@@ -433,10 +530,7 @@
433530
"hasDynamicValueInformation": true,
434531
"inputMode": "Combo",
435532
"isConfidential": false,
436-
"dependencyInputIds": [
437-
"connection",
438-
"projectKey"
439-
],
533+
"dependencyInputIds": ["connection", "projectKey"],
440534
"validation": {
441535
"isRequired": true,
442536
"dataType": "string",
@@ -590,12 +684,7 @@
590684
"properties": {
591685
"visibleRule": "defaultVersionType == specificVersionType"
592686
},
593-
"dependencyInputIds": [
594-
"connection",
595-
"definition",
596-
"defaultVersionType",
597-
"projectKey"
598-
],
687+
"dependencyInputIds": ["connection", "definition", "defaultVersionType", "projectKey"],
599688
"validation": {
600689
"isRequired": true,
601690
"dataType": "string"
@@ -634,9 +723,7 @@
634723
"id": "artifactory-build-info-tab",
635724
"type": "ms.vss-build-web.build-results-tab",
636725
"description": "A tab in build result to enforce Artifactory integration",
637-
"targets": [
638-
"ms.vss-build-web.build-results-view"
639-
],
726+
"targets": ["ms.vss-build-web.build-results-view"],
640727
"properties": {
641728
"name": "Artifactory",
642729
"uri": "artifactory-build-info.html"
@@ -645,189 +732,151 @@
645732
{
646733
"id": "jfrog-promote-build-task",
647734
"type": "ms.vss-distributed-task.task",
648-
"targets": [
649-
"ms.vss-distributed-task.tasks"
650-
],
735+
"targets": ["ms.vss-distributed-task.tasks"],
651736
"properties": {
652737
"name": "tasks/JFrogBuildPromotion"
653738
}
654739
},
655740
{
656741
"id": "jfrog-maven",
657742
"type": "ms.vss-distributed-task.task",
658-
"targets": [
659-
"ms.vss-distributed-task.tasks"
660-
],
743+
"targets": ["ms.vss-distributed-task.tasks"],
661744
"properties": {
662745
"name": "tasks/JFrogMaven"
663746
}
664747
},
665748
{
666749
"id": "jfrog-gradle",
667750
"type": "ms.vss-distributed-task.task",
668-
"targets": [
669-
"ms.vss-distributed-task.tasks"
670-
],
751+
"targets": ["ms.vss-distributed-task.tasks"],
671752
"properties": {
672753
"name": "tasks/JFrogGradle"
673754
}
674755
},
675756
{
676757
"id": "jfrog-npm",
677758
"type": "ms.vss-distributed-task.task",
678-
"targets": [
679-
"ms.vss-distributed-task.tasks"
680-
],
759+
"targets": ["ms.vss-distributed-task.tasks"],
681760
"properties": {
682761
"name": "tasks/JFrogNpm"
683762
}
684763
},
685764
{
686765
"id": "jfrog-nuget",
687766
"type": "ms.vss-distributed-task.task",
688-
"targets": [
689-
"ms.vss-distributed-task.tasks"
690-
],
767+
"targets": ["ms.vss-distributed-task.tasks"],
691768
"properties": {
692769
"name": "tasks/JFrogNuget"
693770
}
694771
},
695772
{
696773
"id": "jfrog-dotnet",
697774
"type": "ms.vss-distributed-task.task",
698-
"targets": [
699-
"ms.vss-distributed-task.tasks"
700-
],
775+
"targets": ["ms.vss-distributed-task.tasks"],
701776
"properties": {
702777
"name": "tasks/JFrogDotnet"
703778
}
704779
},
705780
{
706781
"id": "jfrog-publish-build-info",
707782
"type": "ms.vss-distributed-task.task",
708-
"targets": [
709-
"ms.vss-distributed-task.tasks"
710-
],
783+
"targets": ["ms.vss-distributed-task.tasks"],
711784
"properties": {
712785
"name": "tasks/JFrogPublishBuildInfo"
713786
}
714787
},
715788
{
716789
"id": "jfrog-conan-build-task",
717790
"type": "ms.vss-distributed-task.task",
718-
"targets": [
719-
"ms.vss-distributed-task.tasks"
720-
],
791+
"targets": ["ms.vss-distributed-task.tasks"],
721792
"properties": {
722793
"name": "tasks/JFrogConan"
723794
}
724795
},
725796
{
726797
"id": "jfrog-build-scan-task",
727798
"type": "ms.vss-distributed-task.task",
728-
"targets": [
729-
"ms.vss-distributed-task.tasks"
730-
],
799+
"targets": ["ms.vss-distributed-task.tasks"],
731800
"properties": {
732801
"name": "tasks/JFrogBuildScan"
733802
}
734803
},
735804
{
736805
"id": "jfrog-audit-task",
737806
"type": "ms.vss-distributed-task.task",
738-
"targets": [
739-
"ms.vss-distributed-task.tasks"
740-
],
807+
"targets": ["ms.vss-distributed-task.tasks"],
741808
"properties": {
742809
"name": "tasks/JFrogAudit"
743810
}
744811
},
745812
{
746813
"id": "jfrog-docker-task",
747814
"type": "ms.vss-distributed-task.task",
748-
"targets": [
749-
"ms.vss-distributed-task.tasks"
750-
],
815+
"targets": ["ms.vss-distributed-task.tasks"],
751816
"properties": {
752817
"name": "tasks/JFrogDocker"
753818
}
754819
},
755820
{
756821
"id": "jfrog-discard-builds-task",
757822
"type": "ms.vss-distributed-task.task",
758-
"targets": [
759-
"ms.vss-distributed-task.tasks"
760-
],
823+
"targets": ["ms.vss-distributed-task.tasks"],
761824
"properties": {
762825
"name": "tasks/JFrogDiscardBuilds"
763826
}
764827
},
765828
{
766829
"id": "jfrog-tools-installer-task",
767830
"type": "ms.vss-distributed-task.task",
768-
"targets": [
769-
"ms.vss-distributed-task.tasks"
770-
],
831+
"targets": ["ms.vss-distributed-task.tasks"],
771832
"properties": {
772833
"name": "tasks/JFrogToolsInstaller"
773834
}
774835
},
775836
{
776837
"id": "jfrog-go",
777838
"type": "ms.vss-distributed-task.task",
778-
"targets": [
779-
"ms.vss-distributed-task.tasks"
780-
],
839+
"targets": ["ms.vss-distributed-task.tasks"],
781840
"properties": {
782841
"name": "tasks/JFrogGo"
783842
}
784843
},
785844
{
786845
"id": "jfrog-pip",
787846
"type": "ms.vss-distributed-task.task",
788-
"targets": [
789-
"ms.vss-distributed-task.tasks"
790-
],
847+
"targets": ["ms.vss-distributed-task.tasks"],
791848
"properties": {
792849
"name": "tasks/JFrogPip"
793850
}
794851
},
795852
{
796853
"id": "jfrog-distribution",
797854
"type": "ms.vss-distributed-task.task",
798-
"targets": [
799-
"ms.vss-distributed-task.tasks"
800-
],
855+
"targets": ["ms.vss-distributed-task.tasks"],
801856
"properties": {
802857
"name": "tasks/JFrogDistribution"
803858
}
804859
},
805860
{
806861
"id": "jfrog-collect-issues",
807862
"type": "ms.vss-distributed-task.task",
808-
"targets": [
809-
"ms.vss-distributed-task.tasks"
810-
],
863+
"targets": ["ms.vss-distributed-task.tasks"],
811864
"properties": {
812865
"name": "tasks/JFrogCollectIssues"
813866
}
814867
},
815868
{
816869
"id": "jfrog-cli-v2",
817870
"type": "ms.vss-distributed-task.task",
818-
"targets": [
819-
"ms.vss-distributed-task.tasks"
820-
],
871+
"targets": ["ms.vss-distributed-task.tasks"],
821872
"properties": {
822873
"name": "tasks/JFrogCliV2"
823874
}
824875
},
825876
{
826877
"id": "jfrog-generic-artifacts",
827878
"type": "ms.vss-distributed-task.task",
828-
"targets": [
829-
"ms.vss-distributed-task.tasks"
830-
],
879+
"targets": ["ms.vss-distributed-task.tasks"],
831880
"properties": {
832881
"name": "tasks/JFrogGenericArtifacts"
833882
}
@@ -908,4 +957,4 @@
908957
"path": "tasks/JFrogGenericArtifacts"
909958
}
910959
]
911-
}
960+
}

0 commit comments

Comments
 (0)
Please sign in to comment.