Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TT-1624] Make sure that each Solidity change has a corresponding Solidity Review issue in Jira #14417

Draft
wants to merge 33 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
3532540
WIP#1 - enforce existence of Solidity Review ticket
Tofel Sep 10, 2024
2dd93d8
clean and simplify code
Tofel Sep 13, 2024
b4bfb3f
Merge branch 'develop' into tt_1624_Solidity_Review_jira_each_pr
Tofel Sep 13, 2024
9a626c0
code clean up after tests
Tofel Sep 13, 2024
2b2745c
added function comments
Tofel Sep 13, 2024
f9ab9a1
test out new solidity review workflow
Tofel Sep 13, 2024
e016dc5
fix npm script name
Tofel Sep 13, 2024
c42319d
further test pr enforcement
Tofel Sep 13, 2024
a2ab1d3
use csv changeset format
Tofel Sep 13, 2024
09e118b
fix step name
Tofel Sep 13, 2024
2b6ab5c
[Bot] Update changeset file with jira issue
app-token-issuer-infra-releng[bot] Sep 13, 2024
74c0601
remove Solidity Review issue from changeset to test creation of new one
Tofel Sep 13, 2024
172e2f4
[Bot] Update changeset file with jira issue
app-token-issuer-infra-releng[bot] Sep 13, 2024
e7a7225
add mising await, test creation of Solidity Review again
Tofel Sep 13, 2024
cb808a7
add mising await, test creation of Solidity Review again
Tofel Sep 13, 2024
117d946
[Bot] Update changeset file with jira issue
app-token-issuer-infra-releng[bot] Sep 13, 2024
210bb8f
run with existing solidity issue
Tofel Sep 13, 2024
dcb3aa9
Merge branch 'develop' into tt_1624_Solidity_Review_jira_each_pr
Tofel Sep 16, 2024
a525e1a
print changeset file content in GH comment
Tofel Sep 16, 2024
90a019c
remove test contract + duplicated dependency
Tofel Sep 17, 2024
8612411
Merge branch 'develop' into tt_1624_Solidity_Review_jira_each_pr
Tofel Sep 19, 2024
63faaec
export jira issue keys as gh env vars
Tofel Sep 19, 2024
d33f6e9
test out traceability
Tofel Sep 19, 2024
ed02887
[Bot] Update changeset file with jira issue
app-token-issuer-infra-releng[bot] Sep 19, 2024
4116108
do not modify comment, if you're a bot
Tofel Sep 19, 2024
76f24e5
[Bot] Update changeset file with jira issue
app-token-issuer-infra-releng[bot] Sep 19, 2024
c458d48
fix condition
Tofel Sep 19, 2024
ca6b0f6
modify changeset
Tofel Sep 19, 2024
a930437
[Bot] Update changeset file with jira issue
app-token-issuer-infra-releng[bot] Sep 19, 2024
65c736a
fix jira link
Tofel Sep 19, 2024
c3a671c
[Bot] Update changeset file with jira issue
app-token-issuer-infra-releng[bot] Sep 19, 2024
84748de
do not fail the workflow if jira enforcement fails
Tofel Sep 19, 2024
fb6a876
add tests + update comments
Tofel Sep 20, 2024
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
64 changes: 64 additions & 0 deletions .github/scripts/jira/changeset-lib.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import * as core from "@actions/core";
import { join } from "path";
import { getGitTopLevel } from "./lib";
import { promises as fs } from "fs";

export async function appendIssueNumberToChangesetFile(
prefix: string,
changesetFile: string,
issueNumber: string
) {
const gitTopLevel = await getGitTopLevel();
const fullChangesetPath = join(gitTopLevel, changesetFile);
const changesetContents = await fs.readFile(fullChangesetPath, "utf-8");
// Check if the issue number is already in the changeset file
if (changesetContents.includes(issueNumber)) {
core.info("Issue number already exists in changeset file, skipping...");
return;
}

const updatedChangesetContents = `${changesetContents}\n\n${prefix}${issueNumber}`;
await fs.writeFile(fullChangesetPath, updatedChangesetContents);
}

/**
* Extracts the list of changeset files. Intended to be used with https://github.com/dorny/paths-filter with
* the 'csv' output format.
*
* @returns An array of strings representing the changeset files.
* @throws {Error} If the required environment variable CHANGESET_FILES is missing.
* @throws {Error} If no changeset file exists.
*/
export function extractChangesetFiles(): string[] {
const changesetFiles = process.env.CHANGESET_FILES;
if (!changesetFiles) {
throw Error("Missing required environment variable CHANGESET_FILES");
}
const parsedChangesetFiles = changesetFiles.split(",");
if (parsedChangesetFiles.length === 0) {
throw Error("At least one changeset file must exist");
}

core.info(
`Changeset to extract issues from: ${parsedChangesetFiles.join(", ")}`
);
return parsedChangesetFiles;
}

/**
* Extracts a single changeset file. Intended to be used with https://github.com/dorny/paths-filter with
* the 'csv' output format.
*
* @returns A single changeset file path.
* @throws {Error} If the required environment variable CHANGESET_FILES is missing.
* @throws {Error} If no changeset file exists.
* @throws {Error} If more than one changeset file exists.
*/
export function extractChangesetFile(): string {
const changesetFiles = extractChangesetFiles()
if (changesetFiles.length > 1) {
throw new Error(`Found ${changesetFiles.length} changeset files, but only 1 was expected.`)
}

return changesetFiles[0]
}
28 changes: 3 additions & 25 deletions .github/scripts/jira/create-jira-traceability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,10 @@ import {
generateJiraIssuesLink,
getJiraEnvVars,
handleError,
PR_PREFIX,
} from "./lib";
import * as core from "@actions/core";

/**
* Extracts the list of changeset files. Intended to be used with https://github.com/dorny/paths-filter with
* the 'csv' output format.
*
* @returns An array of strings representing the changeset files.
* @throws {Error} If the required environment variable CHANGESET_FILES is missing.
* @throws {Error} If no changeset file exists.
*/
function extractChangesetFiles(): string[] {
const changesetFiles = process.env.CHANGESET_FILES;
if (!changesetFiles) {
throw Error("Missing required environment variable CHANGESET_FILES");
}
const parsedChangesetFiles = changesetFiles.split(",");
if (parsedChangesetFiles.length === 0) {
throw Error("At least one changeset file must exist");
}

core.info(
`Changeset to extract issues from: ${parsedChangesetFiles.join(", ")}`
);
return parsedChangesetFiles;
}
import { extractChangesetFiles } from './changeset-lib'

/**
* Adds traceability to JIRA issues by commenting on each issue with a link to the artifact payload
Expand Down Expand Up @@ -188,7 +166,7 @@ async function main() {
", "
)}`
);
const jiraIssueNumbers = await extractJiraIssueNumbersFrom(changesetFiles);
const jiraIssueNumbers = await extractJiraIssueNumbersFrom(PR_PREFIX, changesetFiles);

const client = createJiraClient();
const label = generateIssueLabel(product, baseRef, headRef);
Expand Down
83 changes: 5 additions & 78 deletions .github/scripts/jira/enforce-jira-issue.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,17 @@
import * as core from "@actions/core";
import jira from "jira.js";
import { createJiraClient, getGitTopLevel, handleError, parseIssueNumberFrom } from "./lib";
import { promises as fs } from "fs";
import { join } from "path";

async function doesIssueExist(
client: jira.Version3Client,
issueNumber: string,
dryRun: boolean
) {
const payload = {
issueIdOrKey: issueNumber,
};

if (dryRun) {
core.info("Dry run enabled, skipping JIRA issue enforcement");
return true;
}

try {
/**
* The issue is identified by its ID or key, however, if the identifier doesn't match an issue, a case-insensitive search and check for moved issues is performed.
* If a matching issue is found its details are returned, a 302 or other redirect is not returned. The issue key returned in the response is the key of the issue found.
*/
const issue = await client.issues.getIssue(payload);
core.debug(
`JIRA issue id:${issue.id} key: ${issue.key} found while querying for ${issueNumber}`
);
if (issue.key !== issueNumber) {
core.error(
`JIRA issue key ${issueNumber} not found, but found issue key ${issue.key} instead. This can happen if the identifier doesn't match an issue, in which case a case-insensitive search and check for moved issues is performed. Make sure the issue key is correct.`
);
return false;
}

return true;
} catch (e) {
handleError(e)
return false;
}
}
import { createJiraClient, EMPTY_PREFIX, parseIssueNumberFrom, doesIssueExist, PR_PREFIX } from "./lib";
import { appendIssueNumberToChangesetFile, extractChangesetFile } from "./changeset-lib";

async function main() {
const prTitle = process.env.PR_TITLE;
const commitMessage = process.env.COMMIT_MESSAGE;
const branchName = process.env.BRANCH_NAME;
const dryRun = !!process.env.DRY_RUN;
const { changesetFile } = extractChangesetFile();

const changesetFile = extractChangesetFile();
const client = createJiraClient();

// Checks for the Jira issue number and exit if it can't find it
const issueNumber = parseIssueNumberFrom(prTitle, commitMessage, branchName);
const issueNumber = parseIssueNumberFrom(EMPTY_PREFIX, prTitle, commitMessage, branchName);
if (!issueNumber) {
const msg =
"No JIRA issue number found in PR title, commit message, or branch name. This pull request must be associated with a JIRA issue.";
Expand All @@ -69,40 +29,7 @@ async function main() {
}

core.info(`Appending JIRA issue ${issueNumber} to changeset file`);
await appendIssueNumberToChangesetFile(changesetFile, issueNumber);
}

async function appendIssueNumberToChangesetFile(
changesetFile: string,
issueNumber: string
) {
const gitTopLevel = await getGitTopLevel();
const fullChangesetPath = join(gitTopLevel, changesetFile);
const changesetContents = await fs.readFile(fullChangesetPath, "utf-8");
// Check if the issue number is already in the changeset file
if (changesetContents.includes(issueNumber)) {
core.info("Issue number already exists in changeset file, skipping...");
return;
}

const updatedChangesetContents = `${changesetContents}\n\n${issueNumber}`;
await fs.writeFile(fullChangesetPath, updatedChangesetContents);
}

function extractChangesetFile() {
const changesetFiles = process.env.CHANGESET_FILES;
if (!changesetFiles) {
throw Error("Missing required environment variable CHANGESET_FILES");
}
const parsedChangesetFiles = JSON.parse(changesetFiles);
if (parsedChangesetFiles.length !== 1) {
throw Error(
"This action only supports one changeset file per pull request."
);
}
const [changesetFile] = parsedChangesetFiles;

return { changesetFile };
await appendIssueNumberToChangesetFile(PR_PREFIX, changesetFile, issueNumber);
}

async function run() {
Expand Down
Loading
Loading