-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 4212119
Showing
6 changed files
with
297 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
FROM golang:1 | ||
|
||
LABEL "com.github.actions.name"="Issue From Template" | ||
LABEL "com.github.actions.description"="Issue From Template" | ||
LABEL "com.github.actions.icon"="alert-circle" | ||
LABEL "com.github.actions.color"="green" | ||
LABEL "repository"="https://github.com/lowply/issue-from-template" | ||
LABEL "homepage"="https://github.com/lowply/issue-from-template" | ||
LABEL "maintainer"="Sho Mizutani <[email protected]>" | ||
|
||
COPY src src | ||
ENV GO111MODULE=on | ||
WORKDIR /go/src | ||
RUN go build -o ../bin/main | ||
|
||
ADD entrypoint.sh /entrypoint.sh | ||
ENTRYPOINT ["/entrypoint.sh"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# Issue From Template | ||
|
||
This action opens a new issue from an issue template. It parses the template's front matter and the body, then posts [an API request to open an issue](https://developer.github.com/v3/issues/#create-an-issue). Works best with a [scheduled workflow](https://developer.github.com/actions/managing-workflows/creating-and-cancelling-a-workflow/#scheduling-a-workflow) and the [Auto Closer](https://github.com/lowply/auto-closer) action. | ||
|
||
## Environment variables | ||
|
||
- `IFT_TEMPLATE_NAME` (*required*): The name of the issue template. For example, `report.md`. This action will look for the file in the `.github/ISSUE_TEMPLATE` directory. | ||
|
||
## Available template variables | ||
|
||
- `.Year`: Year of the week | ||
- `.WeekStartDate`: Date of Monday of the week | ||
- `.WeekEndDate`: Date of Sunday of the week | ||
- `.WeekNumber`: ISO week number | ||
- `.Dates`: Array of the dates of the week (Can be used as `{{ index .Dates 1 }}` in the template) | ||
|
||
## Template Example | ||
|
||
``` | ||
--- | ||
name: Weekly Report | ||
about: This is an example | ||
title: 'Report on {{ .WeekStartDate }} (Week {{ .WeekNumber }}, {{ .Year }})' | ||
labels: report | ||
assignees: lowply | ||
--- | ||
# This week's updates! | ||
## {{ index .Dates 0 }} MON | ||
## {{ index .Dates 1 }} TUE | ||
## {{ index .Dates 2 }} WED | ||
## {{ index .Dates 3 }} THU | ||
## {{ index .Dates 4 }} FRI | ||
## {{ index .Dates 5 }} SAT | ||
## {{ index .Dates 6 }} SUN | ||
``` | ||
|
||
## Running locally for development | ||
|
||
This is designed to be used as a GitHub Action, but you can also just run it locally with the following env vars: | ||
|
||
``` | ||
export GITHUB_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" | ||
export GITHUB_REPOSITORY="owner/repository" | ||
export GITHUB_WORKSPACE="/path/to/your/local/repository" | ||
export IFT_TEMPLATE_NAME="issue.md" | ||
go run src/main.go | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#!/bin/sh | ||
|
||
if [ -z "$GITHUB_TOKEN" ]; then | ||
echo "GITHUB_TOKEN is missing" | ||
exit 1 | ||
fi | ||
|
||
/go/bin/main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
module github.com/github/Japan | ||
|
||
go 1.12 | ||
|
||
require ( | ||
github.com/jinzhu/now v1.0.0 | ||
github.com/kr/pretty v0.1.0 // indirect | ||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect | ||
gopkg.in/yaml.v2 v2.2.2 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
github.com/jinzhu/now v1.0.0 h1:6WV8LvwPpDhKjo5U9O6b4+xdG/jTXNPwlDme/MTo8Ns= | ||
github.com/jinzhu/now v1.0.0/go.mod h1:oHTiXerJ20+SfYcrdlBO7rzZRJWGwSTQ0iUY2jI6Gfc= | ||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= | ||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= | ||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | ||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= | ||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= | ||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= | ||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,201 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"io/ioutil" | ||
"log" | ||
"net/http" | ||
"os" | ||
"strings" | ||
"text/template" | ||
"time" | ||
|
||
"github.com/jinzhu/now" | ||
yaml "gopkg.in/yaml.v2" | ||
) | ||
|
||
type IssueFromTemplate struct { | ||
Config Config | ||
Issue Issue | ||
} | ||
|
||
type Config struct { | ||
Token string | ||
Repository string | ||
TemplatePath string | ||
ResponseFile string | ||
Endpoint string | ||
} | ||
|
||
type Issue struct { | ||
Title string `json:"title"` | ||
Body string `json:"body"` | ||
Assignees []string `json:"assignees"` | ||
Labels []string `json:"labels"` | ||
} | ||
|
||
func (i *IssueFromTemplate) setConfig() error { | ||
if os.Getenv("GITHUB_TOKEN") == "" { | ||
return errors.New("GITHUB_TOKEN is empty") | ||
} | ||
|
||
if os.Getenv("GITHUB_REPOSITORY") == "" { | ||
return errors.New("GITHUB_REPOSITORY is empty") | ||
} | ||
|
||
if os.Getenv("GITHUB_WORKSPACE") == "" { | ||
return errors.New("GITHUB_WORKSPACE is empty") | ||
} | ||
|
||
if os.Getenv("IFT_TEMPLATE_NAME") == "" { | ||
return errors.New("IFT_TEMPLATE_NAME is empty") | ||
} | ||
|
||
i.Config.TemplatePath = os.Getenv("GITHUB_WORKSPACE") + "/.github/ISSUE_TEMPLATE/" + os.Getenv("IFT_TEMPLATE_NAME") | ||
i.Config.ResponseFile = os.Getenv("HOME") + "/resp.json" | ||
i.Config.Token = os.Getenv("GITHUB_TOKEN") | ||
i.Config.Repository = os.Getenv("GITHUB_REPOSITORY") | ||
i.Config.Endpoint = "https://api.github.com/repos/" + i.Config.Repository + "/issues" | ||
|
||
return nil | ||
} | ||
|
||
func (i *IssueFromTemplate) parseTemplate() (string, error) { | ||
d := &struct { | ||
Year string | ||
WeekStartDate string | ||
WeekEndDate string | ||
WeekNumber string | ||
Dates [7]string | ||
}{} | ||
|
||
now.WeekStartDay = time.Monday | ||
d.Year = now.BeginningOfYear().Format("2006") | ||
d.WeekEndDate = now.EndOfSunday().Format("01/02") | ||
d.WeekStartDate = now.BeginningOfWeek().Format("01/02") | ||
_, isoweek := now.Monday().ISOWeek() | ||
d.WeekNumber = fmt.Sprintf("%02d", isoweek) | ||
for i, _ := range d.Dates { | ||
d.Dates[i] = now.Monday().AddDate(0, 0, i).Format("01/02") | ||
} | ||
|
||
file, err := ioutil.ReadFile(i.Config.TemplatePath) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
t, err := template.New("body").Parse(string(file)) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
b := new(bytes.Buffer) | ||
err = t.Execute(b, d) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return b.String(), nil | ||
} | ||
|
||
func (i IssueFromTemplate) splitAndTrimSpace(s string) []string { | ||
arr := strings.Split(s, ",") | ||
for i := range arr { | ||
arr[i] = strings.TrimSpace(arr[i]) | ||
} | ||
return arr | ||
} | ||
|
||
func (i *IssueFromTemplate) generateIssue() error { | ||
t := &struct { | ||
Name string `yaml:"name"` | ||
About string `yaml:"about"` | ||
Title string `yaml:"title"` | ||
Labels string `yaml:"labels"` | ||
Assignees string `yaml:"assignees"` | ||
}{} | ||
|
||
templateBody, err := i.parseTemplate() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
s := strings.Split(templateBody, "---\n") | ||
|
||
err = yaml.UnmarshalStrict([]byte(s[1]), t) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
i.Issue.Title = t.Title | ||
i.Issue.Body = strings.Replace(s[2], "\n", "", 1) | ||
i.Issue.Assignees = i.splitAndTrimSpace(t.Assignees) | ||
i.Issue.Labels = i.splitAndTrimSpace(t.Labels) | ||
|
||
return nil | ||
} | ||
|
||
func (i IssueFromTemplate) post() error { | ||
d, err := json.Marshal(i.Issue) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
client := &http.Client{} | ||
req, err := http.NewRequest(http.MethodPost, i.Config.Endpoint, bytes.NewReader(d)) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
req.Header.Add("Accept", "application/vnd.github.v3+json") | ||
req.Header.Add("Content-Type", "application/json") | ||
req.Header.Add("Authorization", "token "+i.Config.Token) | ||
|
||
resp, err := client.Do(req) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if resp.StatusCode != 201 { | ||
// Successful response code is 201 Created | ||
return errors.New("Error creating an isue: " + resp.Status) | ||
} | ||
|
||
defer resp.Body.Close() | ||
|
||
fmt.Println("Posted an issue:\n" + string(d)) | ||
|
||
b, err := ioutil.ReadAll(resp.Body) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = ioutil.WriteFile(i.Config.ResponseFile, b, 0644) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func main() { | ||
i := IssueFromTemplate{} | ||
|
||
err := i.setConfig() | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
err = i.generateIssue() | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
err = i.post() | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
} |