Skip to content

Commit 3761d4b

Browse files
committed
Support pull requests
1 parent c2887dd commit 3761d4b

File tree

6 files changed

+647
-76
lines changed

6 files changed

+647
-76
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
name: Add a new GitHub issue to a designate project column
2-
on: issues
1+
name: Add a new GitHub Project card linked to a GitHub issue to a specified project column
2+
on: [issues, pull_request]
33
jobs:
44
add-new-issues-to-project-column:
55
runs-on: ubuntu-latest
66
steps:
7-
- uses: actions/checkout@master
8-
- name: add-new-issues-to-project-column
9-
uses: ./
7+
- name: add-new-issues-to-repository-based-project-column
8+
uses: docker://takanabe/add-new-issues-to-project-column:v0.0.1
9+
if: github.event_name == 'issues' && github.event.action == 'opened
1010
env:
1111
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1212
GITHUB_PROJECT_URL: https://github.com/takanabe/add-new-issues-to-project-column/projects/1
13-
GITHUB_PROJECT_COLUMN_NAME: To do
14-
DEBUG: true
13+
GITHUB_PROJECT_COLUMN_NAME: To do

README.md

+23-3
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,21 @@ For any type of GitHub Projects, you need to change `GITHUB_PROJECT_URL` and `GI
1515

1616
```yml
1717
name: Add a new GitHub Project card linked to a GitHub issue to a specified project column
18-
on: issues
18+
on: [issues, pull_request]
1919
jobs:
2020
add-new-issues-to-project-column:
2121
runs-on: ubuntu-latest
2222
steps:
2323
- name: add-new-issues-to-repository-based-project-column
2424
uses: docker://takanabe/add-new-issues-to-project-column:v0.0.1
25+
if: github.event_name == 'issues' && github.event.action == 'opened'
26+
env:
27+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
28+
GITHUB_PROJECT_URL: https://github.com/takanabe/add-new-issues-to-project-column/projects/1
29+
GITHUB_PROJECT_COLUMN_NAME: To do
30+
- name: add-new-prs-to-repository-based-project-column
31+
uses: docker://takanabe/add-new-issues-to-project-column:v0.0.1
32+
if: github.event_name == 'pull_request' && github.event.action == 'opened'
2533
env:
2634
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2735
GITHUB_PROJECT_URL: https://github.com/takanabe/add-new-issues-to-project-column/projects/1
@@ -35,17 +43,18 @@ jobs:
3543

3644
```yml
3745
name: Add a new GitHub issue to a designate project column
38-
on: issues
46+
on: [issues, pull_request]
3947
jobs:
4048
add-new-issues-to-project-column:
4149
runs-on: ubuntu-latest
4250
steps:
4351
- name: add-new-issues-to-organization-based-project-column
4452
uses: docker://takanabe/add-new-issues-to-project-column:v0.0.1
53+
if: github.event_name == 'issues' && github.event.action == 'opened'
4554
env:
4655
GITHUB_TOKEN: ${{ secrets.GITHUB_PERSONAL_TOKEN_TO_ADD_PROJECT }}
4756
GITHUB_PROJECT_URL: https://github.com/orgs/organization_name/projects/1
48-
GITHUB_PROJECT_COLUMN_NAME: test
57+
GITHUB_PROJECT_COLUMN_NAME: To Do
4958
```
5059

5160
1. Replace the URL set on `GITHUB_PROJECT_URL` to the URL of your repository project to place issues
@@ -59,6 +68,8 @@ jobs:
5968

6069
User-based project is not supported yet
6170

71+
## Configurations
72+
6273
### Environment variables
6374

6475
| Environment variable | Value | Description |
@@ -68,6 +79,15 @@ User-based project is not supported yet
6879
| GITHUB_PROJECT_COLUMN_NAME | Anything (e.g: To Do) | A GitHub Project column name you want to place new issues |
6980
| DEBUG | Anything (e.g: true) | A flag to produce debug messages for this GitHub Actions if this environment variable exists |
7081

82+
### Condition with contexts
83+
84+
You can easily detect [event contexts](https://help.github.com/en/articles/contexts-and-expression-syntax-for-github-actions#github-context) and use them in if statements. Here are some lists of the useful contexts for this GitHub action.
85+
86+
| Property name | Values | Description |
87+
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
88+
| github.event.action | opened, closed, edited, and so on | The name of actions (references for [issues](https://developer.github.com/v3/activity/events/types/#issuesevent) and for [pull_request](https://developer.github.com/v3/activity/events/types/#pullrequestevent) |
89+
| github.event_name | [issues](https://developer.github.com/v3/activity/events/types/#webhook-event-name-19), [pull_quests](https://developer.github.com/v3/activity/events/types/#webhook-event-name-33) | The name of the event that triggered the workflow run |
90+
7191
## Development
7292

7393
### Build Docker image and update DockerHub

issues.go

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"io/ioutil"
6+
"os"
7+
"path/filepath"
8+
9+
"github.com/google/go-github/v25/github"
10+
"github.com/pkg/errors"
11+
)
12+
13+
// issueEventPayload returns GitHub issue event payload kept in the payload file .
14+
// GITHUB_EVENT_PATH keeps the path to the file that contains the payload of the event that triggered the workflow.
15+
// See: https://developer.github.com/actions/creating-github-actions/accessing-the-runtime-environment/#environment-variables
16+
func issueEventPayload() github.IssuesEvent {
17+
var jsonFilePath string
18+
_, ok := os.LookupEnv("GITHUB_ACTION_LOCAL")
19+
if ok {
20+
// Use local test payload
21+
// https://developer.github.com/v3/activity/events/types/#issuesevent
22+
var err error
23+
jsonFilePath, err = filepath.Abs("./payload/issue_event.json")
24+
if err != nil {
25+
errorLog(err)
26+
}
27+
} else {
28+
jsonFilePath = os.Getenv("GITHUB_EVENT_PATH")
29+
}
30+
jsonFile, err := os.Open(jsonFilePath)
31+
if err != nil {
32+
errorLog(errors.Wrap(err, "Failed to open json"))
33+
}
34+
defer jsonFile.Close()
35+
36+
// read opened jsonFile as a byte array.
37+
jsonByte, err := ioutil.ReadAll(jsonFile)
38+
if err != nil {
39+
errorLog(errors.Wrap(err, "Failed to read json as a byte array"))
40+
}
41+
42+
payload := github.IssuesEvent{}
43+
err = json.Unmarshal(jsonByte, &payload)
44+
if err != nil {
45+
errorLog(errors.Wrap(err, "Failed to unmarshal JSON to Go Object"))
46+
}
47+
if payload.GetAction() != "opened" {
48+
infoLog("GitHub action interupts!!")
49+
infoLog("This issue is not new one :D")
50+
os.Exit(0)
51+
}
52+
53+
return payload
54+
}
55+
56+
// extractIssueID returns GitHub issue ID extracted from event payloads
57+
func extractIssueID(payload github.IssuesEvent) (int64, error) {
58+
59+
issueID := payload.GetIssue().GetID()
60+
61+
if issueID == 0 {
62+
return 0, errors.New("Issue ID is 0. Failed to get issue id properly")
63+
}
64+
65+
return issueID, nil
66+
}

main.go

+40-66
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,9 @@ package main
22

33
import (
44
"context"
5-
"encoding/json"
6-
"fmt"
7-
"io/ioutil"
8-
"log"
95
"net/http"
106
"net/url"
117
"os"
12-
"path/filepath"
138
"regexp"
149
"strings"
1510

@@ -19,17 +14,37 @@ import (
1914
)
2015

2116
func main() {
22-
payload := issueEventPayload()
17+
// Event name is kept in GITHUB_EVENT_NAME
18+
// https://help.github.com/en/articles/virtual-environments-for-github-actions#default-environment-variables
19+
eventName := os.Getenv("GITHUB_EVENT_NAME")
20+
infoLog("Event name: %s\n", eventName)
21+
if !(eventName == "issues" || eventName == "pull_request") {
22+
infoLog("This GitHub event is neither issues nor pull_requests. Stop executing this action.")
23+
infoLog("Please add 'if github.event_name' to the workflow yaml by following https://github.com/takanabe/add-new-issues-to-project-column/blob/master/README.md ")
24+
os.Exit(0)
25+
}
2326

24-
issueID := extractIssueID(payload)
25-
infoLog("New issue is found!!")
26-
debugLog("Issue ID: %d\n", issueID)
27+
// eventID stores issue ID or pull-request ID
28+
var eventID int64
29+
var err error
30+
if eventName == "issues" {
31+
payload := issueEventPayload()
32+
eventID, err = extractIssueID(payload)
33+
errCheck(err)
34+
} else if eventName == "pull_request" {
35+
payload := pullRequestEventPayload()
36+
eventID, err = extractPullRequestID(payload)
37+
errCheck(err)
38+
}
39+
40+
infoLog("Payload for %s extract correctly", eventName)
41+
debugLog("Target event ID: %d\n", eventID)
2742

2843
client, ctx := getGitHubClient()
2944

3045
url := os.Getenv("GITHUB_PROJECT_URL")
3146
if url == "" {
32-
log.Println("[ERROR] Environment variable GITHUB_PROJECT_URL is not defined in your workflow file")
47+
errorLog(errors.New("Environment variable GITHUB_PROJECT_URL is not defined in your workflow file"))
3348
os.Exit(1)
3449
}
3550

@@ -49,14 +64,14 @@ func main() {
4964
pjID, err = projectIDByOrg(ctx, client, url, parentName)
5065
errCheck(err)
5166
} else if pjType == "user" {
52-
log.Println("[ERROR] User project is not supported yet")
67+
errorLog(errors.New("User project is not supported yet"))
5368
os.Exit(1)
5469
}
5570
infoLog("Project type:%s\n", pjType)
5671

5772
pjColumn := os.Getenv("GITHUB_PROJECT_COLUMN_NAME")
5873
if pjColumn == "" {
59-
log.Println("[ERROR] Environment variable PROJECT_COLUMN_NAME is not defined in your workflow file")
74+
errorLog(errors.New("Environment variable PROJECT_COLUMN_NAME is not defined in your workflow file"))
6075
os.Exit(1)
6176
}
6277

@@ -68,59 +83,12 @@ func main() {
6883
////
6984
// Add a new opened issue to a designate project column
7085
////
71-
err = addIssueToProject(ctx, client, issueID, columnID)
86+
err = addToProject(ctx, client, eventID, columnID, eventName)
7287
errCheck(err)
7388

7489
os.Exit(0)
7590
}
7691

77-
// issueEventPayload returns GitHub issue event payload kept in the payload file .
78-
// GITHUB_EVENT_PATH keeps the path to the file that contains the payload of the event that triggered the workflow.
79-
// See: https://developer.github.com/actions/creating-github-actions/accessing-the-runtime-environment/#environment-variables
80-
func issueEventPayload() github.IssuesEvent {
81-
var jsonFilePath string
82-
_, ok := os.LookupEnv("GITHUB_ACTION_LOCAL")
83-
if ok {
84-
// Use local test payload
85-
// https://developer.github.com/v3/activity/events/types/#issuesevent
86-
var err error
87-
jsonFilePath, err = filepath.Abs("./payload/issue_event.json")
88-
if err != nil {
89-
log.Fatalf("[ERROR] No such a file: %e", err)
90-
}
91-
} else {
92-
jsonFilePath = os.Getenv("GITHUB_EVENT_PATH")
93-
}
94-
jsonFile, err := os.Open(jsonFilePath)
95-
if err != nil {
96-
log.Fatalf("[ERROR] Failed to open json: %e", err)
97-
}
98-
defer jsonFile.Close()
99-
100-
// read opened jsonFile as a byte array.
101-
jsonByte, err := ioutil.ReadAll(jsonFile)
102-
if err != nil {
103-
log.Fatalf("[ERROR] Failed to read json as a byte array: %e", err)
104-
}
105-
106-
payload := github.IssuesEvent{}
107-
err = json.Unmarshal(jsonByte, &payload)
108-
if err != nil {
109-
log.Fatalf("[ERROR] Failed to unmarshal JSON to Go Object: %e", err)
110-
}
111-
if payload.GetAction() != "opened" {
112-
fmt.Println("GitHub action interupts!!")
113-
fmt.Println("This issue is not new one :D")
114-
os.Exit(0)
115-
}
116-
return payload
117-
}
118-
119-
// extractIssueID returns GitHub issue ID extracted from event payloads
120-
func extractIssueID(payload github.IssuesEvent) int64 {
121-
return payload.GetIssue().GetID()
122-
}
123-
12492
func getGitHubClient() (*github.Client, context.Context) {
12593
ctx := context.Background()
12694
ts := oauth2.StaticTokenSource(
@@ -219,7 +187,7 @@ func projectIDByOrg(ctx context.Context, client *github.Client, url, org string)
219187
for _, project := range projects {
220188
if project.GetHTMLURL() == url {
221189
projectID = project.GetID()
222-
fmt.Println("Project Name: " + project.GetName())
190+
infoLog("Project Name: " + project.GetName())
223191
infoLog("Project ID: %d\n", projectID)
224192
break
225193
}
@@ -255,11 +223,17 @@ func projectColumnID(ctx context.Context, client *github.Client, pjID int64, pjC
255223
return columnID, nil
256224
}
257225

258-
func addIssueToProject(ctx context.Context, client *github.Client, issueID int64, columnID int64) error {
259-
opt := &github.ProjectCardOptions{
260-
ContentID: issueID,
261-
ContentType: "Issue",
226+
func addToProject(ctx context.Context, client *github.Client, eventID, columnID int64, eventName string) error {
227+
opt := &github.ProjectCardOptions{}
228+
229+
if eventName == "issues" {
230+
opt.ContentID = eventID
231+
opt.ContentType = "Issue"
232+
} else if eventName == "pull_request" {
233+
opt.ContentID = eventID
234+
opt.ContentType = "PullRequest"
262235
}
236+
263237
card, res, err := client.Projects.CreateProjectCard(ctx, columnID, opt)
264238

265239
err = validateGitHubResponse(res, err)
@@ -271,7 +245,7 @@ func addIssueToProject(ctx context.Context, client *github.Client, issueID int64
271245
return errors.New("Failed to create a card")
272246
}
273247

274-
infoLog("Created card %d! issue %d is placed to ColumnID %d", card.GetID(), issueID, columnID)
248+
infoLog("Created card %d! issue %d is placed to ColumnID %d", card.GetID(), eventID, columnID)
275249
return nil
276250
}
277251

0 commit comments

Comments
 (0)