This is an automated email from the ASF dual-hosted git repository.
amolina pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/master by this push:
new b1bcd6f3f1 ARROW-18380: [Dev] Update dev_pr GitHub workflows to accept
both GitHub issues and JIRA (#14731)
b1bcd6f3f1 is described below
commit b1bcd6f3f17ceee958fae6905185a99e1307e6a7
Author: Raúl Cumplido <[email protected]>
AuthorDate: Tue Nov 29 13:54:44 2022 +0100
ARROW-18380: [Dev] Update dev_pr GitHub workflows to accept both GitHub
issues and JIRA (#14731)
This might require to be done once the merge_arrow_pr.sh script is also
updated. Updating the merge PR script is tracked on GitHub for the migration
here: #14720
I have tested this new workflow on my fork with the following PRs and
issues on my fork.
Example of valid issue: https://github.com/raulcd/arrow/pull/41
Example of issues without labels or assignees:
https://github.com/raulcd/arrow/pull/42 or
https://github.com/raulcd/arrow/pull/43
Example of issue with non existent GH issue:
https://github.com/raulcd/arrow/pull/45
Authored-by: Raúl Cumplido <[email protected]>
Signed-off-by: Alessandro Molina <[email protected]>
---
.github/workflows/dev_pr.yml | 5 +-
.github/workflows/dev_pr/helpers.js | 64 +++++++++------
.../dev_pr/{jira_check.js => issue_check.js} | 91 +++++++++++++++++++++-
.github/workflows/dev_pr/link.js | 71 ++++++++++++++---
.github/workflows/dev_pr/title_check.js | 7 +-
.github/workflows/dev_pr/title_check.md | 13 +++-
6 files changed, 205 insertions(+), 46 deletions(-)
diff --git a/.github/workflows/dev_pr.yml b/.github/workflows/dev_pr.yml
index f3c59ad54f..1de6cf1b01 100644
--- a/.github/workflows/dev_pr.yml
+++ b/.github/workflows/dev_pr.yml
@@ -36,6 +36,7 @@ concurrency:
permissions:
contents: read
pull-requests: write
+ issues: write
jobs:
process:
@@ -66,7 +67,7 @@ jobs:
const script =
require(`${process.env.GITHUB_WORKSPACE}/.github/workflows/dev_pr/title_check.js`);
script({github, context});
- - name: Check Jira Issue
+ - name: Check Issue
if: |
(github.event.action == 'opened' ||
github.event.action == 'edited')
@@ -75,7 +76,7 @@ jobs:
debug: true
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
- const script =
require(`${process.env.GITHUB_WORKSPACE}/.github/workflows/dev_pr/jira_check.js`);
+ const script =
require(`${process.env.GITHUB_WORKSPACE}/.github/workflows/dev_pr/issue_check.js`);
script({github, context});
- name: Assign GitHub labels
diff --git a/.github/workflows/dev_pr/helpers.js
b/.github/workflows/dev_pr/helpers.js
index d5f275d27f..282567f956 100644
--- a/.github/workflows/dev_pr/helpers.js
+++ b/.github/workflows/dev_pr/helpers.js
@@ -18,34 +18,33 @@
const https = require('https');
/**
- * Given the title of a PullRequest return the ID of the JIRA issue
+ * Given the title of a PullRequest return the Issue
+ *
* @param {String} title
- * @returns {String} the ID of the associated JIRA issue
+ * @returns {Issue} or null if no issue detected.
+ *
+ * @typedef {Object} Issue
+ * @property {string} kind - The kind of issue: minor, jira or github
+ * @property {string} id - The id of the issue:
+ * ARROW-XXXX, PARQUET-XXXX for jira
+ * The numeric issue id for github
*/
-function detectJIRAID(title) {
+function detectIssue(title) {
if (!title) {
return null;
}
- const matched = /^(WIP:?\s*)?((ARROW|PARQUET)-\d+)/.exec(title);
- if (!matched) {
- return null;
+ if (title.startsWith("MINOR: ")) {
+ return {"kind": "minor"};
}
- return matched[2];
-}
-
-/**
- * Given the title of a PullRequest checks if it contains a JIRA issue ID
- * @param {String} title
- * @returns {Boolean} true if it starts with a JIRA ID or MINOR:
- */
-function haveJIRAID(title) {
- if (!title) {
- return false;
+ const matched_jira = /^(WIP:?\s*)?((ARROW|PARQUET)-\d+)/.exec(title);
+ if (matched_jira) {
+ return {"kind": "jira", "id": matched_jira[2]};
}
- if (title.startsWith("MINOR: ")) {
- return true;
+ const matched_gh = /^(WIP:?\s*)?GH-(\d+)/.exec(title);
+ if (matched_gh) {
+ return {"kind": "github", "id": matched_gh[2]};
}
- return /^(WIP:?\s*)?(ARROW|PARQUET)-\d+/.test(title);
+ return null;
}
/**
@@ -69,8 +68,27 @@ async function getJiraInfo(jiraID) {
});
}
+/**
+ * Retrieves information about a GitHub issue.
+ * @param {String} issueID
+ * @returns {Object} the information about a GitHub issue.
+ */
+ async function getGitHubInfo(github, context, issueID, pullRequestNumber) {
+ try {
+ const response = await github.issues.get({
+ issue_number: issueID,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ })
+ return response.data
+ } catch (error) {
+ console.log(`${error.name}: ${error.code}`);
+ return false
+ }
+}
+
module.exports = {
- detectJIRAID,
- haveJIRAID,
- getJiraInfo
+ detectIssue,
+ getJiraInfo,
+ getGitHubInfo
};
\ No newline at end of file
diff --git a/.github/workflows/dev_pr/jira_check.js
b/.github/workflows/dev_pr/issue_check.js
similarity index 51%
rename from .github/workflows/dev_pr/jira_check.js
rename to .github/workflows/dev_pr/issue_check.js
index 3c294f8c7a..3dff23f53e 100644
--- a/.github/workflows/dev_pr/jira_check.js
+++ b/.github/workflows/dev_pr/issue_check.js
@@ -17,6 +17,16 @@
const helpers = require("./helpers.js");
+/**
+ * Performs checks on the JIRA Issue:
+ * - The issue is started in JIRA.
+ * - The issue contains components.
+ *
+ * @param {Object} github
+ * @param {Object} context
+ * @param {String} pullRequestNumber
+ * @param {String} jiraID
+ */
async function verifyJIRAIssue(github, context, pullRequestNumber, jiraID) {
const ticketInfo = await helpers.getJiraInfo(jiraID);
if(!ticketInfo["fields"]["components"].length) {
@@ -30,6 +40,13 @@ async function verifyJIRAIssue(github, context,
pullRequestNumber, jiraID) {
}
}
+/**
+ * Adds a comment to add components on the JIRA ticket.
+ *
+ * @param {Object} github
+ * @param {Object} context
+ * @param {String} pullRequestNumber
+ */
async function commentMissingComponents(github, context, pullRequestNumber) {
const {data: comments} = await github.issues.listComments({
owner: context.repo.owner,
@@ -54,6 +71,13 @@ async function commentMissingComponents(github, context,
pullRequestNumber) {
}
}
+/**
+ * Adds a comment to start the ticket in JIRA.
+ *
+ * @param {Object} github
+ * @param {Object} context
+ * @param {String} pullRequestNumber
+ */
async function commentNotStartedTicket(github, context, pullRequestNumber) {
const {data: comments} = await github.issues.listComments({
owner: context.repo.owner,
@@ -78,11 +102,72 @@ async function commentNotStartedTicket(github, context,
pullRequestNumber) {
}
}
+/**
+ * Assigns the Github Issue to the PR creator.
+ *
+ * @param {Object} github
+ * @param {Object} context
+ * @param {String} pullRequestNumber
+ * @param {Object} issueInfo
+ */
+async function assignGitHubIssue(github, context, pullRequestNumber,
issueInfo) {
+ await github.issues.addAssignees({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: issueInfo.number,
+ assignees: context.payload.pull_request.user.login
+ });
+ await github.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: pullRequestNumber,
+ body: ":warning: GitHub issue #" + issueInfo.number + " **has been
automatically assigned in GitHub** to PR creator."
+ });
+}
+
+/**
+ * Performs checks on the GitHub Issue:
+ * - The issue is assigned to someone. If not assign it gets automatically
+ * assigned to the PR creator.
+ * - The issue contains any label.
+ *
+ * @param {Object} github
+ * @param {Object} context
+ * @param {String} pullRequestNumber
+ * @param {String} issueID
+ */
+async function verifyGitHubIssue(github, context, pullRequestNumber, issueID) {
+ const issueInfo = await helpers.getGitHubInfo(github, context, issueID,
pullRequestNumber);
+ if (!issueInfo) {
+ await github.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: pullRequestNumber,
+ body: ":x: GitHub issue #" + issueID + " could not be retrieved."
+ })
+ }
+ if (!issueInfo.assignees.length) {
+ await assignGitHubIssue(github, context, pullRequestNumber, issueInfo);
+ }
+ if(!issueInfo.labels.filter((label) =>
label.name.startsWith("Component:")).length) {
+ await github.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: pullRequestNumber,
+ body: ":warning: GitHub issue #" + issueID + " **has no
components**, please add labels for components."
+ })
+ }
+}
+
module.exports = async ({github, context}) => {
const pullRequestNumber = context.payload.number;
const title = context.payload.pull_request.title;
- const jiraID = helpers.detectJIRAID(title);
- if (jiraID) {
- await verifyJIRAIssue(github, context, pullRequestNumber, jiraID);
+ const issue = helpers.detectIssue(title)
+ if (issue){
+ if (issue.kind == "jira") {
+ await verifyJIRAIssue(github, context, pullRequestNumber,
issue.id);
+ } else if(issue.kind == "github") {
+ await verifyGitHubIssue(github, context, pullRequestNumber,
issue.id);
+ }
}
};
diff --git a/.github/workflows/dev_pr/link.js b/.github/workflows/dev_pr/link.js
index 404ff46436..7d99ca1053 100644
--- a/.github/workflows/dev_pr/link.js
+++ b/.github/workflows/dev_pr/link.js
@@ -18,7 +18,16 @@
const helpers = require("./helpers.js");
-async function haveComment(github, context, pullRequestNumber, body) {
+/**
+ * Checks whether message is present on Pull Request list of comments.
+ *
+ * @param {Object} github
+ * @param {Object} context
+ * @param {String} pullRequestNumber
+ * @param {String} message
+ * @returns {Boolean} true if message was found.
+ */
+async function haveComment(github, context, pullRequestNumber, message) {
const options = {
owner: context.repo.owner,
repo: context.repo.repo,
@@ -27,7 +36,7 @@ async function haveComment(github, context,
pullRequestNumber, body) {
};
while (true) {
const response = await github.issues.listComments(options);
- if (response.data.some(comment => comment.body === body)) {
+ if (response.data.some(comment => comment.body === message)) {
return true;
}
if (!/;\s*rel="next"/.test(response.headers.link || "")) {
@@ -38,24 +47,64 @@ async function haveComment(github, context,
pullRequestNumber, body) {
return false;
}
+/**
+ * Adds a comment on the Pull Request linking the JIRA issue.
+ *
+ * @param {Object} github
+ * @param {Object} context
+ * @param {String} pullRequestNumber
+ * @param {String} jiraID
+ */
async function commentJIRAURL(github, context, pullRequestNumber, jiraID) {
+ const issueInfo = await helpers.getJiraInfo(jiraID);
const jiraURL = `https://issues.apache.org/jira/browse/${jiraID}`;
if (await haveComment(github, context, pullRequestNumber, jiraURL)) {
return;
}
- await github.issues.createComment({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: pullRequestNumber,
- body: jiraURL
- });
+ if (issueInfo){
+ await github.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: pullRequestNumber,
+ body: jiraURL
+ });
+ }
+}
+
+/**
+ * Adds a comment on the Pull Request linking the GitHub issue.
+ *
+ * @param {Object} github
+ * @param {Object} context
+ * @param {String} pullRequestNumber - String containing numeric id of PR
+ * @param {String} issueID - String containing numeric id of the github issue
+ */
+async function commentGitHubURL(github, context, pullRequestNumber, issueID) {
+ // Make the call to ensure issue exists before adding comment
+ const issueInfo = await helpers.getGitHubInfo(github, context, issueID,
pullRequestNumber);
+ const message = "* Github Issue: #" + issueInfo.number
+ if (await haveComment(github, context, pullRequestNumber, message)) {
+ return;
+ }
+ if (issueInfo){
+ await github.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: pullRequestNumber,
+ body: message
+ });
+ }
}
module.exports = async ({github, context}) => {
const pullRequestNumber = context.payload.number;
const title = context.payload.pull_request.title;
- const jiraID = helpers.detectJIRAID(title);
- if (jiraID) {
- await commentJIRAURL(github, context, pullRequestNumber, jiraID);
+ const issue = helpers.detectIssue(title);
+ if (issue){
+ if (issue.kind == "jira") {
+ await commentJIRAURL(github, context, pullRequestNumber, issue.id);
+ } else if (issue.kind == "github") {
+ await commentGitHubURL(github, context, pullRequestNumber, issue.id);
+ }
}
};
diff --git a/.github/workflows/dev_pr/title_check.js
b/.github/workflows/dev_pr/title_check.js
index 392108269d..1b7a6c5c88 100644
--- a/.github/workflows/dev_pr/title_check.js
+++ b/.github/workflows/dev_pr/title_check.js
@@ -18,7 +18,7 @@
const fs = require("fs");
const helpers = require("./helpers.js");
-async function commentOpenJIRAIssue(github, context, pullRequestNumber) {
+async function commentOpenGitHubIssue(github, context, pullRequestNumber) {
const {data: comments} = await github.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
@@ -41,7 +41,8 @@ async function commentOpenJIRAIssue(github, context,
pullRequestNumber) {
module.exports = async ({github, context}) => {
const pullRequestNumber = context.payload.number;
const title = context.payload.pull_request.title;
- if (!helpers.haveJIRAID(title)) {
- await commentOpenJIRAIssue(github, context, pullRequestNumber);
+ const issue = helpers.detectIssue(title)
+ if (!issue) {
+ await commentOpenGitHubIssue(github, context, pullRequestNumber);
}
};
diff --git a/.github/workflows/dev_pr/title_check.md
b/.github/workflows/dev_pr/title_check.md
index 1db9fcf637..589a73aaa8 100644
--- a/.github/workflows/dev_pr/title_check.md
+++ b/.github/workflows/dev_pr/title_check.md
@@ -19,18 +19,23 @@
Thanks for opening a pull request!
-If this is not a [minor
PR](https://github.com/apache/arrow/blob/master/CONTRIBUTING.md#Minor-Fixes).
Could you open an issue for this pull request on JIRA?
https://issues.apache.org/jira/browse/ARROW
+If this is not a [minor
PR](https://github.com/apache/arrow/blob/master/CONTRIBUTING.md#Minor-Fixes).
Could you open an issue for this pull request on GitHub?
https://github.com/apache/arrow/issues/new/choose
-Opening JIRAs ahead of time contributes to the
[Openness](http://theapacheway.com/open/#:~:text=Openness%20allows%20new%20users%20the,must%20happen%20in%20the%20open.)
of the Apache Arrow project.
+Opening GitHub issues ahead of time contributes to the
[Openness](http://theapacheway.com/open/#:~:text=Openness%20allows%20new%20users%20the,must%20happen%20in%20the%20open.)
of the Apache Arrow project.
-Then could you also rename pull request title in the following format?
+Then could you also rename the pull request title in the following format?
- ARROW-${JIRA_ID}: [${COMPONENT}] ${SUMMARY}
+ GH-${GITHUB_ISSUE_ID}: [${COMPONENT}] ${SUMMARY}
or
MINOR: [${COMPONENT}] ${SUMMARY}
+In the case of old issues on JIRA the title also supports:
+
+ ARROW-${JIRA_ISSUE_ID}: [${COMPONENT}] ${SUMMARY}
+ PARQUET-${JIRA_ISSUE_ID}: [${COMPONENT}] ${SUMMARY}
+
See also:
* [Other pull requests](https://github.com/apache/arrow/pulls/)