> Pull Request Template > > Use this template to quickly create a well written pull request. Delete all quotes before creating the pull request. > ## Description > Add a TL;DR when description is extra long (helps content team) > > Please include a summary of the changes and which issue has been fixed. Please also include relevant motivation > and context. List any dependencies that are required for this change > > Links to Notion, Figma or any other documents that might be relevant to the PR > > #### PR fixes following issue(s) Fixes # (issue number) > if no issue exists, please create an issue and ask the maintainers about this first > > #### Media > A video or a GIF is preferred. when using Loom, don’t embed because it looks like it’s a GIF. instead, just link to the video > > #### Type of change > Please delete options that are not relevant. - Bug fix (non-breaking change which fixes an issue) - New feature (non-breaking change which adds functionality) - Breaking change (fix or feature that would cause existing functionality to not work as expected) - Chore (housekeeping or task changes that don't impact user perception) - This change requires a documentation update > > > ## Testing > #### How Has This Been Tested? > Please describe the tests that you ran to verify your changes. Also list any relevant details for your test configuration. > Delete anything that is not relevant - [ ] Manual - [ ] JUnit - [ ] Jest - [ ] Cypress > > #### Test Plan > Add Testsmith test cases links that relate to this PR > > #### Issues raised during DP testing > Link issues raised during DP testing for better visiblity and tracking (copy link from comments dropped on this PR) > > > ## Checklist: #### Dev activity - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag #### QA activity: - [ ] [Speedbreak features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-) have been covered - [ ] Test plan covers all impacted features and [areas of interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-) - [ ] Test plan has been peer reviewed by project stakeholders and other QA members - [ ] Manually tested functionality on DP - [ ] We had an implementation alignment call with stakeholders post QA Round 2 - [ ] Cypress test cases have been added and approved by SDET/manual QA - [ ] Added `Test Plan Approved` label after Cypress tests were reviewed - [ ] Added `Test Plan Approved` label after JUnit tests were reviewed
150 lines
4.9 KiB
TypeScript
150 lines
4.9 KiB
TypeScript
import { Pool } from "pg";
|
|
import AWS from "aws-sdk";
|
|
import fs from "fs";
|
|
import { Octokit } from "@octokit/rest";
|
|
import fetch from "node-fetch";
|
|
|
|
export interface DataItem {
|
|
name: string;
|
|
duration: string;
|
|
}
|
|
export default class util {
|
|
public getVars() {
|
|
return {
|
|
runId: this.getEnvValue("RUNID", { required: true }),
|
|
attempt_number: this.getEnvValue("ATTEMPT_NUMBER", { required: true }),
|
|
repository: this.getEnvValue("REPOSITORY", { required: true }),
|
|
committer: this.getEnvValue("COMMITTER", { required: true }),
|
|
tag: this.getEnvValue("TAG", { required: true }),
|
|
branch: this.getEnvValue("BRANCH", { required: true }),
|
|
cypressDbUser: this.getEnvValue("CYPRESS_DB_USER", { required: true }),
|
|
cypressDbHost: this.getEnvValue("CYPRESS_DB_HOST", { required: true }),
|
|
cypressDbName: this.getEnvValue("CYPRESS_DB_NAME", { required: true }),
|
|
cypressDbPwd: this.getEnvValue("CYPRESS_DB_PWD", { required: true }),
|
|
cypressS3Access: this.getEnvValue("CYPRESS_S3_ACCESS", {
|
|
required: true,
|
|
}),
|
|
cypressS3Secret: this.getEnvValue("CYPRESS_S3_SECRET", {
|
|
required: true,
|
|
}),
|
|
githubToken: process.env["GITHUB_TOKEN"],
|
|
commitMsg: this.getEnvValue("COMMIT_INFO_MESSAGE", { required: false }),
|
|
totalRunners: this.getEnvValue("TOTAL_RUNNERS", { required: false }),
|
|
thisRunner: this.getEnvValue("THIS_RUNNER", { required: true }),
|
|
cypressSpecs: this.getEnvValue("CYPRESS_SPECS", { required: false }),
|
|
cypressRerun: this.getEnvValue("CYPRESS_RERUN", { required: false }),
|
|
};
|
|
}
|
|
|
|
public async divideSpecsIntoBalancedGroups(
|
|
data: DataItem[],
|
|
numberOfGroups: number,
|
|
): Promise<DataItem[][]> {
|
|
const groups: DataItem[][] = Array.from(
|
|
{ length: numberOfGroups },
|
|
() => [],
|
|
);
|
|
data.forEach((item) => {
|
|
// Find the group with the shortest total duration and add the item to it
|
|
const shortestGroupIndex = groups.reduce(
|
|
(minIndex, group, currentIndex) => {
|
|
const totalDuration = groups[minIndex].reduce(
|
|
(acc, item) => acc + Number(item.duration),
|
|
0,
|
|
);
|
|
const totalDurationCurrent = group.reduce(
|
|
(acc, item) => acc + Number(item.duration),
|
|
0,
|
|
);
|
|
return totalDurationCurrent < totalDuration ? currentIndex : minIndex;
|
|
},
|
|
0,
|
|
);
|
|
groups[shortestGroupIndex].push(item);
|
|
});
|
|
return groups;
|
|
}
|
|
|
|
public getEnvValue(varName: string, { required = true }): string {
|
|
if (required && process.env[varName] === undefined) {
|
|
throw Error(
|
|
`${varName} is not defined.
|
|
Please check all the following environment variables are defined properly
|
|
[ RUNID, ATTEMPT_NUMBER, REPOSITORY, COMMITTER, TAG, BRANCH, THIS_RUNNER, CYPRESS_DB_USER, CYPRESS_DB_HOST, CYPRESS_DB_NAME, CYPRESS_DB_PWD, CYPRESS_S3_ACCESS, CYPRESS_S3_SECRET ].`,
|
|
);
|
|
}
|
|
return process.env[varName] ?? "";
|
|
}
|
|
|
|
//This is to setup the db client
|
|
public configureDbClient() {
|
|
const dbConfig = {
|
|
user: this.getVars().cypressDbUser,
|
|
host: this.getVars().cypressDbHost,
|
|
database: this.getVars().cypressDbName,
|
|
password: this.getVars().cypressDbPwd,
|
|
port: 5432,
|
|
connectionTimeoutMillis: 60000,
|
|
ssl: true,
|
|
keepalives: 30,
|
|
};
|
|
const dbClient = new Pool(dbConfig);
|
|
return dbClient;
|
|
}
|
|
|
|
// This is to setup the AWS client
|
|
public configureS3() {
|
|
AWS.config.update({ region: "ap-south-1" });
|
|
const s3client = new AWS.S3({
|
|
credentials: {
|
|
accessKeyId: this.getVars().cypressS3Access,
|
|
secretAccessKey: this.getVars().cypressS3Secret,
|
|
},
|
|
});
|
|
return s3client;
|
|
}
|
|
|
|
// This is to upload files to s3 when required
|
|
public async uploadToS3(s3Client: AWS.S3, filePath: string, key: string) {
|
|
const fileContent = fs.readFileSync(filePath);
|
|
const params = {
|
|
Bucket: "appsmith-internal-cy-db",
|
|
Key: key,
|
|
Body: fileContent,
|
|
};
|
|
return await s3Client.upload(params).promise();
|
|
}
|
|
|
|
public async getActiveRunners() {
|
|
const octokit = new Octokit({
|
|
auth: this.getVars().githubToken,
|
|
request: {
|
|
fetch: fetch,
|
|
},
|
|
});
|
|
try {
|
|
const repo: string[] = this.getVars().repository.split("/");
|
|
const response = await octokit.request(
|
|
"GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs",
|
|
{
|
|
owner: repo[0],
|
|
repo: repo[1],
|
|
run_id: Number(this.getVars().runId),
|
|
per_page: 100,
|
|
headers: {
|
|
"X-GitHub-Api-Version": "2022-11-28",
|
|
},
|
|
},
|
|
);
|
|
const active_runners = response.data.jobs.filter(
|
|
(job) =>
|
|
(job.status === "in_progress" || job.status === "queued") &&
|
|
job.run_attempt === Number(this.getVars().attempt_number),
|
|
);
|
|
return active_runners.length;
|
|
} catch (error) {
|
|
console.error("Error:", error);
|
|
}
|
|
}
|
|
}
|