Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 15 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ Flags:
--github-token GitHub API token (or env var GITHUB_TOKEN)
--interval update interval (ex. 5ms, 10s, 1m, 3h) (default: 1m0s)
--once run once and exit, do not run as a daemon (default: false)
--verbose-keys include title data in keys
--orgs organizations to include (this option only applies to --autofill) (default: [])
--watch-since defines the starting point of the issues been watched (format: 2006-01-02T15:04:05Z). defaults to no filter (default: 2008-01-01T00:00:00Z)
--watched include the watched repositories (default: false)
Expand All @@ -84,19 +85,20 @@ Commands:

Your airtable table must have the following fields:

- `reference` **(single line text)**
- `title` **(single line text)**
- `type` **(single select)**
- `state` **(single line text)**
- `author` **(single line text)**
- `labels` **(multiple select)**
- `comments` **(number)**
- `url` **(url)**
- `updated` **(date, include time)**
- `created` **(date, include time)**
- `completed` **(date, include time)**
- `project` **(link to another sheet)**
- `repository` **(single line text)**
- `Reference` **(single line text)**
- `Title` **(single line text)**
- `Body` **(single line text)**
- `Type` **(single select)**
- `State` **(single select)**
- `Author` **(single line text)**
- `Labels` **(multiple select)**
- `Comments` **(number)**
- `URL` **(url)**
- `Updated` **(date, include time)**
- `Created` **(date, include time)**
- `Completed` **(date, include time)**
- `Project` **(link to another sheet)**
- `Repository` **(single line text)**

The only data you need to initialize **(if not running with `--autofill`)**
is the `Reference` which is in the format
Expand Down
36 changes: 29 additions & 7 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,18 @@ import (

"golang.org/x/oauth2"

airtable "github.com/fabioberger/airtable-go"
airtable "github.com/iwoj/airtable-go"
"github.com/genuinetools/pkg/cli"
"github.com/google/go-github/github"
"github.com/jessfraz/gitable/version"
"github.com/sirupsen/logrus"
)

var (
interval time.Duration
autofill bool
once bool
interval time.Duration
autofill bool
verboseKeys bool
once bool

githubToken string
orgs stringSlice
Expand Down Expand Up @@ -64,6 +65,7 @@ func main() {
p.FlagSet = flag.NewFlagSet("global", flag.ExitOnError)
p.FlagSet.DurationVar(&interval, "interval", time.Minute, "update interval (ex. 5ms, 10s, 1m, 3h)")
p.FlagSet.BoolVar(&autofill, "autofill", false, "autofill all pull requests and issues for a user [or orgs] to a table (defaults to current user unless --orgs is set)")
p.FlagSet.BoolVar(&verboseKeys, "verbose-keys", false, "include title data in keys")
p.FlagSet.BoolVar(&once, "once", false, "run once and exit, do not run as a daemon")

p.FlagSet.StringVar(&githubToken, "github-token", os.Getenv("GITHUB_TOKEN"), "GitHub API token (or env var GITHUB_TOKEN)")
Expand Down Expand Up @@ -196,12 +198,14 @@ type bot struct {
type githubRecord struct {
ID string `json:"id,omitempty"`
Fields Fields `json:"fields,omitempty"`
Typecast bool `json:"typecast,omitempty"`
}

// Fields defines the airtable fields for the data.
type Fields struct {
Reference string
Title string
Body string
State string
Author string
Type string
Expand Down Expand Up @@ -345,6 +349,7 @@ func (bot *bot) applyRecordToTable(ctx context.Context, issue *github.Issue, key
Fields: Fields{
Reference: key,
Title: issue.GetTitle(),
Body: issue.GetBody(),
State: issue.GetState(),
Author: issue.GetUser().GetLogin(),
Type: issueType,
Expand All @@ -355,12 +360,14 @@ func (bot *bot) applyRecordToTable(ctx context.Context, issue *github.Issue, key
Completed: issue.GetClosedAt(),
Repository: repo,
},
Typecast: true,
}

// Update the record fields.
fields := map[string]interface{}{
"Reference": record.Fields.Reference,
"Title": record.Fields.Title,
"Body": record.Fields.Body,
"State": record.Fields.State,
"Author": record.Fields.Author,
"Type": record.Fields.Type,
Expand All @@ -375,7 +382,7 @@ func (bot *bot) applyRecordToTable(ctx context.Context, issue *github.Issue, key
if id != "" {
// If we were passed a record ID, update the record instead of create.
logrus.Debugf("updating record %s for issue %s", id, key)
if err := bot.airtableClient.UpdateRecord(airtableTableName, id, fields, &record); err != nil {
if err := bot.airtableClient.UpdateRecord(airtableTableName, id, fields, &record, true); err != nil {
logrus.Warnf("updating record %s for issue %s failed: %v", id, key, err)
return nil
}
Expand All @@ -390,7 +397,7 @@ func (bot *bot) applyRecordToTable(ctx context.Context, issue *github.Issue, key
// Try again with labels, since the user may not have pre-populated the label options.
// TODO: add a create multiple select when the airtable API supports it.
fields["Labels"] = labels
if err := bot.airtableClient.UpdateRecord(airtableTableName, record.ID, fields, &record); err != nil {
if err := bot.airtableClient.UpdateRecord(airtableTableName, record.ID, fields, &record, true); err != nil {
logrus.Warnf("updating record with labels %s for issue %s failed: %v", record.ID, key, err)
}

Expand All @@ -415,10 +422,18 @@ func (bot *bot) getRepositories(ctx context.Context, page, perPage int, affiliat
if in(orgs, repo.GetOwner().GetLogin()) {
logrus.Debugf("getting issues for repo %s...", repo.GetFullName())
ipage := 0
if err := bot.getIssues(ctx, ipage, perPage, repo.GetOwner().GetLogin(), repo.GetName(), repo.UpdatedAt.Time); err != nil {
since, err := time.Parse("2006-01-02T15:04:05Z", "1900-01-02T15:04:05Z")
if err != nil {
return err
}
if !autofill {
since = repo.UpdatedAt.Time
}
if err := bot.getIssues(ctx, ipage, perPage, repo.GetOwner().GetLogin(), repo.GetName(), since); err != nil {
logrus.Debugf("Failed to get issues for repo %s - %v\n", repo.GetName(), err)
return err
}
logrus.Debugf("Total issues: %d...", len(bot.issues))
}
}

Expand Down Expand Up @@ -478,6 +493,10 @@ func (bot *bot) getIssues(ctx context.Context, page, perPage int, owner, repo st
for _, issue := range issues {
key := fmt.Sprintf("%s/%s#%d", owner, repo, issue.GetNumber())

if verboseKeys {
key = fmt.Sprintf("%s/%s#%d - %s", owner, repo, issue.GetNumber(), issue.GetTitle())
}

// logrus.Debugf("handling issue %s...", key)
bot.issues[key] = issue
}
Expand All @@ -494,6 +513,9 @@ func (bot *bot) getIssues(ctx context.Context, page, perPage int, owner, repo st
func parseReference(ref string) (string, string, int, error) {
// Split the reference into repository and issue number.
parts := strings.SplitN(ref, "#", 2)
verboseParts := strings.SplitN(parts[1], " - ", 2)
parts[1] = verboseParts[0]

if len(parts) < 2 {
return "", "", 0, fmt.Errorf("could not parse reference name into repository and issue number for %s, got: %#v", ref, parts)
}
Expand Down