Skip to content

Commit

Permalink
chore(Cross): [IOAPPX-213] Remove pivotal from danger and changelog s…
Browse files Browse the repository at this point in the history
…cripts (#5422)

## Short description
This PR addresses the removal of Pivotal Tracker integration from our
danger and changelog scripts, as it has been replaced by Jira.

## List of changes proposed in this pull request
- Removes `danger-plugin-digitalcitizenship` and `pivotaljs`, with the
former being a plugin with custom rules over Danger;
- Removes any dead code related to cross-linking with Pivotal Tracker
stories based on the PR title;
- Removes assigning scope based on ticket labels, given that they have
remained unused since the transition to Jira while keeping the
association between the project ID and a scope;
- Removes a generalization layer created to manage both Jira and Pivotal
tickets, making the scripts more coincise;
- Removes old scopes from inactive Jira boards while adding a scope for
the `IOAPPX` board;
- Refactors file and folders structure to make them coherent with the
declared functions and utilities;

## How to test
Static checks and tests. I also made a few tests by editing this PR
title and running Danger to check its behavior, as you can tell by this
messages history.
The changelog can be generated locally by testing any release command or
the script directly.

---------

Co-authored-by: Mario Perrotta <[email protected]>
  • Loading branch information
LazyAfternoons and hevelius authored Jan 31, 2024
1 parent 535e797 commit 8cd556b
Show file tree
Hide file tree
Showing 19 changed files with 452 additions and 1,172 deletions.
6 changes: 3 additions & 3 deletions Dangerfile.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Import custom DangerJS rules.
// See http://danger.systems/js
import { DangerDSLType } from "danger/distribution/dsl/DangerDSL";
import { commentPrWithTicketsInfo } from "./scripts/ts/danger/commentPrWithTicketsInfo";
import { updatePrTitleForChangelog } from "./scripts/ts/danger/updatePrTitleForChangelog";
import { getTicketsFromTitle } from "./scripts/ts/danger/utils/titleParser";
import { commentPrWithTicketsInfo } from "./scripts/ts/danger/commentPr";
import { updatePrTitleForChangelog } from "./scripts/ts/danger/updatePrTitle";
import { getTicketsFromTitle } from "./scripts/ts/common/jiraTicket";

declare const danger: DangerDSLType;

Expand Down
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,6 @@
"babel-preset-react-native": "^4.0.1",
"chalk": "^2.4.1",
"danger": "^10.3.0",
"danger-plugin-digitalcitizenship": "^0.3.1",
"eslint": "^8.6.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-functional": "^4.1.1",
Expand All @@ -286,7 +285,6 @@
"node-fetch": "^2.6.7",
"npm-run-all": "^4.1.3",
"patch-package": "6.5.1",
"pivotaljs": "^1.0.3",
"plist": "^3.0.5",
"postinstall-postinstall": "^1.0.0",
"prettier": "2.8.8",
Expand Down Expand Up @@ -320,7 +318,7 @@
},
"standard-version": {
"scripts": {
"postchangelog": "node scripts/changelog/add_pivotal_stories.js"
"postchangelog": "node scripts/changelog/add_jira_stories.js"
}
}
}
26 changes: 0 additions & 26 deletions patches/danger-plugin-digitalcitizenship+0.3.1.patch

This file was deleted.

6 changes: 0 additions & 6 deletions patches/patches.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,6 @@ Updated on **29/08/2022**

- This patch is going to fix a gradle issue that breaks the compile on android platform, due to gradle imcompatibility

### danger-plugin-digitalcitizenship+0.3.1
Created on **06/08/2020**

#### Reason:
- Recognizes the ids of pivotal stories even if they are not at the beginning of the line

### react-native-push-notification+7.3.1
Created on **10/05/2021**

Expand Down
Original file line number Diff line number Diff line change
@@ -1,42 +1,12 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fs = require("fs-extra");
const Pivotal = require("pivotaljs");
const pivotal = new Pivotal();

const jiraTicketBaseUrl = "https://pagopa.atlassian.net/browse/";

/**
* Skip the use of API to find the story url if the url is already retrieved (contains pivotaltracker.com)
* or the id length is < 9 (not a pivotal id)
* @param id
* @param url
* @return {*|boolean}
*/
function skipStoryCheck(id, url) {
return url.includes("pivotaltracker.com") || id.length < 9;
}

async function replacePivotalUrl(match, storyId, url) {
const sameUrl = `[${storyId}](${url})`;
try {
// avoid to use the api if story is already linked to pivotal
if (skipStoryCheck(storyId, url)) {
return sameUrl;
}
// try to get the story with the specified id
const story = await getStory(storyId.substr(1));

// if the story doesn't exists (eg: story deleted) remove the markdown link
return story.url !== undefined
? `[${storyId}](${story.url})`
: `${storyId}`;
} catch (err) {
return sameUrl;
}
}

async function addJiraUrl(match, ticketKeys) {
return `[${ticketKeys
.split(",")
// eslint-disable-next-line sonarjs/no-nested-template-literals
.map(x => `[${x}](${new URL(x, jiraTicketBaseUrl).toString()})`)}]`;
}

Expand All @@ -47,7 +17,7 @@ async function replaceJiraStories(content) {
}

/**
* replace the changelog content by removing the repetition of "closes [#idPivotalorJiraStory](url)"
* replace the changelog content by removing the repetition of "closes [#idJiraStory](url)"
* @param content
* @return {Promise<string>}
*/
Expand All @@ -61,8 +31,6 @@ async function addTasksUrls() {
const rawChangelog = fs.readFileSync("CHANGELOG.md").toString("utf8");

const updatedChangelog = await [
// Add pivotal stories url
replacePivotalStories,
// Add jira ticket url
replaceJiraStories,
// clean closes
Expand All @@ -75,14 +43,6 @@ async function addTasksUrls() {
fs.writeFileSync("CHANGELOG.md", updatedChangelog);
}

async function replacePivotalStories(content) {
// identify the pattern [#XXXXX](url) for markdown link
const pivotalTagRegex = /\[(#\d+)\]\(([a-zA-z/\d\-@:%._+~#=]+)\)/g;

// check for all the matches if is a pivotal story and update the url
return await replaceAsync(content, pivotalTagRegex, replacePivotalUrl);
}

/**
* A custom method created to allows the replace in a string using an async function
* @param str
Expand All @@ -94,29 +54,18 @@ async function replaceAsync(str, regex, asyncFn) {
const promises = [];
str.replace(regex, (match, ...args) => {
const promise = asyncFn(match, ...args);
// eslint-disable-next-line functional/immutable-data
promises.push(promise);
});
const data = await Promise.all(promises);
// eslint-disable-next-line functional/immutable-data
return str.replace(regex, () => data.shift());
}

/**
* Wrap the getStory callback with a promise
* @param storyId
* @return {Promise<Pivotal.Story>}
*/
getStory = storyId =>
new Promise((resolve, reject) => {
pivotal.getStory(storyId, (err, story) => {
if (err) {
return reject(err);
}
resolve(story);
});
});

// Execute the script to find the pivotal stories and jira ticket id in order to associate
// Execute the script to find jira ticket id in order to associate
// the right url in the changelog
addTasksUrls()
// eslint-disable-next-line no-console
.then(() => console.log("done"))
// eslint-disable-next-line no-console
.catch(ex => console.log(ex));
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { flow, pipe } from "fp-ts/lib/function";
import * as TE from "fp-ts/lib/TaskEither";
import { Errors } from "io-ts";
import fetch from "node-fetch";
import { RemoteJiraTicket } from "./types";
import * as O from "fp-ts/lib/Option";
import { JiraTicketRetrievalResults, RemoteJiraTicket } from "./types";

const jiraOrgBaseUrl = "https://pagopa.atlassian.net/rest/api/3/issue/";
export const jiraTicketBaseUrl = "https://pagopa.atlassian.net/browse/";
Expand Down Expand Up @@ -58,3 +59,39 @@ export const getJiraTickets = async (
jiraIds: ReadonlyArray<string>
): Promise<ReadonlyArray<E.Either<Errors | Error, RemoteJiraTicket>>> =>
await Promise.all(jiraIds.map(getJiraTicket));

const jiraRegex = /\[([A-Z0-9]+-\d+(,[A-Z0-9]+-\d+)*)]\s.+/;

/**
* Extracts Jira ticket ids from the pr title (if any)
* @param title
*/
export const getJiraIdFromPrTitle = (
title: string
): O.Option<ReadonlyArray<string>> =>
pipe(
title.match(jiraRegex),
O.fromNullable,
O.map(a => a[1].split(","))
);

/**
* Try to retrieve Jira tickets from pr title
* and transforms them into {@link GenericTicket}
* @param title
*/
export const getTicketsFromTitle = async (
title: string
): Promise<JiraTicketRetrievalResults> => {
const maybeJiraId = await pipe(
getJiraIdFromPrTitle(title),
O.map(getJiraTickets),
O.toUndefined
);

if (maybeJiraId) {
return maybeJiraId;
} else {
return [E.left(new Error("No Jira ticket found"))];
}
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import * as t from "io-ts";
import * as E from "fp-ts/lib/Either";
import { Errors } from "io-ts";

const JiraIssueType = t.keyof({
Epic: null,
Expand All @@ -12,28 +14,28 @@ const JiraIssueType = t.keyof({

export type JiraIssueType = t.TypeOf<typeof JiraIssueType>;

const IssueType = t.interface({
const IssueType = t.type({
name: JiraIssueType,
subtask: t.boolean
});

const Project = t.interface({
const Project = t.type({
id: t.string,
key: t.string,
name: t.string
});

const FieldsR = t.interface({
const FieldsR = t.type({
issuetype: IssueType,
project: Project,
labels: t.array(t.string),
summary: t.string
});

const FieldsP = t.partial({
parent: t.interface({
parent: t.type({
key: t.string,
fields: t.interface({
fields: t.type({
summary: t.string,
issuetype: IssueType
})
Expand All @@ -53,3 +55,11 @@ export const RemoteJiraTicket = t.interface({
});

export type RemoteJiraTicket = t.TypeOf<typeof RemoteJiraTicket>;

export type RemoteJiraTicketParent = Required<
t.TypeOf<typeof FieldsP>
>["parent"];

export type JiraTicketRetrievalResults = ReadonlyArray<
E.Either<Error | Errors, RemoteJiraTicket>
>;
39 changes: 0 additions & 39 deletions scripts/ts/common/ticket/pivotal/types.d.ts

This file was deleted.

Loading

0 comments on commit 8cd556b

Please sign in to comment.