github.com/twelho/conform@v0.0.0-20231016230407-c25e9238598a/cmd/conform/serve.go (about) 1 // This Source Code Form is subject to the terms of the Mozilla Public 2 // License, v. 2.0. If a copy of the MPL was not distributed with this 3 // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 5 package main 6 7 import ( 8 "encoding/json" 9 "fmt" 10 "io" 11 "log" 12 "net/http" 13 "os" 14 "os/exec" 15 "path/filepath" 16 17 git "github.com/go-git/go-git/v5" 18 "github.com/go-git/go-git/v5/config" 19 "github.com/go-git/go-git/v5/plumbing" 20 "github.com/google/go-github/v41/github" 21 "github.com/spf13/cobra" 22 ) 23 24 const ( 25 path = "/github" 26 ) 27 28 // serveCmd represents the serve command. 29 var serveCmd = &cobra.Command{ 30 Use: "serve", 31 Short: "", 32 Long: ``, 33 Run: func(cmd *cobra.Command, args []string) { 34 if err := os.MkdirAll("/tmp", 0o700); err != nil { 35 log.Fatal(err) 36 } 37 38 http.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { 39 payload, err := io.ReadAll(r.Body) 40 if err != nil { 41 log.Printf("failed to read payload: %+v\n", err) 42 43 return 44 } 45 46 go func() { 47 dir, err := os.CreateTemp("/tmp", "conform") 48 if err != nil { 49 log.Printf("failed to create temporary directory: %+v\n", err) 50 51 return 52 } 53 54 defer os.RemoveAll(dir.Name()) //nolint:errcheck 55 56 if err = os.MkdirAll(filepath.Join(dir.Name(), "github"), 0o700); err != nil { 57 log.Printf("failed to create github directory: %+v\n", err) 58 59 return 60 } 61 if err = os.MkdirAll(filepath.Join(dir.Name(), "repo"), 0o700); err != nil { 62 log.Printf("failed to create repo directory: %+v\n", err) 63 64 return 65 } 66 67 event := filepath.Join(dir.Name(), "github", "event.json") 68 pullRequestEvent := &github.PullRequestEvent{} 69 if err = json.Unmarshal(payload, pullRequestEvent); err != nil { 70 log.Printf("failed to parse pull_request event: %+v\n", err) 71 72 return 73 } 74 75 cloneRepo := filepath.Join(dir.Name(), "repo") 76 cloneURL := pullRequestEvent.GetPullRequest().GetBase().GetRepo().GetCloneURL() 77 78 log.Printf("Cloning %s", cloneURL) 79 80 repo, err := git.PlainClone(cloneRepo, false, &git.CloneOptions{ 81 SingleBranch: false, 82 NoCheckout: true, 83 URL: cloneURL, 84 Progress: os.Stdout, 85 }) 86 if err != nil { 87 log.Printf("failed to clone repo: %+v\n", err) 88 89 return 90 } 91 92 id := pullRequestEvent.GetPullRequest().GetNumber() 93 94 ref := plumbing.ReferenceName(pullRequestEvent.GetPullRequest().GetHead().GetRef()) 95 96 refSpec := fmt.Sprintf("refs/pull/%d/head:%s", id, ref) 97 98 err = repo.Fetch(&git.FetchOptions{ 99 RefSpecs: []config.RefSpec{ 100 config.RefSpec("refs/heads/*:refs/heads/*"), 101 config.RefSpec(refSpec), 102 }, 103 Progress: os.Stdout, 104 }) 105 if err != nil { 106 log.Printf("failed to fetch %q: %v", refSpec, err) 107 108 return 109 } 110 111 worktree, err := repo.Worktree() 112 if err != nil { 113 log.Printf("failed to get working tree: %v", err) 114 115 return 116 } 117 118 err = worktree.Checkout(&git.CheckoutOptions{ 119 Branch: ref, 120 }) 121 122 if err != nil { 123 log.Printf("failed to checkout %q: %v", ref, err) 124 125 return 126 } 127 128 log.Printf("writing %s to disk", event) 129 130 if err = os.WriteFile(event, payload, 0o600); err != nil { 131 log.Printf("failed to write event to disk: %+v\n", err) 132 133 return 134 } 135 cmd := exec.Command("/proc/self/exe", "enforce", "--reporter=github", "--commit-ref=refs/heads/"+pullRequestEvent.GetPullRequest().GetBase().GetRef()) 136 cmd.Stdout = os.Stdout 137 cmd.Stderr = os.Stdout 138 cmd.Dir = cloneRepo 139 cmd.Env = []string{fmt.Sprintf("INPUT_TOKEN=%s", os.Getenv("INPUT_TOKEN")), fmt.Sprintf("GITHUB_EVENT_PATH=%s", event)} 140 err = cmd.Start() 141 if err != nil { 142 log.Printf("failed to start command: %+v\n", err) 143 144 return 145 } 146 err = cmd.Wait() 147 if err != nil { 148 log.Printf("command failed: %+v\n", err) 149 150 return 151 } 152 }() 153 154 w.WriteHeader(http.StatusOK) 155 }) 156 157 log.Fatal(http.ListenAndServe(":3000", nil)) 158 }, 159 } 160 161 func init() { 162 rootCmd.AddCommand(serveCmd) 163 }