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
1 change: 1 addition & 0 deletions tasks/JFrogConan/conanUtils.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
// eslint-disable-next-line @typescript-eslint/no-namespace
declare namespace conan_utils {
function getCliPartialsBuildDir(buildName: string, buildNumber: string): string;
function initCliPartialsBuildDir(buildName: string, buildNumber: string): number;
}
export = conan_utils;
53 changes: 48 additions & 5 deletions tasks/JFrogConan/conanUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ function executeConanTask(commandArgs) {

let conanTaskId = generateConanTaskUUId();
tl.debug('Conan Task Id: ' + conanTaskId);
let buildTimestamp = Date.now();

let conanPath = null;
try {
Expand Down Expand Up @@ -58,7 +57,7 @@ function executeConanTask(commandArgs) {
let buildName = tl.getInput('buildName', true);
let buildNumber = tl.getInput('buildNumber', true);
try {
initCliPartialsBuildDir(buildName, buildNumber);
let buildTimestamp = initCliPartialsBuildDir(buildName, buildNumber);
setConanTraceFileLocation(conanUserHome, conanTaskId);
setArtifactsBuildInfoProperties(conanUserHome, buildName, buildNumber, buildTimestamp);
} catch (err) {
Expand Down Expand Up @@ -387,14 +386,56 @@ function purgeConanRemotes() {
* Creates the path of for partials build info and initializing the details file with Timestamp.
* @param buildName (string) - The build name
* @param buildNumber (string) - The build number
* @returns {number} - The timestamp of the build in milliseconds.
*/
function initCliPartialsBuildDir(buildName, buildNumber) {
let partialsBuildDir = join(getCliPartialsBuildDir(buildName, buildNumber), 'partials');
let buildDetailsFile = join(partialsBuildDir, 'details');

// If a build was initialized before this task, read the build timestamp from the existing build details.
if (fs.pathExistsSync(buildDetailsFile)) {
let buildTimestamp = readTimestampFromPartial(buildDetailsFile);
if (buildTimestamp) {
tl.debug('Read timestamp "' + buildTimestamp + '" from partial build details at: ' + buildDetailsFile);
return buildTimestamp;
}
}
// If a build was not initialized, create a new build details file.
return createBuildDetailsPartial(partialsBuildDir, buildDetailsFile);
}

/**
* Creates the partial details file with the current timestamp.
* @param partialsBuildDir (string) - path to the build's partials directory.
* @param buildDetailsFile (string) - path to the build's partial build details file.
* @returns {number} - The timestamp of the build in milliseconds.
*/
function createBuildDetailsPartial(partialsBuildDir, buildDetailsFile) {
if (!fs.pathExistsSync(partialsBuildDir)) {
fs.ensureDirSync(partialsBuildDir);
}
fs.writeJsonSync(join(partialsBuildDir, 'details'), { Timestamp: new Date().toISOString() });
tl.debug('Created partial details at: ' + join(partialsBuildDir, 'details'));

// The start time is saved as ISO, but the artifacts property is saved as a timestamp.
let buildStartTime = new Date();
fs.writeJsonSync(buildDetailsFile, { Timestamp: buildStartTime.toISOString() });
tl.debug('Created partial build details at: ' + buildDetailsFile);
return buildStartTime.getTime();
}

/**
* Reads the build start time from the build's partial build details file, and returns it as timestamp.
* @param buildDetailsFile (string) - path to the build's partial build details file.
* @returns {number} - The timestamp of the build in milliseconds.
*/
function readTimestampFromPartial(buildDetailsFile) {
try {
const data = fs.readFileSync(buildDetailsFile, 'utf8');
const jsonData = JSON.parse(data);
return Date.parse(jsonData.Timestamp);
} catch (err) {
console.error('Error reading or parsing the build details partials file:', err);
return undefined;
}
}

function getCliPartialsBuildDir(buildName, buildNumber) {
Expand All @@ -405,6 +446,8 @@ function getCliPartialsBuildDir(buildName, buildNumber) {

module.exports = {
executeConanTask: executeConanTask,
getCliPartialsBuildDir: getCliPartialsBuildDir, // Exported for tests
purgeConanRemotes: purgeConanRemotes,
// Exported for tests:
getCliPartialsBuildDir: getCliPartialsBuildDir,
initCliPartialsBuildDir: initCliPartialsBuildDir,
};
16 changes: 8 additions & 8 deletions tests/testUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const repoKeys: any = {
pipRemoteRepo: 'pip-remote',
pipVirtualRepo: 'pip-virtual',
releaseBundlesRepo: 'rb-repo',
dockerLocalRepo: 'docker-local'
dockerLocalRepo: 'docker-local',
};

export { testDataDir, repoKeys, platformUrl, platformPassword, platformUsername, platformAccessToken, platformDockerDomain };
Expand Down Expand Up @@ -165,7 +165,7 @@ export function createTestRepositories(): void {
url: 'https://releases.jfrog.io/artifactory/jfrog-cli/v2-jf',
}),
);
if (!isSkipTest('maven')) {
if (!isSkipTest('maven')) {
createRepo(repoKeys.mavenLocalRepo, JSON.stringify({ rclass: 'local', packageType: 'maven' }));
createRepo(
repoKeys.mavenRemoteRepo,
Expand All @@ -176,7 +176,7 @@ export function createTestRepositories(): void {
}),
);
}
if (!isSkipTest('nuget') && !isSkipTest('dotnet')) {
if (!isSkipTest('nuget') && !isSkipTest('dotnet')) {
createRepo(
repoKeys.nugetLocalRepo,
JSON.stringify({
Expand Down Expand Up @@ -207,7 +207,7 @@ export function createTestRepositories(): void {
}),
);
}
if (!isSkipTest('npm')) {
if (!isSkipTest('npm')) {
createRepo(
repoKeys.npmLocalRepo,
JSON.stringify({
Expand Down Expand Up @@ -235,10 +235,10 @@ export function createTestRepositories(): void {
}),
);
}
if (!isSkipTest('conan')) {
if (!isSkipTest('conan')) {
createRepo(repoKeys.conanLocalRepo, JSON.stringify({ rclass: 'local', packageType: 'conan' }));
}
if (!isSkipTest('go')) {
if (!isSkipTest('go')) {
createRepo(
repoKeys.goLocalRepo,
JSON.stringify({
Expand Down Expand Up @@ -266,7 +266,7 @@ export function createTestRepositories(): void {
}),
);
}
if (!isSkipTest('pip')) {
if (!isSkipTest('pip')) {
createRepo(repoKeys.pipLocalRepo, JSON.stringify({ rclass: 'local', packageType: 'pypi', repoLayoutRef: 'simple-default' }));
createRepo(
repoKeys.pipRemoteRepo,
Expand All @@ -293,7 +293,7 @@ export function createTestRepositories(): void {
packageType: 'docker',
dockerApiVersion: 'V2',
dockerV1Enabled: false,
enableTokenAuthentication: true
enableTokenAuthentication: true,
}),
);
}
Expand Down
37 changes: 36 additions & 1 deletion tests/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,14 @@ describe('JFrog Artifactory Extension Tests', (): void => {
},
TestUtils.isSkipTest('unit'),
);

runSyncTest(
'Conan Utils - Init build details partial and verify consistency in timestamp',
(): void => {
testInitCliPartialsBuildDir();
},
TestUtils.isSkipTest('unit'),
);
});

describe('JFrog CLI Task Tests', (): void => {
Expand Down Expand Up @@ -745,7 +753,9 @@ describe('JFrog Artifactory Extension Tests', (): void => {
const filesDir: string = TestUtils.isWindows() ? 'windowsFiles' : 'unixFiles';

// Run docker build + tag
execSync(`docker build -t ${platformDockerDomain}/${repoKeys.dockerLocalRepo}/docker-test:1 ${join(__dirname, 'resources', testDir, filesDir)}`);
execSync(
`docker build -t ${platformDockerDomain}/${repoKeys.dockerLocalRepo}/docker-test:1 ${join(__dirname, 'resources', testDir, filesDir)}`,
);

// run docker push
mockTask(testDir, 'push');
Expand Down Expand Up @@ -1227,6 +1237,31 @@ function testGetCliPartialsBuildDir(): void {
testDTO.testsBuildNames.forEach((element: string): void => runBuildCommand('bc', element, testDTO.testBuildNumber));
}

function testInitCliPartialsBuildDir(): void {
const testsBuildName: string = 'partialTestBuildName';
const testBuildNumber: string = '123';

// Cleanup old partials.
runBuildCommand('bc', testsBuildName, testBuildNumber);

// Init build partials directory. A new build timestamp should be generated.
let originalBuildTimestamp: number = conanUtils.initCliPartialsBuildDir(testsBuildName, testBuildNumber);
assert.ok(originalBuildTimestamp, 'A timestamp should have been generated');
assert.equal(originalBuildTimestamp.toString().length, 13, 'The timestamp should be valid');

// Calling initialization again. Since it already exists, we expect the same timestamp to be returned.
let newBuildTimestamp: number = conanUtils.initCliPartialsBuildDir(testsBuildName, testBuildNumber);
assert.equal(originalBuildTimestamp, newBuildTimestamp, 'The timestamp should not have changed');

// Cleanup existing partials, init again and assert the new timestamp.
runBuildCommand('bc', testsBuildName, testBuildNumber);
newBuildTimestamp = conanUtils.initCliPartialsBuildDir(testsBuildName, testBuildNumber);
assert.notEqual(originalBuildTimestamp, newBuildTimestamp, 'The timestamp should have changed');

// Cleanup test.
runBuildCommand('bc', testsBuildName, testBuildNumber);
}

function runBuildCommand(command: string, buildName: string, buildNumber: string): void {
jfrogUtils.executeCliCommand('jf rt ' + command + ' "' + buildName + '" ' + buildNumber, TestUtils.testDataDir);
}
Loading