Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ distribution.js
pipBuild.js
tests.js
testUtils.js
docker.js
docker.js
utilsTests.js
1 change: 1 addition & 0 deletions jfrog-tasks-utils/utils.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,6 @@ declare module '@jfrog/tasks-utils' {
cliPath: string,
buildDir: string,
): string;
export function parsePlatformUrlFromServiceUrl(serviceUrl: string): string;
export { taskSelectedCliVersionEnv };
}
31 changes: 30 additions & 1 deletion jfrog-tasks-utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ module.exports = {
jfrogCliToolName: jfrogCliToolName,
isServerIdEnvSupported: isServerIdEnvSupported,
setJdkHomeForJavaTasks: setJdkHomeForJavaTasks,
parsePlatformUrlFromServiceUrl: parsePlatformUrlFromServiceUrl,
};

/**
Expand Down Expand Up @@ -437,7 +438,15 @@ function configureSpecificCliServer(service, urlFlag, serverId, cliPath, buildDi
// username and access token params for further use by the users.
if (oidcProviderName) {
// we need platform url for oidc token exchange
let platformUrl = tl.getEndpointAuthorizationParameter(service, 'jfrogPlatformUrl', true);
let platformUrl = "";
try {
platformUrl = tl.getEndpointAuthorizationParameter(service, 'jfrogPlatformUrl', true);
} catch (error) {
console.warn('Failed to get platform url from field: ' + error+"\nparsing from url instead");
}
if (!platformUrl || !platformUrl.trim()) {
platformUrl = parsePlatformUrlFromServiceUrl(serviceUrl);
}
serviceAccessToken = exchangeOidcTokenAndSetStepVariables(service, platformUrl, oidcProviderName, cliPath, buildDir);
}

Expand Down Expand Up @@ -953,6 +962,26 @@ function stripTrailingSlash(str) {
return str.endsWith('/') ? str.slice(0, -1) : str;
}

/**
* Parse platform URL from a service URL by stripping service-specific suffixes.
* Handles URLs ending with /xray, /artifactory, or /distribution (case-insensitive).
*
* @param serviceUrl - The service URL to parse (e.g., 'https://example.jfrog.io/artifactory')
* @returns The platform URL with the service suffix removed
*/
function parsePlatformUrlFromServiceUrl(serviceUrl) {
const suffixes = ['/xray', '/artifactory', '/distribution'];
const url = new URL(serviceUrl);
for (const suffix of suffixes) {
if (url.pathname.endsWith(suffix)) {
url.pathname = url.pathname.replace(suffix, '');
break;
}
}
// Remove trailing slash
return url.toString().replace(/\/$/, '');
}

/**
* Determines the required working directory for running the cli.
* Decision is based on the default path to run, and the provided path by the user.
Expand Down
7 changes: 6 additions & 1 deletion tests/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
tests.js.map
tests.d.ts
tests.js

testUtils.js.map
testUtils.d.ts
testUtils.js
testUtils.js

utilsTests.js.map
utilsTests.d.ts
utilsTests.js
162 changes: 162 additions & 0 deletions tests/utilsTests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/// <reference types="mocha" />
import * as assert from 'assert';

// Use require to get the actual module with latest exports
import * as jfrogUtils from '@jfrog/tasks-utils';

/**
* Simulates the platformUrl resolution logic from utils.js lines 441-449:
*
* let platformUrl = "";
* try {
* platformUrl = tl.getEndpointAuthorizationParameter(service, 'jfrogPlatformUrl', true);
* } catch (error) {
* console.warn('Failed to get platform url from field: ' + error + "\nparsing from url instead");
* }
* if (!platformUrl || !platformUrl.trim()) {
* platformUrl = parsePlatformUrlFromServiceUrl(serviceUrl);
* }
*
* @param getEndpointResult - Simulated result from tl.getEndpointAuthorizationParameter
* @param shouldThrow - Whether the call should throw an error
* @param serviceUrl - The service URL to parse from if platformUrl is not available
* @returns The resolved platform URL
*/
function simulatePlatformUrlResolution(
getEndpointResult: string | undefined | null,
shouldThrow: boolean,
serviceUrl: string,
): string {
let platformUrl: string | undefined | null = '';
try {
if (shouldThrow) {
throw new Error('Simulated error');
}
platformUrl = getEndpointResult;
} catch {
// Simulates: console.warn('Failed to get platform url from field...')
}
if (!platformUrl || !platformUrl.trim()) {
platformUrl = jfrogUtils.parsePlatformUrlFromServiceUrl(serviceUrl);
}
return platformUrl;
}

describe('Utils Unit Tests', (): void => {
describe('platformUrl resolution (simulating tl.getEndpointAuthorizationParameter)', (): void => {
const serviceUrl: string = 'https://example.jfrog.io/artifactory';

it('should use platformUrl directly when getEndpointAuthorizationParameter returns valid URL', (): void => {
const result: string = simulatePlatformUrlResolution('https://my-platform.jfrog.io', false, serviceUrl);
assert.strictEqual(result, 'https://my-platform.jfrog.io');
});

it('should parse from serviceUrl when getEndpointAuthorizationParameter returns empty string', (): void => {
const result: string = simulatePlatformUrlResolution('', false, serviceUrl);
assert.strictEqual(result, 'https://example.jfrog.io');
});

it('should parse from serviceUrl when getEndpointAuthorizationParameter returns undefined', (): void => {
const result: string = simulatePlatformUrlResolution(undefined, false, serviceUrl);
assert.strictEqual(result, 'https://example.jfrog.io');
});

it('should parse from serviceUrl when getEndpointAuthorizationParameter returns null', (): void => {
const result: string = simulatePlatformUrlResolution(null, false, serviceUrl);
assert.strictEqual(result, 'https://example.jfrog.io');
});

it('should parse from serviceUrl when getEndpointAuthorizationParameter returns whitespace only', (): void => {
const result: string = simulatePlatformUrlResolution(' ', false, serviceUrl);
assert.strictEqual(result, 'https://example.jfrog.io');
});

it('should parse from serviceUrl when getEndpointAuthorizationParameter throws error', (): void => {
const result: string = simulatePlatformUrlResolution('', true, serviceUrl);
assert.strictEqual(result, 'https://example.jfrog.io');
});

it('should parse from xray serviceUrl when platformUrl not available', (): void => {
const result: string = simulatePlatformUrlResolution('', false, 'https://example.jfrog.io/xray');
assert.strictEqual(result, 'https://example.jfrog.io');
});

it('should parse from distribution serviceUrl when platformUrl not available', (): void => {
const result: string = simulatePlatformUrlResolution('', false, 'https://example.jfrog.io/distribution');
assert.strictEqual(result, 'https://example.jfrog.io');
});
});

describe('parsePlatformUrlFromServiceUrl', (): void => {
it('should strip /artifactory suffix', (): void => {
assert.strictEqual(
jfrogUtils.parsePlatformUrlFromServiceUrl('https://example.jfrog.io/artifactory'),
'https://example.jfrog.io',
);
});

it('should strip /xray suffix', (): void => {
assert.strictEqual(
jfrogUtils.parsePlatformUrlFromServiceUrl('https://example.jfrog.io/xray'),
'https://example.jfrog.io',
);
});

it('should strip /distribution suffix', (): void => {
assert.strictEqual(
jfrogUtils.parsePlatformUrlFromServiceUrl('https://example.jfrog.io/distribution'),
'https://example.jfrog.io',
);
});

it('should handle case-insensitive matching for /Artifactory', (): void => {
assert.strictEqual(
jfrogUtils.parsePlatformUrlFromServiceUrl('https://example.jfrog.io/Artifactory'),
'https://example.jfrog.io',
);
});

it('should handle case-insensitive matching for /XRAY', (): void => {
assert.strictEqual(
jfrogUtils.parsePlatformUrlFromServiceUrl('https://example.jfrog.io/XRAY'),
'https://example.jfrog.io',
);
});

it('should return URL as-is when no known suffix', (): void => {
assert.strictEqual(
jfrogUtils.parsePlatformUrlFromServiceUrl('https://example.jfrog.io/other'),
'https://example.jfrog.io/other',
);
});

it('should handle URL with port', (): void => {
assert.strictEqual(
jfrogUtils.parsePlatformUrlFromServiceUrl('https://example.jfrog.io:8080/artifactory'),
'https://example.jfrog.io:8080',
);
});

it('should handle URL with trailing slash on suffix', (): void => {
assert.strictEqual(
jfrogUtils.parsePlatformUrlFromServiceUrl('https://example.jfrog.io/artifactory/'),
'https://example.jfrog.io',
);
});

it('should handle URL with path prefix', (): void => {
assert.strictEqual(
jfrogUtils.parsePlatformUrlFromServiceUrl('https://example.com/jfrog/artifactory'),
'https://example.com/jfrog',
);
});

it('should handle URL without any prefix', (): void => {
assert.strictEqual(jfrogUtils.parsePlatformUrlFromServiceUrl('https://example.com/jfrog'), 'https://example.com/jfrog');
});

it('should handle hostnames as well', (): void => {
assert.strictEqual(jfrogUtils.parsePlatformUrlFromServiceUrl('https://artifactory.com/jfrog/artifactory'), 'https://artifactory.com/jfrog');
});
});
});
Loading