• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

coccyx / gogen / #113

19 Feb 2025 07:39PM UTC coverage: 52.539%. First build
#113

push

web-flow
Updating dependencies and removing an output (#44)

* Updating some deps. Removing govvv because it's deprecated.

* Removing a problematic output

* finished updating dependencies

4 of 21 new or added lines in 5 files covered. (19.05%)

2090 of 3978 relevant lines covered (52.54%)

493.53 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/internal/github.go
1
package internal
2

3
// Mostly from https://jacobmartins.com/2016/02/29/getting-started-with-oauth2-in-go/
4

5
import (
6
        "context"
7
        "io/ioutil"
8
        "net/http"
9
        "os"
10
        "path/filepath"
11

12
        yaml "gopkg.in/yaml.v2"
13

14
        "github.com/kr/pretty"
15
        uuid "github.com/satori/go.uuid"
16
        "github.com/skratchdot/open-golang/open"
17

18
        log "github.com/coccyx/gogen/logger"
19
        "github.com/google/go-github/github"
20
        "golang.org/x/oauth2"
21
        githuboauth "golang.org/x/oauth2/github"
22
)
23

24
var (
25
        gitHubClientID     string // Passed in during the build process
26
        gitHubClientSecret string // Passed in during the build process
27
        oauthConf          = &oauth2.Config{
28
                RedirectURL:  "http://localhost:46436/GitHubCallback",
29
                ClientID:     gitHubClientID,
30
                ClientSecret: gitHubClientSecret,
31
                Endpoint:     githuboauth.Endpoint,
32
                Scopes:       []string{"gist"},
33
        }
34
        // Some random string, random for each request
35
        oauthStateString = uuid.NewV4().String()
36
)
37

38
// GitHub allows posting gists to a user's GitHub
39
type GitHub struct {
40
        done   chan int
41
        token  string
42
        client *github.Client
43
}
44

45
// Push will create a public gist of "name.yml" from our running config
46
func (gh *GitHub) Push(name string, c *Config) *github.Gist {
×
47
        gist := new(github.Gist)
×
48
        files := make(map[github.GistFilename]github.GistFile)
×
49

×
50
        file := new(github.GistFile)
×
51
        fname := name + ".yml"
×
52
        file.Filename = &fname
×
53
        var outb []byte
×
54
        var outbs *string
×
55
        var err error
×
56
        if outb, err = yaml.Marshal(c); err != nil {
×
57
                log.Fatalf("Cannot Marshal c.Global, err: %s", err)
×
58
        }
×
59
        outbs = new(string)
×
60
        *outbs = string(outb)
×
61
        file.Content = outbs
×
62
        files[github.GistFilename(name)] = *file
×
63

×
64
        gist.Files = files
×
65
        gist.Description = &name
×
66
        public := true
×
67
        gist.Public = &public
×
68

×
69
        var foundgist *github.Gist
×
70
        foundgist = gh.findgist(name)
×
71

×
72
        if foundgist != nil {
×
73
                log.Debugf("Found gist, updating")
×
NEW
74
                updatedgist, _, err := gh.client.Gists.Edit(context.Background(), *foundgist.ID, gist)
×
75
                if err != nil {
×
76
                        log.Fatalf("Error updating gist %# v: %s", pretty.Formatter(gist), err)
×
77
                }
×
78
                return updatedgist
×
79
        }
80
        log.Debugf("Gist not found, creating")
×
NEW
81
        newgist, _, err := gh.client.Gists.Create(context.Background(), gist)
×
82
        if err != nil {
×
83
                log.Fatalf("Error creating gist %# v: %s", pretty.Formatter(gist), err)
×
84
        }
×
85
        return newgist
×
86
}
87

88
// Pull grabs a named gist from GitHub
89
func (gh *GitHub) Pull(name string) *github.Gist {
×
90
        var gist *github.Gist
×
91
        gist = gh.findgist(name)
×
92
        if gist == nil {
×
93
                log.Fatalf("Error finding gist %s", name+".yml")
×
94
        }
×
95
        return gist
×
96
}
97

98
func (gh *GitHub) findgist(name string) (foundgist *github.Gist) {
×
NEW
99
        gists, _, err := gh.client.Gists.List(context.Background(), "", nil)
×
100
        if err != nil {
×
101
                log.Fatalf("Cannot pull Gists list: %s", err)
×
102
        }
×
103
findgist:
×
104
        for _, testgist := range gists {
×
105
                for _, gistfile := range testgist.Files {
×
106
                        log.Debugf("Testing %s if match %s", *gistfile.Filename, name+".yml")
×
107
                        if *gistfile.Filename == name+".yml" {
×
108
                                foundgist = testgist
×
109
                                break findgist
×
110
                        }
111
                }
112
        }
113
        return foundgist
×
114
}
115

116
// NewGitHub returns a GitHub object, with a set auth token
117
func NewGitHub(requireauth bool) *GitHub {
×
118
        gh := new(GitHub)
×
119
        gh.done = make(chan int)
×
120

×
121
        log.Infof("GitHub OAuth Client ID: %s", gitHubClientID)
×
122

×
123
        if oauthConf.ClientID == "" {
×
124
                oauthConf.ClientID = os.Getenv("GITHUB_OAUTH_CLIENT_ID")
×
125
        }
×
126
        if oauthConf.ClientSecret == "" {
×
127
                oauthConf.ClientSecret = os.Getenv("GITHUB_OAUTH_CLIENT_SECRET")
×
128
        }
×
129

130
        tokenFile := filepath.Join(os.ExpandEnv("$GOGEN_HOME"), ".githubtoken")
×
131
        _, err := os.Stat(tokenFile)
×
132
        if err == nil {
×
133
                buf, err := ioutil.ReadFile(tokenFile)
×
134
                if err != nil {
×
135
                        log.Fatalf("Error reading from file %s: %s", tokenFile, err)
×
136
                }
×
137
                gh.token = string(buf)
×
138
                log.Debugf("Getting GitHub token '%s' from file", gh.token)
×
139
        } else if requireauth {
×
140
                if !os.IsNotExist(err) {
×
141
                        log.Fatalf("Unexpected error accessing %s: %s", tokenFile, err)
×
142
                }
×
143
                http.HandleFunc("/GitHubLogin", gh.handleGitHubLogin)
×
144
                open.Run("http://localhost:46436/GitHubLogin")
×
145
                http.HandleFunc("/GitHubCallback", gh.handleGitHubCallback)
×
146
                go http.ListenAndServe(":46436", nil)
×
147
                <-gh.done
×
148
                log.Debugf("Getting GitHub token '%s' from oauth", gh.token)
×
149

×
150
                err = ioutil.WriteFile(tokenFile, []byte(gh.token), 400)
×
151
                if err != nil {
×
152
                        log.Fatalf("Error writing token to file %s: %s", tokenFile, err)
×
153
                }
×
154
        }
155
        if len(gh.token) > 0 {
×
156
                ts := oauth2.StaticTokenSource(
×
157
                        &oauth2.Token{AccessToken: gh.token},
×
158
                )
×
159
                tc := oauth2.NewClient(oauth2.NoContext, ts)
×
160
                gh.client = github.NewClient(tc)
×
161
        } else {
×
162
                gh.client = github.NewClient(nil)
×
163
        }
×
164
        return gh
×
165
}
166

167
func (gh *GitHub) handleGitHubLogin(w http.ResponseWriter, r *http.Request) {
×
168
        url := oauthConf.AuthCodeURL(oauthStateString)
×
169
        http.Redirect(w, r, url, http.StatusTemporaryRedirect)
×
170
}
×
171

172
func (gh *GitHub) handleGitHubCallback(w http.ResponseWriter, r *http.Request) {
×
173
        state := r.FormValue("state")
×
174
        if state != oauthStateString {
×
175
                log.Errorf("invalid oauth state, expected '%s', got '%s'\n", oauthStateString, state)
×
176
                http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
×
177
                return
×
178
        }
×
179

180
        code := r.FormValue("code")
×
181
        token, err := oauthConf.Exchange(oauth2.NoContext, code)
×
182
        if err != nil {
×
183
                log.Errorf("Code exchange failed with '%s'\n", err)
×
184
                http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
×
185
                return
×
186
        }
×
187

188
        gh.token = token.AccessToken
×
189
        gh.done <- 1
×
190
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc