mirror of
https://github.com/samsonjs/retrogit.git
synced 2026-03-25 09:25:49 +00:00
Changes necessary to run with the Go 1.11 App Engine runtime.
This commit is contained in:
parent
eb7efc60bc
commit
6c662e2109
14 changed files with 118 additions and 99 deletions
|
|
@ -1,6 +1,6 @@
|
|||
# RetroGit
|
||||
|
||||
Service that shows you your GitHub commits from a year ago. Includes a mail digest to that you can see each day what you were up to in the past.
|
||||
Service that shows you your GitHub commits from previous years. Includes a mail digest to that you can see each day what you were up to in the past.
|
||||
|
||||
It's currently running at [https://www.retrogit.com/](https://www.retrogit.com/).
|
||||
|
||||
|
|
@ -21,5 +21,5 @@ The server can the be accessed at [http://localhost:8080/](http://localhost:8080
|
|||
## Deploying to App Engine
|
||||
|
||||
```
|
||||
gcloud app deploy --project retrogit app/app.yaml
|
||||
./deploy.sh
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
package retrogit
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/gob"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"appengine"
|
||||
"appengine/datastore"
|
||||
"google.golang.org/appengine/datastore"
|
||||
|
||||
"code.google.com/p/goauth2/oauth"
|
||||
"github.com/google/go-github/github"
|
||||
|
|
@ -28,7 +28,7 @@ type Account struct {
|
|||
WeeklyDay time.Weekday
|
||||
}
|
||||
|
||||
func getAccount(c appengine.Context, githubUserId int) (*Account, error) {
|
||||
func getAccount(c context.Context, githubUserId int) (*Account, error) {
|
||||
key := datastore.NewKey(c, "Account", "", int64(githubUserId), nil)
|
||||
account := new(Account)
|
||||
err := datastore.Get(c, key, account)
|
||||
|
|
@ -63,7 +63,7 @@ func initAccount(account *Account) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func getAllAccounts(c appengine.Context) ([]Account, error) {
|
||||
func getAllAccounts(c context.Context) ([]Account, error) {
|
||||
q := datastore.NewQuery("Account")
|
||||
var accounts []Account
|
||||
_, err := q.GetAll(c, &accounts)
|
||||
|
|
@ -88,7 +88,7 @@ func (account *Account) IsRepoIdExcluded(repoId int) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (account *Account) Put(c appengine.Context) error {
|
||||
func (account *Account) Put(c context.Context) error {
|
||||
w := new(bytes.Buffer)
|
||||
err := gob.NewEncoder(w).Encode(&account.OAuthToken)
|
||||
if err != nil {
|
||||
|
|
@ -100,7 +100,7 @@ func (account *Account) Put(c appengine.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (account *Account) Delete(c appengine.Context) error {
|
||||
func (account *Account) Delete(c context.Context) error {
|
||||
key := datastore.NewKey(c, "Account", "", int64(account.GitHubUserId), nil)
|
||||
err := datastore.Delete(c, key)
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
package retrogit
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"appengine"
|
||||
"google.golang.org/appengine"
|
||||
|
||||
"github.com/google/go-github/github"
|
||||
)
|
||||
|
|
|
|||
31
app/app.go
31
app/app.go
|
|
@ -1,4 +1,4 @@
|
|||
package retrogit
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
|
@ -6,13 +6,14 @@ import (
|
|||
"fmt"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
log_ "log"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"appengine"
|
||||
"appengine/mail"
|
||||
"google.golang.org/appengine"
|
||||
"google.golang.org/appengine/log"
|
||||
"google.golang.org/appengine/mail"
|
||||
|
||||
"github.com/google/go-github/github"
|
||||
"github.com/gorilla/sessions"
|
||||
|
|
@ -208,14 +209,14 @@ func handleAppError(e *AppError, w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
} else {
|
||||
c.Errorf("GitHub fetch error was not of type github.ErrorResponse")
|
||||
log.Errorf(c, "GitHub fetch error was not of type github.ErrorResponse")
|
||||
}
|
||||
} else if e.Type == AppErrorTypeRedirect {
|
||||
http.Redirect(w, r, e.Message, e.Code)
|
||||
return
|
||||
}
|
||||
if e.Type != AppErrorTypeBadInput {
|
||||
c.Errorf("%v", e.Error)
|
||||
log.Errorf(c, "%v", e.Error)
|
||||
if !appengine.IsDevAppServer() {
|
||||
sendAppErrorMail(e, r)
|
||||
}
|
||||
|
|
@ -226,11 +227,11 @@ func handleAppError(e *AppError, w http.ResponseWriter, r *http.Request) {
|
|||
w.WriteHeader(e.Code)
|
||||
templateError := templates["internal-error"].Render(w, data)
|
||||
if templateError != nil {
|
||||
c.Errorf("Error %s rendering error template.", templateError.Error.Error())
|
||||
log.Errorf(c, "Error %s rendering error template.", templateError.Error.Error())
|
||||
}
|
||||
return
|
||||
} else {
|
||||
c.Infof("%v", e.Error)
|
||||
log.Infof(c, "%v", e.Error)
|
||||
}
|
||||
http.Error(w, e.Message, e.Code)
|
||||
}
|
||||
|
|
@ -260,7 +261,7 @@ Error: %s`,
|
|||
c := appengine.NewContext(r)
|
||||
err := mail.Send(c, errorMessage)
|
||||
if err != nil {
|
||||
c.Errorf("Error %s sending error email.", err.Error())
|
||||
log.Errorf(c, "Error %s sending error email.", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -323,11 +324,11 @@ func loadTemplates() (templates map[string]*Template) {
|
|||
}
|
||||
sharedFileNames, err := filepath.Glob("templates/shared/*.html")
|
||||
if err != nil {
|
||||
log.Panicf("Could not read shared template file names %s", err.Error())
|
||||
log_.Panicf("Could not read shared template file names %s", err.Error())
|
||||
}
|
||||
templateFileNames, err := filepath.Glob("templates/*.html")
|
||||
if err != nil {
|
||||
log.Panicf("Could not read template file names %s", err.Error())
|
||||
log_.Panicf("Could not read template file names %s", err.Error())
|
||||
}
|
||||
templates = make(map[string]*Template)
|
||||
for _, templateFileName := range templateFileNames {
|
||||
|
|
@ -344,7 +345,7 @@ func loadTemplates() (templates map[string]*Template) {
|
|||
_, templateFileName = filepath.Split(fileNames[0])
|
||||
parsedTemplate, err := template.New(templateFileName).Funcs(funcMap).ParseFiles(fileNames...)
|
||||
if err != nil {
|
||||
log.Printf("Could not parse template files for %s: %s", templateFileName, err.Error())
|
||||
log_.Printf("Could not parse template files for %s: %s", templateFileName, err.Error())
|
||||
}
|
||||
templates[templateName] = &Template{parsedTemplate}
|
||||
}
|
||||
|
|
@ -354,13 +355,13 @@ func loadTemplates() (templates map[string]*Template) {
|
|||
func loadStyles() (result map[string]template.CSS) {
|
||||
stylesBytes, err := ioutil.ReadFile("config/styles.json")
|
||||
if err != nil {
|
||||
log.Panicf("Could not read styles JSON: %s", err.Error())
|
||||
log_.Panicf("Could not read styles JSON: %s", err.Error())
|
||||
}
|
||||
var stylesJson interface{}
|
||||
err = json.Unmarshal(stylesBytes, &stylesJson)
|
||||
result = make(map[string]template.CSS)
|
||||
if err != nil {
|
||||
log.Printf("Could not parse styles JSON %s: %s", stylesBytes, err.Error())
|
||||
log_.Printf("Could not parse styles JSON %s: %s", stylesBytes, err.Error())
|
||||
return
|
||||
}
|
||||
var parse func(string, map[string]interface{}, *string)
|
||||
|
|
@ -377,7 +378,7 @@ func loadStyles() (result map[string]template.CSS) {
|
|||
parse(path+k, v.(map[string]interface{}), &nestedStyle)
|
||||
result[path+k] = template.CSS(nestedStyle)
|
||||
default:
|
||||
log.Printf("Unexpected type for %s in styles JSON, ignoring", k)
|
||||
log_.Printf("Unexpected type for %s in styles JSON, ignoring", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
runtime: go
|
||||
api_version: go1
|
||||
runtime: go111
|
||||
|
||||
handlers:
|
||||
- url: /static
|
||||
|
|
@ -11,11 +10,11 @@ handlers:
|
|||
static_files: static/robots.txt
|
||||
upload: static/robots.txt
|
||||
- url: /digest/cron
|
||||
script: _go_app
|
||||
script: auto
|
||||
login: admin
|
||||
- url: /admin/.*
|
||||
script: _go_app
|
||||
script: auto
|
||||
login: admin
|
||||
- url: /.*
|
||||
script: _go_app
|
||||
script: auto
|
||||
secure: always
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
package retrogit
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"io"
|
||||
|
|
@ -11,8 +12,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"appengine"
|
||||
"appengine/memcache"
|
||||
"google.golang.org/appengine/log"
|
||||
"google.golang.org/appengine/memcache"
|
||||
)
|
||||
|
||||
// Simple http.RoundTripper implementation which wraps an existing transport and
|
||||
|
|
@ -20,7 +21,7 @@ import (
|
|||
// iteration cycle during development.
|
||||
type CachingTransport struct {
|
||||
Transport http.RoundTripper
|
||||
Context appengine.Context
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
func (t *CachingTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
|
||||
|
|
@ -50,7 +51,7 @@ func (t *CachingTransport) RoundTrip(req *http.Request) (resp *http.Response, er
|
|||
|
||||
cachedRespItem, err := memcache.Get(t.Context, cacheKey)
|
||||
if err != nil && err != memcache.ErrCacheMiss {
|
||||
t.Context.Errorf("Error getting cached response: %v", err)
|
||||
log.Errorf(t.Context, "Error getting cached response: %v", err)
|
||||
return t.Transport.RoundTrip(req)
|
||||
}
|
||||
if err == nil {
|
||||
|
|
@ -59,17 +60,17 @@ func (t *CachingTransport) RoundTrip(req *http.Request) (resp *http.Response, er
|
|||
if err == nil {
|
||||
return resp, nil
|
||||
} else {
|
||||
t.Context.Errorf("Error readings bytes for cached response: %v", err)
|
||||
log.Errorf(t.Context, "Error readings bytes for cached response: %v", err)
|
||||
}
|
||||
}
|
||||
t.Context.Infof("Fetching %s", req.URL)
|
||||
log.Infof(t.Context, "Fetching %s", req.URL)
|
||||
resp, err = t.Transport.RoundTrip(req)
|
||||
if err != nil || resp.StatusCode != 200 {
|
||||
return
|
||||
}
|
||||
respBytes, err := httputil.DumpResponse(resp, true)
|
||||
if err != nil {
|
||||
t.Context.Errorf("Error dumping bytes for cached response: %v", err)
|
||||
log.Errorf(t.Context, "Error dumping bytes for cached response: %v", err)
|
||||
return resp, nil
|
||||
}
|
||||
var expiration time.Duration = time.Hour
|
||||
|
|
@ -86,7 +87,7 @@ func (t *CachingTransport) RoundTrip(req *http.Request) (resp *http.Response, er
|
|||
Expiration: expiration,
|
||||
})
|
||||
if err != nil {
|
||||
t.Context.Errorf("Error setting cached response for %s (cache key %s, %d bytes to cache): %v",
|
||||
log.Errorf(t.Context, "Error setting cached response for %s (cache key %s, %d bytes to cache): %v",
|
||||
req.URL, cacheKey, len(respBytes), err)
|
||||
}
|
||||
return resp, nil
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
package retrogit
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"appengine"
|
||||
"google.golang.org/appengine/log"
|
||||
|
||||
"github.com/google/go-github/github"
|
||||
)
|
||||
|
|
@ -171,7 +172,7 @@ type Digest struct {
|
|||
RepoErrors map[string]error
|
||||
}
|
||||
|
||||
func newDigest(c appengine.Context, githubClient *github.Client, account *Account) (*Digest, error) {
|
||||
func newDigest(c context.Context, githubClient *github.Client, account *Account) (*Digest, error) {
|
||||
user, _, err := githubClient.Users.Get("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -225,7 +226,7 @@ func newDigest(c appengine.Context, githubClient *github.Client, account *Accoun
|
|||
|
||||
digest.fetch(githubClient)
|
||||
for repoFullName, err := range digest.RepoErrors {
|
||||
c.Errorf("Error fetching %s: %s", repoFullName, err.Error())
|
||||
log.Errorf(c, "Error fetching %s: %s", repoFullName, err.Error())
|
||||
}
|
||||
return digest, nil
|
||||
}
|
||||
|
|
|
|||
2
app/index.yaml
Normal file
2
app/index.yaml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
indexes:
|
||||
# AUTOGENERATED
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package retrogit
|
||||
package main
|
||||
|
||||
// From Martini's recovery package:
|
||||
// https://github.com/go-martini/martini/blob/master/recovery.go
|
||||
|
|
|
|||
38
app/repos.go
38
app/repos.go
|
|
@ -1,13 +1,15 @@
|
|||
package retrogit
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"appengine"
|
||||
"appengine/datastore"
|
||||
"appengine/delay"
|
||||
"appengine/taskqueue"
|
||||
"google.golang.org/appengine"
|
||||
"google.golang.org/appengine/datastore"
|
||||
"google.golang.org/appengine/delay"
|
||||
"google.golang.org/appengine/log"
|
||||
"google.golang.org/appengine/taskqueue"
|
||||
|
||||
"github.com/google/go-github/github"
|
||||
)
|
||||
|
|
@ -23,16 +25,16 @@ type RepoVintage struct {
|
|||
Vintage time.Time `datastore:",noindex"`
|
||||
}
|
||||
|
||||
func getVintageKey(c appengine.Context, userId int, repoId int) *datastore.Key {
|
||||
func getVintageKey(c context.Context, userId int, repoId int) *datastore.Key {
|
||||
return datastore.NewKey(c, "RepoVintage", fmt.Sprintf("%d-%d", userId, repoId), 0, nil)
|
||||
}
|
||||
|
||||
var computeVintageFunc *delay.Function
|
||||
|
||||
func computeVintage(c appengine.Context, userId int, userLogin string, repoId int, repoOwnerLogin string, repoName string) error {
|
||||
func computeVintage(c context.Context, userId int, userLogin string, repoId int, repoOwnerLogin string, repoName string) error {
|
||||
account, err := getAccount(c, userId)
|
||||
if err != nil {
|
||||
c.Errorf("Could not load account %d: %s. Presumed deleted, aborting computing vintage for %s/%s", userId, err.Error(), repoOwnerLogin, repoName)
|
||||
log.Errorf(c, "Could not load account %d: %s. Presumed deleted, aborting computing vintage for %s/%s", userId, err.Error(), repoOwnerLogin, repoName)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -42,7 +44,7 @@ func computeVintage(c appengine.Context, userId int, userLogin string, repoId in
|
|||
|
||||
repo, response, err := githubClient.Repositories.Get(repoOwnerLogin, repoName)
|
||||
if response.StatusCode == 403 || response.StatusCode == 404 {
|
||||
c.Warningf("Got a %d when trying to look up %s/%s (%d)", response.StatusCode, repoOwnerLogin, repoName, repoId)
|
||||
log.Warningf(c, "Got a %d when trying to look up %s/%s (%d)", response.StatusCode, repoOwnerLogin, repoName, repoId)
|
||||
_, err = datastore.Put(c, getVintageKey(c, userId, repoId), &RepoVintage{
|
||||
UserId: userId,
|
||||
RepoId: repoId,
|
||||
|
|
@ -50,7 +52,7 @@ func computeVintage(c appengine.Context, userId int, userLogin string, repoId in
|
|||
})
|
||||
return err
|
||||
} else if err != nil {
|
||||
c.Errorf("Could not load repo %s/%s (%d): %s", repoOwnerLogin, repoName, repoId, err.Error())
|
||||
log.Errorf(c, "Could not load repo %s/%s (%d): %s", repoOwnerLogin, repoName, repoId, err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +71,7 @@ func computeVintage(c appengine.Context, userId int, userLogin string, repoId in
|
|||
// GitHub returns with a 409 when a repository is empty.
|
||||
commits = make([]github.RepositoryCommit, 0)
|
||||
} else if err != nil {
|
||||
c.Errorf("Could not load commits for repo %s (%d): %s", *repo.FullName, repoId, err.Error())
|
||||
log.Errorf(c, "Could not load commits for repo %s (%d): %s", *repo.FullName, repoId, err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -78,10 +80,10 @@ func computeVintage(c appengine.Context, userId int, userLogin string, repoId in
|
|||
if len(commits) > 0 {
|
||||
stats, response, err := githubClient.Repositories.ListContributorsStats(repoOwnerLogin, repoName)
|
||||
if response.StatusCode == 202 {
|
||||
c.Infof("Stats were not available for %s, will try again later", *repo.FullName)
|
||||
log.Infof(c, "Stats were not available for %s, will try again later", *repo.FullName)
|
||||
task, err := computeVintageFunc.Task(userId, userLogin, repoId, repoOwnerLogin, repoName)
|
||||
if err != nil {
|
||||
c.Errorf("Could create delayed task for %s: %s", *repo.FullName, err.Error())
|
||||
log.Errorf(c, "Could create delayed task for %s: %s", *repo.FullName, err.Error())
|
||||
return err
|
||||
}
|
||||
task.Delay = time.Second * 10
|
||||
|
|
@ -89,7 +91,7 @@ func computeVintage(c appengine.Context, userId int, userLogin string, repoId in
|
|||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
c.Errorf("Could not load stats for repo %s: %s", *repo.FullName, err.Error())
|
||||
log.Errorf(c, "Could not load stats for repo %s: %s", *repo.FullName, err.Error())
|
||||
return err
|
||||
}
|
||||
for _, stat := range stats {
|
||||
|
|
@ -111,7 +113,7 @@ func computeVintage(c appengine.Context, userId int, userLogin string, repoId in
|
|||
Vintage: vintage,
|
||||
})
|
||||
if err != nil {
|
||||
c.Errorf("Could save vintage for repo %s: %s", *repo.FullName, err.Error())
|
||||
log.Errorf(c, "Could save vintage for repo %s: %s", *repo.FullName, err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -122,7 +124,7 @@ func init() {
|
|||
computeVintageFunc = delay.Func("computeVintage", computeVintage)
|
||||
}
|
||||
|
||||
func fillVintages(c appengine.Context, user *github.User, repos []*Repo) error {
|
||||
func fillVintages(c context.Context, user *github.User, repos []*Repo) error {
|
||||
if len(repos) > VintageChunkSize {
|
||||
for chunkStart := 0; chunkStart < len(repos); chunkStart += VintageChunkSize {
|
||||
chunkEnd := chunkStart + VintageChunkSize
|
||||
|
|
@ -151,7 +153,7 @@ func fillVintages(c appengine.Context, user *github.User, repos []*Repo) error {
|
|||
if err == datastore.ErrNoSuchEntity {
|
||||
vintages[i] = nil
|
||||
} else if err != nil {
|
||||
c.Errorf("%d/%s vintage fetch error: %s", i, *repos[i].FullName, err.Error())
|
||||
log.Errorf(c, "%d/%s vintage fetch error: %s", i, *repos[i].FullName, err.Error())
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -238,7 +240,7 @@ type UserRepos struct {
|
|||
Repos []*Repo
|
||||
}
|
||||
|
||||
func getRepos(c appengine.Context, githubClient *github.Client, account *Account, user *github.User) (*Repos, error) {
|
||||
func getRepos(c context.Context, githubClient *github.Client, account *Account, user *github.User) (*Repos, error) {
|
||||
clientUserRepos := make([]github.Repository, 0)
|
||||
page := 1
|
||||
for {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
package retrogit
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
log_ "log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
|
@ -13,11 +14,12 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"appengine"
|
||||
"appengine/datastore"
|
||||
"appengine/delay"
|
||||
"appengine/mail"
|
||||
"appengine/urlfetch"
|
||||
"google.golang.org/appengine"
|
||||
"google.golang.org/appengine/datastore"
|
||||
"google.golang.org/appengine/delay"
|
||||
"google.golang.org/appengine/log"
|
||||
"google.golang.org/appengine/mail"
|
||||
"google.golang.org/appengine/urlfetch"
|
||||
|
||||
"code.google.com/p/goauth2/oauth"
|
||||
"github.com/google/go-github/github"
|
||||
|
|
@ -33,7 +35,7 @@ var sessionStore *sessions.CookieStore
|
|||
var sessionConfig SessionConfig
|
||||
var templates map[string]*Template
|
||||
|
||||
func init() {
|
||||
func main() {
|
||||
templates = loadTemplates()
|
||||
timezones = initTimezones()
|
||||
sessionStore, sessionConfig = initSession()
|
||||
|
|
@ -62,6 +64,8 @@ func init() {
|
|||
router.Handle("/admin/repos", AppHandler(reposAdminHandler)).Name("repos-admin")
|
||||
router.Handle("/admin/delete-account", AppHandler(deleteAccountAdminHandler)).Name("delete-account-admin")
|
||||
http.Handle("/", router)
|
||||
|
||||
appengine.Main()
|
||||
}
|
||||
|
||||
func initGithubOAuthConfig(includePrivateRepos bool) (config oauth.Config) {
|
||||
|
|
@ -72,11 +76,11 @@ func initGithubOAuthConfig(includePrivateRepos bool) (config oauth.Config) {
|
|||
path += ".json"
|
||||
configBytes, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
log.Panicf("Could not read GitHub OAuth config from %s: %s", path, err.Error())
|
||||
log_.Panicf("Could not read GitHub OAuth config from %s: %s", path, err.Error())
|
||||
}
|
||||
err = json.Unmarshal(configBytes, &config)
|
||||
if err != nil {
|
||||
log.Panicf("Could not parse GitHub OAuth config %s: %s", configBytes, err.Error())
|
||||
log_.Panicf("Could not parse GitHub OAuth config %s: %s", configBytes, err.Error())
|
||||
}
|
||||
repoScopeModifier := ""
|
||||
if !includePrivateRepos {
|
||||
|
|
@ -232,12 +236,12 @@ func digestCronHandler(w http.ResponseWriter, r *http.Request) *AppError {
|
|||
if account.Frequency == "weekly" {
|
||||
now := time.Now().In(account.TimezoneLocation)
|
||||
if now.Weekday() != account.WeeklyDay {
|
||||
c.Infof("Skipping %d, since it wants weekly digests on %ss and today is a %s.",
|
||||
log.Infof(c, "Skipping %d, since it wants weekly digests on %ss and today is a %s.",
|
||||
account.GitHubUserId, account.WeeklyDay, now.Weekday())
|
||||
continue
|
||||
}
|
||||
}
|
||||
c.Infof("Enqueing task for %d...", account.GitHubUserId)
|
||||
log.Infof(c, "Enqueing task for %d...", account.GitHubUserId)
|
||||
sendDigestForAccountFunc.Call(c, account.GitHubUserId)
|
||||
}
|
||||
fmt.Fprint(w, "Done")
|
||||
|
|
@ -246,31 +250,31 @@ func digestCronHandler(w http.ResponseWriter, r *http.Request) *AppError {
|
|||
|
||||
var sendDigestForAccountFunc = delay.Func(
|
||||
"sendDigestForAccount",
|
||||
func(c appengine.Context, githubUserId int) error {
|
||||
c.Infof("Sending digest for %d...", githubUserId)
|
||||
func(c context.Context, githubUserId int) error {
|
||||
log.Infof(c, "Sending digest for %d...", githubUserId)
|
||||
account, err := getAccount(c, githubUserId)
|
||||
if err != nil {
|
||||
c.Errorf(" Error looking up account: %s", err.Error())
|
||||
log.Errorf(c, " Error looking up account: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
sent, err := sendDigestForAccount(account, c)
|
||||
if err != nil {
|
||||
c.Errorf(" Error: %s", err.Error())
|
||||
log.Errorf(c, " Error: %s", err.Error())
|
||||
if !appengine.IsDevAppServer() {
|
||||
sendDigestErrorMail(err, c, githubUserId)
|
||||
}
|
||||
} else if sent {
|
||||
c.Infof(" Sent!")
|
||||
log.Infof(c, " Sent!")
|
||||
} else {
|
||||
c.Infof(" Not sent, digest was empty")
|
||||
log.Infof(c, " Not sent, digest was empty")
|
||||
}
|
||||
return err
|
||||
})
|
||||
|
||||
func sendDigestErrorMail(e error, c appengine.Context, gitHubUserId int) {
|
||||
func sendDigestErrorMail(e error, c context.Context, gitHubUserId int) {
|
||||
if strings.Contains(e.Error(), ": 502") {
|
||||
// Ignore 502s from GitHub, there's nothing we do about them.
|
||||
return;
|
||||
return
|
||||
}
|
||||
errorMessage := &mail.Message{
|
||||
Sender: "RetroGit Admin <digests@retrogit.com>",
|
||||
|
|
@ -280,11 +284,11 @@ func sendDigestErrorMail(e error, c appengine.Context, gitHubUserId int) {
|
|||
}
|
||||
err := mail.Send(c, errorMessage)
|
||||
if err != nil {
|
||||
c.Errorf("Error %s sending error email.", err.Error())
|
||||
log.Errorf(c, "Error %s sending error email.", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func sendDigestForAccount(account *Account, c appengine.Context) (bool, error) {
|
||||
func sendDigestForAccount(account *Account, c context.Context) (bool, error) {
|
||||
oauthTransport := githubOAuthTransport(c)
|
||||
oauthTransport.Token = &account.OAuthToken
|
||||
githubClient := github.NewClient(oauthTransport.Client())
|
||||
|
|
@ -295,7 +299,7 @@ func sendDigestForAccount(account *Account, c appengine.Context) (bool, error) {
|
|||
gitHubStatus := gitHubError.Response.StatusCode
|
||||
if gitHubStatus == http.StatusUnauthorized ||
|
||||
gitHubStatus == http.StatusForbidden {
|
||||
c.Errorf(" GitHub auth error while getting email adddress, skipping: %s", err.Error())
|
||||
log.Errorf(c, " GitHub auth error while getting email adddress, skipping: %s", err.Error())
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
|
@ -312,7 +316,7 @@ func sendDigestForAccount(account *Account, c appengine.Context) (bool, error) {
|
|||
gitHubStatus := gitHubError.Response.StatusCode
|
||||
if gitHubStatus == http.StatusUnauthorized ||
|
||||
gitHubStatus == http.StatusForbidden {
|
||||
c.Errorf(" GitHub auth error while getting digest, sending error email: %s", err.Error())
|
||||
log.Errorf(c, " GitHub auth error while getting digest, sending error email: %s", err.Error())
|
||||
var authErrorHtml bytes.Buffer
|
||||
if err := templates["github-auth-error-email"].Execute(&authErrorHtml, nil); err != nil {
|
||||
return false, err
|
||||
|
|
@ -516,11 +520,11 @@ func setInitialTimezoneHandler(w http.ResponseWriter, r *http.Request, state *Ap
|
|||
|
||||
var cacheDigestForAccountFunc = delay.Func(
|
||||
"cacheDigestForAccount",
|
||||
func(c appengine.Context, githubUserId int) error {
|
||||
c.Infof("Caching digest for %d...", githubUserId)
|
||||
func(c context.Context, githubUserId int) error {
|
||||
log.Infof(c, "Caching digest for %d...", githubUserId)
|
||||
account, err := getAccount(c, githubUserId)
|
||||
if err != nil {
|
||||
c.Errorf(" Error looking up account: %s", err.Error())
|
||||
log.Errorf(c, " Error looking up account: %s", err.Error())
|
||||
// Not returning error since we don't want these tasks to be
|
||||
// retried.
|
||||
return nil
|
||||
|
|
@ -531,9 +535,9 @@ var cacheDigestForAccountFunc = delay.Func(
|
|||
githubClient := github.NewClient(oauthTransport.Client())
|
||||
_, err = newDigest(c, githubClient, account)
|
||||
if err != nil {
|
||||
c.Errorf(" Error computing digest: %s", err.Error())
|
||||
log.Errorf(c, " Error computing digest: %s", err.Error())
|
||||
}
|
||||
c.Infof(" Done!")
|
||||
log.Infof(c, " Done!")
|
||||
return nil
|
||||
})
|
||||
|
||||
|
|
@ -544,12 +548,12 @@ func deleteAccountHandler(w http.ResponseWriter, r *http.Request, state *AppSign
|
|||
return RedirectToRoute("index")
|
||||
}
|
||||
|
||||
func githubOAuthTransport(c appengine.Context) *oauth.Transport {
|
||||
appengineTransport := &urlfetch.Transport{Context: c}
|
||||
appengineTransport.Deadline = time.Second * 60
|
||||
func githubOAuthTransport(c context.Context) *oauth.Transport {
|
||||
ctx_with_timeout, _ := context.WithTimeout(c, time.Second*60)
|
||||
appengineTransport := &urlfetch.Transport{Context: ctx_with_timeout}
|
||||
cachingTransport := &CachingTransport{
|
||||
Transport: appengineTransport,
|
||||
Context: c,
|
||||
Context: ctx_with_timeout,
|
||||
}
|
||||
return &oauth.Transport{
|
||||
Config: &githubOauthConfig,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package retrogit
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
|
@ -6,7 +6,7 @@ import (
|
|||
"io/ioutil"
|
||||
"log"
|
||||
|
||||
"appengine"
|
||||
"google.golang.org/appengine"
|
||||
|
||||
"github.com/gorilla/sessions"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package retrogit
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
|
|
|||
9
deploy.sh
Executable file
9
deploy.sh
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/sh
|
||||
|
||||
# With the Go 1.11 runtime, if we're not using modules, all source (including
|
||||
# the app itself) must live under GOPATH. Copy it there before deploying.
|
||||
DEST="$GOPATH/src/retrogit"
|
||||
rm -rf $DEST
|
||||
cp -r app $DEST
|
||||
cd $DEST
|
||||
gcloud app deploy --project retro-git app.yaml
|
||||
Loading…
Reference in a new issue