Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
lowply committed May 15, 2019
0 parents commit 4212119
Show file tree
Hide file tree
Showing 6 changed files with 297 additions and 0 deletions.
17 changes: 17 additions & 0 deletions Dockerfile
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"]
49 changes: 49 additions & 0 deletions README.md
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
```
8 changes: 8 additions & 0 deletions entrypoint.sh
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
10 changes: 10 additions & 0 deletions src/go.mod
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
)
12 changes: 12 additions & 0 deletions src/go.sum
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=
201 changes: 201 additions & 0 deletions src/main.go
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)
}
}

0 comments on commit 4212119

Please sign in to comment.