Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# For more information about the Codesphere teams see: https://github.com/orgs/codesphere-cloud/teams
#
# add users to groups at: https://github.com/orgs/codesphere-cloud/teams/dev/teams
# new groups should have dev as parent (or else one of the subgroups)
#
# IMPORTANT: only add groups as owners (below); never individual users.

# Global owners.
* @codesphere-cloud/architects
* @codesphere-cloud/cs-go
28 changes: 28 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go

name: Build & Test

on:
push:
branches:
- main
pull_request:

jobs:

build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'

- name: Build
run: make build

- name: Test
run: make test
24 changes: 24 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Lint
on:
push:
branches:
- main
pull_request:

permissions:
contents: read
pull-requests: read

jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
- name: golangci-lint
uses: golangci/golangci-lint-action@v7
with:
version: v2.0
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ OPENAPI_DIR = ./pkg/api/openapi_client
format:
go fmt ./...

check:
go vet ./...
lint:
golangci-lint run

test:
go test ./...
Expand Down
39 changes: 24 additions & 15 deletions cmd/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,10 @@ func (logCmd *LogCmd) RunE(_ *cobra.Command, args []string) (err error) {
if *logCmd.scope.workspaceId == 0 {
*logCmd.scope.workspaceId, err = strconv.Atoi(os.Getenv("CS_WORKSPACE_ID"))
if err != nil {
return fmt.Errorf("Failed to read env var: %e", err)
return fmt.Errorf("failed to read env var: %e", err)
}
if *logCmd.scope.workspaceId == 0 {
return errors.New("Workspace ID required, but not provided.")
return errors.New("workspace ID required, but not provided")
}
}

Expand All @@ -119,9 +119,9 @@ func (logCmd *LogCmd) RunE(_ *cobra.Command, args []string) (err error) {
return printLogsOfServer(&logCmd.scope)
}

logCmd.printAllLogs()
err = logCmd.printAllLogs()
if err != nil {
return fmt.Errorf("Failed to print logs: %e", err)
return fmt.Errorf("failed to print logs: %e", err)
}

return nil
Expand All @@ -132,20 +132,23 @@ func (l *LogCmd) printAllLogs() error {

replicas, err := cs.GetPipelineStatus(*l.scope.workspaceId, "run")
if err != nil {
return fmt.Errorf("Failed to get pipeline status: %e", err)
return fmt.Errorf("failed to get pipeline status: %e", err)
}

var wg sync.WaitGroup
for _, replica := range replicas {
for s, _ := range replica.Steps {
for s := range replica.Steps {
wg.Add(1)
go func() {
defer wg.Done()
scope := l.scope
*scope.step = s
*scope.replica = replica.Replica
prefix := fmt.Sprintf("|%-10s|%s", replica.Server, replica.Replica[len(replica.Replica)-11:])
printLogsOfReplica(prefix, &scope)
err = printLogsOfReplica(prefix, &scope)
if err != nil {
fmt.Printf("Error printling logs: %e\n", err)
}
}()
}
}
Expand Down Expand Up @@ -183,21 +186,24 @@ func printLogsOfEndpoint(prefix string, endpoint string) error {

req, err := http.NewRequestWithContext(ctx, "GET", endpoint, nil)
if err != nil {
return fmt.Errorf("Failed to construct request: %s", err)
return fmt.Errorf("failed to construct request: %s", err)
}

// Set the Accept header to indicate SSE
req.Header.Set("Accept", "text/event-stream")
cs.SetAuthoriziationHeader(req)
err = cs.SetAuthoriziationHeader(req)
if err != nil {
return fmt.Errorf("failed to set header: %e", err)
}

resp, err := http.DefaultClient.Do(req)
if err != nil {
return fmt.Errorf("Failed to request logs: %s", err)
return fmt.Errorf("failed to request logs: %e", err)
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()

if resp.StatusCode != http.StatusOK {
return fmt.Errorf("Log server responded with non-ok code: %d", resp.StatusCode)
return fmt.Errorf("log server responded with non-ok code: %d", resp.StatusCode)
}

reader := bufio.NewReader(resp.Body)
Expand All @@ -210,7 +216,7 @@ func printLogsOfEndpoint(prefix string, endpoint string) error {
if err == io.EOF {
return nil
}
return fmt.Errorf("Failed to parse log: %s", err)
return fmt.Errorf("failed to parse log: %s", err)
}

line = strings.TrimSpace(line)
Expand Down Expand Up @@ -247,9 +253,12 @@ func printLogsOfEndpoint(prefix string, endpoint string) error {
err := json.Unmarshal([]byte(sse.data), &log)
if err != nil {
var errRes ErrResponse
json.Unmarshal([]byte(sse.data), &errRes)
err = json.Unmarshal([]byte(sse.data), &errRes)
if err != nil {
return fmt.Errorf("error reading error json: %e", err)
}
return fmt.Errorf(
"Server responded with error: %d %s: %s",
"server responded with error: %d %s: %s",
errRes.Status, errRes.Title, errRes.Detail,
)
}
Expand Down
20 changes: 14 additions & 6 deletions pkg/cs/cs.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,28 +33,36 @@ func GetPipelineStatus(ws int, stage string) (res []ReplicaStatus, err error) {

status, err := Get(fmt.Sprintf("workspaces/%d/pipeline/%s", ws, stage))
if err != nil {
err = fmt.Errorf("Failed to get pipeline status: %e", err)
err = fmt.Errorf("failed to get pipeline status: %e", err)
return
}

json.Unmarshal(status, &res)
err = json.Unmarshal(status, &res)
if err != nil {
err = fmt.Errorf("Failed to unmarshal pipeline status: %e", err)
err = fmt.Errorf("failed to unmarshal pipeline status: %e", err)
return
}
return
}

func Get(path string) (body []byte, err error) {
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/%s", GetApiUrl(), strings.TrimPrefix(path, "/")), http.NoBody)
SetAuthoriziationHeader(req)
if err != nil {
err = fmt.Errorf("failed to create request: %e", err)
return
}
err = SetAuthoriziationHeader(req)
if err != nil {
err = fmt.Errorf("failed to set header: %e", err)
return
}

res, err := http.DefaultClient.Do(req)
if err != nil {
err = fmt.Errorf("GET failed: %e", err)
return
}
defer res.Body.Close()
defer func() { _ = res.Body.Close() }()
body, err = io.ReadAll(res.Body)
return
}
Expand All @@ -63,7 +71,7 @@ func SetAuthoriziationHeader(req *http.Request) error {

apiToken := os.Getenv("CS_TOKEN")
if apiToken == "" {
return errors.New("CS_TOKEN env var required, but not set.")
return errors.New("CS_TOKEN env var required, but not set")
}
req.Header.Set("Authorization", "Bearer "+apiToken)
return nil
Expand Down