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/)

Reply via email to