Skip to content

Commit ce0ef3c

Browse files
authored
Refactor (#7)
* refactor.
1 parent 8ab3164 commit ce0ef3c

12 files changed

+977
-773
lines changed

main.go

+10-773
Large diffs are not rendered by default.

vsts/client.go

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package vsts
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"fmt"
7+
"log"
8+
"net/http"
9+
)
10+
11+
func getFromVsts(url string, v interface{}) error {
12+
client := &http.Client{}
13+
req, err := http.NewRequest("GET", url, nil)
14+
if err != nil {
15+
return err
16+
}
17+
18+
req.SetBasicAuth(config.Username, config.Password)
19+
resp, err := client.Do(req)
20+
if err != nil {
21+
return err
22+
}
23+
defer resp.Body.Close()
24+
25+
if resp.StatusCode != 200 {
26+
return fmt.Errorf("repsonse with non 200 code of %d", resp.StatusCode)
27+
}
28+
29+
return json.NewDecoder(resp.Body).Decode(v)
30+
}
31+
32+
func postToVsts(url string, v interface{}) error {
33+
return sendToVsts("POST", url, v)
34+
}
35+
36+
func putToVsts(url string, v interface{}) error {
37+
return sendToVsts("PUT", url, v)
38+
}
39+
40+
func patchToVsts(url string, v interface{}) error {
41+
return sendToVsts("PATCH", url, v)
42+
}
43+
44+
func sendToVsts(method string, url string, v interface{}) error {
45+
client := &http.Client{}
46+
body := new(bytes.Buffer)
47+
json.NewEncoder(body).Encode(v)
48+
req, err := http.NewRequest(method, url, body)
49+
if err != nil {
50+
return err
51+
}
52+
53+
req.SetBasicAuth(config.Username, config.Password)
54+
req.Header.Set("Content-Type", "application/json")
55+
56+
resp, err := client.Do(req)
57+
if err != nil {
58+
return err
59+
}
60+
defer resp.Body.Close()
61+
62+
log.Println(resp.Status)
63+
if resp.StatusCode != 200 && resp.StatusCode != 201 {
64+
return fmt.Errorf("repsonse with non 200|201 code of %d", resp.StatusCode)
65+
}
66+
67+
return nil
68+
}

vsts/comment.go

+159
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package vsts
2+
3+
import (
4+
"log"
5+
"strconv"
6+
"strings"
7+
)
8+
9+
func getThreadsURL(pullRequestID int) string {
10+
threadsURLTemplate := "https://{instance}/DefaultCollection/{project}/_apis/git/repositories/{repository}/pullRequests/{pullRequest}/threads?api-version={version}"
11+
12+
r := strings.NewReplacer(
13+
"{instance}", config.Instance,
14+
"{project}", config.Project,
15+
"{repository}", config.Repo,
16+
"{pullRequest}", strconv.Itoa(pullRequestID),
17+
"{version}", "3.0-preview")
18+
19+
return r.Replace(threadsURLTemplate)
20+
}
21+
22+
func getThreadURL(pullRequestID int, threadID int) string {
23+
threadURLTempate := "https://{instance}/DefaultCollection/{project}/_apis/git/repositories/{repository}/pullRequests/{pullRequest}/threads/{threadID}?api-version={version}"
24+
r := strings.NewReplacer(
25+
"{instance}", config.Instance,
26+
"{project}", config.Project,
27+
"{repository}", config.Repo,
28+
"{pullRequest}", strconv.Itoa(pullRequestID),
29+
"{threadID}", strconv.Itoa(threadID),
30+
"{version}", "3.0-preview")
31+
32+
return r.Replace(threadURLTempate)
33+
}
34+
35+
func getCommentURL(pullRequestID int, threadID int) string {
36+
commentURLTempate := "https://{instance}/DefaultCollection/{project}/_apis/git/repositories/{repository}/pullRequests/{pullRequest}/threads/{threadID}/comments?api-version={version}"
37+
r := strings.NewReplacer(
38+
"{instance}", config.Instance,
39+
"{project}", config.Project,
40+
"{repository}", config.Repo,
41+
"{pullRequest}", strconv.Itoa(pullRequestID),
42+
"{threadID}", strconv.Itoa(threadID),
43+
"{version}", "3.0-preview")
44+
45+
return r.Replace(commentURLTempate)
46+
}
47+
48+
func getCommentThreads(pullRequestID int) (*commentThreads, error) {
49+
commentThreads := new(commentThreads)
50+
51+
url := getThreadsURL(pullRequestID)
52+
err := getFromVsts(url, commentThreads)
53+
54+
if err != nil {
55+
return nil, err
56+
}
57+
58+
return commentThreads, nil
59+
}
60+
61+
func createCommentThread(pullRequestID int, filePath string, status int, content string) error {
62+
log.Printf("Creating comment thread to PR %v...\n", pullRequestID)
63+
64+
thread := postThread{
65+
Comments: []postComment{
66+
{
67+
ParentCommentID: 0,
68+
Content: content,
69+
CommentType: 1,
70+
},
71+
},
72+
Properties: threadProperty{
73+
MicrosoftTeamFoundationDiscussionSupportsMarkdown: supportsMarkDown{
74+
Type: "System.Int32",
75+
Value: 1,
76+
},
77+
},
78+
Status: status,
79+
ThreadContext: threadContext{
80+
FilePath: filePath,
81+
RightFileStart: filePosition{
82+
Line: 1,
83+
Offset: 1,
84+
},
85+
RightFileEnd: filePosition{
86+
Line: 1,
87+
Offset: 3,
88+
},
89+
},
90+
}
91+
92+
url := getThreadsURL(pullRequestID)
93+
94+
err := postToVsts(url, thread)
95+
if err != nil {
96+
return err
97+
}
98+
99+
return nil
100+
}
101+
102+
func addComment(pullRequestID int, thread commentThread, essentialMessage string, content string) error {
103+
lastCommentID := 0
104+
commentContent := ""
105+
for _, comment := range thread.Comments {
106+
if !comment.IsDeleted && comment.ID > lastCommentID {
107+
lastCommentID = comment.ID
108+
commentContent = comment.Content
109+
}
110+
}
111+
112+
if strings.Contains(commentContent, essentialMessage) {
113+
log.Printf("Already commented to PR %v thread %v...\n", pullRequestID, thread.ID)
114+
return nil
115+
}
116+
117+
log.Printf("Adding comment to PR %v thread %v...\n", pullRequestID, thread.ID)
118+
119+
comment := postComment{
120+
ParentCommentID: lastCommentID,
121+
Content: content,
122+
CommentType: 1,
123+
}
124+
125+
url := getCommentURL(pullRequestID, thread.ID)
126+
127+
err := postToVsts(url, comment)
128+
if err != nil {
129+
return err
130+
}
131+
132+
return nil
133+
}
134+
135+
func setCommentThreadStatus(pullRequestID int, thread commentThread, status int) error {
136+
statusString := "active"
137+
if status == 2 {
138+
statusString = "fixed"
139+
}
140+
if strings.EqualFold(thread.Status, statusString) {
141+
log.Printf("PR %v thread %v status is already %v\n", pullRequestID, thread.ID, status)
142+
return nil
143+
}
144+
145+
log.Printf("Set PR %v thread %v to %v...\n", pullRequestID, thread.ID, status)
146+
147+
patchThread := patchThread{
148+
Status: status,
149+
}
150+
151+
url := getThreadURL(pullRequestID, thread.ID)
152+
153+
err := patchToVsts(url, patchThread)
154+
if err != nil {
155+
return err
156+
}
157+
158+
return nil
159+
}

vsts/config.go

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package vsts
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"os"
7+
)
8+
9+
const (
10+
configPath = "VSTS_CONFIG_PATH"
11+
)
12+
13+
type imageConfig struct {
14+
Os string `json:"os"`
15+
ConfigPath string `json:"configPath"`
16+
Header string `json:"header"`
17+
}
18+
19+
// Config is configuration for VSTS access
20+
type Config struct {
21+
Username string `json:"username"`
22+
Password string `json:"password"`
23+
Instance string `json:"instance"`
24+
Collection string `json:"collection"`
25+
Project string `json:"project"`
26+
Repo string `json:"repo"`
27+
MasterBranch string `json:"masterBranch"`
28+
UserID string `json:"userId"`
29+
ImageConfigs []imageConfig `json:"imageConfigs"`
30+
Endpoints []string `json:"endpoints"`
31+
}
32+
33+
// GetConfig loads configuration from file
34+
func GetConfig() (*Config, error) {
35+
configPathString := os.Getenv(configPath)
36+
if len(configPathString) == 0 {
37+
return nil, fmt.Errorf("env '%s' not found", configPath)
38+
}
39+
40+
config := Config{}
41+
42+
file, _ := os.Open(configPathString)
43+
defer file.Close()
44+
decoder := json.NewDecoder(file)
45+
err := decoder.Decode(&config)
46+
if err != nil {
47+
return nil, err
48+
}
49+
50+
return &config, nil
51+
}

vsts/diff.go

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package vsts
2+
3+
import (
4+
"strings"
5+
)
6+
7+
func getBranchNameFromRefName(refName string) string {
8+
return (strings.SplitAfterN(refName, "/", 3))[2]
9+
}
10+
11+
func getdiffsURL(baseBranch string, targetBranch string) string {
12+
diffsURLTemplate := "https://{instance}/DefaultCollection/{project}/_apis/git/repositories/{repository}/diffs/commits?api-version={version}&targetVersionType=branch&targetVersion={targetBranch}&baseVersionType=branch&baseVersion={baseBranch}"
13+
r := strings.NewReplacer(
14+
"{instance}", config.Instance,
15+
"{project}", config.Project,
16+
"{repository}", config.Repo,
17+
"{version}", "1.0",
18+
"{baseBranch}", baseBranch,
19+
"{targetBranch}", targetBranch)
20+
21+
return r.Replace(diffsURLTemplate)
22+
}
23+
24+
func getDiffsBetweenBranches(baseBranch string, targetBranch string) (*diffs, error) {
25+
diffs := new(diffs)
26+
27+
url := getdiffsURL(baseBranch, targetBranch)
28+
29+
err := getFromVsts(url, diffs)
30+
if err != nil {
31+
return nil, err
32+
}
33+
34+
return diffs, nil
35+
}

vsts/item.go

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package vsts
2+
3+
import (
4+
"strings"
5+
)
6+
7+
func getBranchItemURL(branch string, itemPath string) string {
8+
itemURLTemplate := "https://{instance}/DefaultCollection/{project}/_apis/git/repositories/{repository}/items?api-version={version}&versionType={versionType}&version={versionValue}&scopePath={itemPath}&lastProcessedChange=true"
9+
r := strings.NewReplacer(
10+
"{instance}", config.Instance,
11+
"{project}", config.Project,
12+
"{repository}", config.Repo,
13+
"{versionType}", "branch",
14+
"{versionValue}", branch,
15+
"{itemPath}", itemPath,
16+
"{version}", "1.0")
17+
18+
return r.Replace(itemURLTemplate)
19+
20+
}
21+
22+
func getBranchItemContent(branch string, itemPath string, v interface{}) error {
23+
24+
url := getBranchItemURL(branch, itemPath)
25+
err := getFromVsts(url, v)
26+
27+
if err != nil {
28+
return err
29+
}
30+
31+
return nil
32+
}

0 commit comments

Comments
 (0)