-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.go
More file actions
executable file
·149 lines (126 loc) · 4.16 KB
/
main.go
File metadata and controls
executable file
·149 lines (126 loc) · 4.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package main
import (
"encoding/json"
"math/rand"
"net/http"
"os"
"sync"
"time"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
type StepPayload struct {
StepName string `json:"step_name"`
RepoPath string `json:"repo_path"`
CommitHash string `json:"commit_hash"`
SimulateStatus *string `json:"simulate_status,omitempty"`
SimulateBuildTime *int `json:"simulate_build_time,omitempty"`
}
type Response struct {
BuildLogs string `json:"build_logs"`
Status string `json:"status"`
DurationMs int `json:"duration_ms"`
}
var buildLock = sync.Mutex{}
var testLock = sync.Mutex{}
func stepTriggerHandler(w http.ResponseWriter, r *http.Request) {
log.Printf("[Step Handler] Received request from %v", r.RemoteAddr)
if r.Method != http.MethodPost {
http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
return
}
var payload StepPayload
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
startTime := time.Now()
logs := "step '" + payload.StepName + "' build started!"
logs += "\nRepo path: " + payload.RepoPath
logs += "\nCommit hash: " + payload.CommitHash
status := "Success"
switch payload.StepName {
case "lint":
logs += "\nLinting..."
// simulate a short random step that always succeeds
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
case "build":
logs += "\nBuilding..."
buildTime := rand.Intn(1000) // Random build time in milliseconds
if payload.SimulateBuildTime != nil {
buildTime = *payload.SimulateBuildTime
}
// Check if the lock is available. If not, write something to the logs and wait until it is.
// This is to simulate a shared resource during the build.
if !buildLock.TryLock() {
log.Warn().Msg("Building lock is not available!")
logs += "\nWaiting for lock..."
buildLock.Lock()
}
defer buildLock.Unlock()
// Simulate build time
logs += "\nSimulating build for step '" + payload.StepName + "'..."
time.Sleep(time.Duration(buildTime) * time.Millisecond)
if payload.SimulateStatus != nil {
status = *payload.SimulateStatus
} else if rand.Intn(2) == 0 {
status = "Failure"
}
case "test":
logs += "\nTesting..."
buildTime := rand.Intn(1000) // Random build time in milliseconds
if payload.SimulateBuildTime != nil {
buildTime = *payload.SimulateBuildTime
}
// Check if the lock is available. If not, write something to the logs and wait until it is.
// This is to simulate a shared resource during the build.
if !testLock.TryLock() {
log.Warn().Msg("Testing lock is not available!")
logs += "\nWaiting for lock..."
testLock.Lock()
}
defer testLock.Unlock()
// Simulate build time
logs += "\nSimulating build for step '" + payload.StepName + "'..."
time.Sleep(time.Duration(buildTime) * time.Millisecond)
if payload.SimulateStatus != nil {
status = *payload.SimulateStatus
} else if rand.Intn(2) == 0 {
status = "Failure"
}
// Randomly, 1 of 5 times, simulate a total server crash because of a
// test failure (like a Segfault in the test runner, for example),
// unless the CI_SERVER_CRASHABLE environment variable is set to
// "false".
if os.Getenv("CI_SERVER_CRASHABLE") == "false" {
break
}
if rand.Intn(5) == 0 {
log.Fatal().Msg("Oh no! The tests caused a server crash!")
}
default:
log.Error().Msg("Unknown step provided")
http.Error(w, "Unknown step!", http.StatusBadRequest)
return
}
duration := int(time.Since(startTime).Milliseconds())
logs += "\nStep '" + payload.StepName + "' completed with status: " + status
response := Response{
BuildLogs: logs,
Status: status,
DurationMs: duration,
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
const DEFAULT_SERVER_ADDR = ":8080"
func main() {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
serverAddr := os.Getenv("STEP_RUNNER_SERVER_ADDR")
if serverAddr == "" {
serverAddr = DEFAULT_SERVER_ADDR
}
log.Printf("Starting server on %s...", serverAddr)
http.HandleFunc("/step/trigger", stepTriggerHandler)
log.Err(http.ListenAndServe(serverAddr, nil)).Msg("Server done")
}