style(ui): add package docs and mark unused parameters
Some checks failed
CI / build-and-test (push) Has been cancelled
Release / build (arm64, darwin) (push) Has been cancelled
Release / build (amd64, windows) (push) Has been cancelled
Release / build (arm64, linux) (push) Has been cancelled
Release / build (amd64, darwin) (push) Has been cancelled
Release / build (amd64, linux) (push) Has been cancelled
Release / release (push) Has been cancelled
Some checks failed
CI / build-and-test (push) Has been cancelled
Release / build (arm64, darwin) (push) Has been cancelled
Release / build (amd64, windows) (push) Has been cancelled
Release / build (arm64, linux) (push) Has been cancelled
Release / build (amd64, darwin) (push) Has been cancelled
Release / build (amd64, linux) (push) Has been cancelled
Release / release (push) Has been cancelled
Adds package-level documentation comments across cmd and internal packages. Marks unused function parameters with underscore prefix to satisfy linter requirements. Replaces if-else chains with switch statements for better readability. Explicitly ignores os.Setenv return value where error handling is not needed.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
// Copyright 2026 MarketAlly. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Package main provides the upload-helper CLI tool for reliable file uploads.
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
@@ -22,8 +22,8 @@ type cacheServerArgs struct {
|
||||
Port uint16
|
||||
}
|
||||
|
||||
func runCacheServer(ctx context.Context, configFile *string, cacheArgs *cacheServerArgs) func(cmd *cobra.Command, args []string) error {
|
||||
return func(cmd *cobra.Command, args []string) error {
|
||||
func runCacheServer(_ context.Context, configFile *string, cacheArgs *cacheServerArgs) func(cmd *cobra.Command, args []string) error {
|
||||
return func(_ *cobra.Command, _ []string) error {
|
||||
cfg, err := config.LoadDefault(*configFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid configuration: %w", err)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2022 The Gitea Authors and MarketAlly. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Package cmd provides the CLI commands for gitcaddy-runner.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
@@ -15,6 +16,7 @@ import (
|
||||
"git.marketally.com/gitcaddy/gitcaddy-runner/internal/pkg/ver"
|
||||
)
|
||||
|
||||
// Execute runs the root command for gitcaddy-runner CLI.
|
||||
func Execute(ctx context.Context) {
|
||||
// ./gitcaddy-runner
|
||||
rootCmd := &cobra.Command{
|
||||
|
||||
@@ -58,7 +58,7 @@ var (
|
||||
)
|
||||
|
||||
func runDaemon(ctx context.Context, daemArgs *daemonArgs, configFile *string) func(cmd *cobra.Command, args []string) error {
|
||||
return func(cmd *cobra.Command, args []string) error {
|
||||
return func(_ *cobra.Command, _ []string) error {
|
||||
cfg, err := config.LoadDefault(*configFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid configuration: %w", err)
|
||||
@@ -132,7 +132,7 @@ func runDaemon(ctx context.Context, daemArgs *daemonArgs, configFile *string) fu
|
||||
return err
|
||||
}
|
||||
// if dockerSocketPath passes the check, override DOCKER_HOST with dockerSocketPath
|
||||
os.Setenv("DOCKER_HOST", dockerSocketPath)
|
||||
_ = os.Setenv("DOCKER_HOST", dockerSocketPath)
|
||||
// empty cfg.Container.DockerHost means act_runner need to find an available docker host automatically
|
||||
// and assign the path to cfg.Container.DockerHost
|
||||
if cfg.Container.DockerHost == "" {
|
||||
@@ -182,21 +182,22 @@ func runDaemon(ctx context.Context, daemArgs *daemonArgs, configFile *string) fu
|
||||
capabilities := envcheck.DetectCapabilities(ctx, dockerHost, cfg.Container.WorkdirParent, globalConfig.Runner.Capacity)
|
||||
// Include initial bandwidth result if available
|
||||
capabilities.Bandwidth = bandwidthManager.GetLastResult()
|
||||
capabilitiesJson := capabilities.ToJSON()
|
||||
log.Infof("detected capabilities: %s", capabilitiesJson)
|
||||
capabilitiesJSON := capabilities.ToJSON()
|
||||
log.Infof("detected capabilities: %s", capabilitiesJSON)
|
||||
|
||||
// Check disk space and warn if low
|
||||
checkDiskSpaceAndCleanup(ctx, capabilities)
|
||||
|
||||
// declare the labels of the runner before fetching tasks
|
||||
resp, err := runner.Declare(ctx, ls.Names(), capabilitiesJson)
|
||||
if err != nil && connect.CodeOf(err) == connect.CodeUnimplemented {
|
||||
resp, err := runner.Declare(ctx, ls.Names(), capabilitiesJSON)
|
||||
switch {
|
||||
case err != nil && connect.CodeOf(err) == connect.CodeUnimplemented:
|
||||
log.Errorf("Your GitCaddy version is too old to support runner declare, please upgrade to v1.21 or later")
|
||||
return err
|
||||
} else if err != nil {
|
||||
case err != nil:
|
||||
log.WithError(err).Error("fail to invoke Declare")
|
||||
return err
|
||||
} else {
|
||||
default:
|
||||
log.Infof("runner: %s, with version: %s, with labels: %v, declare successfully",
|
||||
resp.Msg.Runner.Name, resp.Msg.Runner.Version, resp.Msg.Runner.Labels)
|
||||
}
|
||||
@@ -261,14 +262,15 @@ func checkDiskSpaceAndCleanup(ctx context.Context, capabilities *envcheck.Runner
|
||||
usedPercent := capabilities.Disk.UsedPercent
|
||||
freeGB := float64(capabilities.Disk.Free) / (1024 * 1024 * 1024)
|
||||
|
||||
if usedPercent >= DiskSpaceCriticalThreshold {
|
||||
switch {
|
||||
case usedPercent >= DiskSpaceCriticalThreshold:
|
||||
log.Errorf("CRITICAL: Disk space critically low! %.1f%% used, only %.2f GB free. Runner may fail to execute jobs!", usedPercent, freeGB)
|
||||
// Always try cleanup at critical level
|
||||
triggerAutoCleanup(ctx)
|
||||
} else if usedPercent >= DiskSpaceAutoCleanupThreshold {
|
||||
case usedPercent >= DiskSpaceAutoCleanupThreshold:
|
||||
log.Warnf("WARNING: Disk space at %.1f%% used (%.2f GB free). Triggering automatic cleanup.", usedPercent, freeGB)
|
||||
triggerAutoCleanup(ctx)
|
||||
} else if usedPercent >= DiskSpaceWarningThreshold {
|
||||
case usedPercent >= DiskSpaceWarningThreshold:
|
||||
log.Warnf("WARNING: Disk space running low. %.1f%% used, %.2f GB free. Consider cleaning up disk space.", usedPercent, freeGB)
|
||||
}
|
||||
}
|
||||
@@ -330,13 +332,13 @@ func periodicCapabilitiesUpdate(ctx context.Context, runner *run.Runner, labelNa
|
||||
capabilities.Bandwidth = bandwidthManager.GetLastResult()
|
||||
}
|
||||
|
||||
capabilitiesJson := capabilities.ToJSON()
|
||||
capabilitiesJSON := capabilities.ToJSON()
|
||||
|
||||
// Check for disk space warnings
|
||||
checkDiskSpaceAndCleanup(ctx, capabilities)
|
||||
|
||||
// Send updated capabilities to server
|
||||
_, err := runner.Declare(ctx, labelNames, capabilitiesJson)
|
||||
_, err := runner.Declare(ctx, labelNames, capabilitiesJSON)
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("failed to update capabilities")
|
||||
} else {
|
||||
|
||||
@@ -264,7 +264,7 @@ func printList(plan *model.Plan) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func runExecList(ctx context.Context, planner model.WorkflowPlanner, execArgs *executeArgs) error {
|
||||
func runExecList(_ context.Context, planner model.WorkflowPlanner, execArgs *executeArgs) error {
|
||||
// plan with filtered jobs - to be used for filtering only
|
||||
var filterPlan *model.Plan
|
||||
|
||||
@@ -286,19 +286,20 @@ func runExecList(ctx context.Context, planner model.WorkflowPlanner, execArgs *e
|
||||
}
|
||||
|
||||
var err error
|
||||
if execArgs.job != "" {
|
||||
switch {
|
||||
case execArgs.job != "":
|
||||
log.Infof("Preparing plan with a job: %s", execArgs.job)
|
||||
filterPlan, err = planner.PlanJob(execArgs.job)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if filterEventName != "" {
|
||||
case filterEventName != "":
|
||||
log.Infof("Preparing plan for a event: %s", filterEventName)
|
||||
filterPlan, err = planner.PlanEvent(filterEventName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
default:
|
||||
log.Infof("Preparing plan with all jobs")
|
||||
filterPlan, err = planner.PlanAll()
|
||||
if err != nil {
|
||||
@@ -312,7 +313,7 @@ func runExecList(ctx context.Context, planner model.WorkflowPlanner, execArgs *e
|
||||
}
|
||||
|
||||
func runExec(ctx context.Context, execArgs *executeArgs) func(cmd *cobra.Command, args []string) error {
|
||||
return func(cmd *cobra.Command, args []string) error {
|
||||
return func(_ *cobra.Command, _ []string) error {
|
||||
planner, err := model.NewWorkflowPlanner(execArgs.WorkflowsPath(), execArgs.noWorkflowRecurse)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -331,18 +332,19 @@ func runExec(ctx context.Context, execArgs *executeArgs) func(cmd *cobra.Command
|
||||
// collect all events from loaded workflows
|
||||
events := planner.GetEvents()
|
||||
|
||||
if len(execArgs.event) > 0 {
|
||||
switch {
|
||||
case len(execArgs.event) > 0:
|
||||
log.Infof("Using chosed event for filtering: %s", execArgs.event)
|
||||
eventName = execArgs.event
|
||||
} else if len(events) == 1 && len(events[0]) > 0 {
|
||||
case len(events) == 1 && len(events[0]) > 0:
|
||||
log.Infof("Using the only detected workflow event: %s", events[0])
|
||||
eventName = events[0]
|
||||
} else if execArgs.autodetectEvent && len(events) > 0 && len(events[0]) > 0 {
|
||||
case execArgs.autodetectEvent && len(events) > 0 && len(events[0]) > 0:
|
||||
// set default event type to first event from many available
|
||||
// this way user dont have to specify the event.
|
||||
log.Infof("Using first detected workflow event: %s", events[0])
|
||||
eventName = events[0]
|
||||
} else {
|
||||
default:
|
||||
log.Infof("Using default workflow event: push")
|
||||
eventName = "push"
|
||||
}
|
||||
@@ -388,7 +390,7 @@ func runExec(ctx context.Context, execArgs *executeArgs) func(cmd *cobra.Command
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
defer func() { _ = os.RemoveAll(tempDir) }()
|
||||
|
||||
execArgs.artifactServerPath = tempDir
|
||||
}
|
||||
@@ -454,7 +456,7 @@ func runExec(ctx context.Context, execArgs *executeArgs) func(cmd *cobra.Command
|
||||
log.Debugf("artifacts server started at %s:%s", execArgs.artifactServerPath, execArgs.artifactServerPort)
|
||||
|
||||
ctx = common.WithDryrun(ctx, execArgs.dryrun)
|
||||
executor := r.NewPlanExecutor(plan).Finally(func(ctx context.Context) error {
|
||||
executor := r.NewPlanExecutor(plan).Finally(func(_ context.Context) error {
|
||||
artifactCancel()
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
|
||||
// runRegister registers a runner to the server
|
||||
func runRegister(ctx context.Context, regArgs *registerArgs, configFile *string) func(*cobra.Command, []string) error {
|
||||
return func(cmd *cobra.Command, args []string) error {
|
||||
return func(_ *cobra.Command, _ []string) error {
|
||||
log.SetReportCaller(false)
|
||||
isTerm := isatty.IsTerminal(os.Stdout.Fd())
|
||||
log.SetFormatter(&log.TextFormatter{
|
||||
@@ -80,6 +80,7 @@ type registerArgs struct {
|
||||
|
||||
type registerStage int8
|
||||
|
||||
// Register stage constants define the steps in the registration workflow.
|
||||
const (
|
||||
StageUnknown registerStage = -1
|
||||
StageOverwriteLocalConfig registerStage = iota + 1
|
||||
@@ -250,7 +251,7 @@ func registerInteractive(ctx context.Context, configFile string, regArgs *regist
|
||||
if stage == StageWaitingForRegistration {
|
||||
log.Infof("Registering runner, name=%s, instance=%s, labels=%v.", inputs.RunnerName, inputs.InstanceAddr, inputs.Labels)
|
||||
if err := doRegister(ctx, cfg, inputs); err != nil {
|
||||
return fmt.Errorf("Failed to register runner: %w", err)
|
||||
return fmt.Errorf("failed to register runner: %w", err)
|
||||
}
|
||||
log.Infof("Runner registered successfully.")
|
||||
return nil
|
||||
@@ -311,7 +312,7 @@ func registerNoInteractive(ctx context.Context, configFile string, regArgs *regi
|
||||
return err
|
||||
}
|
||||
if err := doRegister(ctx, cfg, inputs); err != nil {
|
||||
return fmt.Errorf("Failed to register runner: %w", err)
|
||||
return fmt.Errorf("failed to register runner: %w", err)
|
||||
}
|
||||
log.Infof("Runner registered successfully.")
|
||||
return nil
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2023 The Gitea Authors and MarketAlly. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Package poll provides task polling functionality for CI runners.
|
||||
package poll
|
||||
|
||||
import (
|
||||
@@ -22,6 +23,7 @@ import (
|
||||
"git.marketally.com/gitcaddy/gitcaddy-runner/internal/pkg/envcheck"
|
||||
)
|
||||
|
||||
// Poller handles task polling from the Gitea server.
|
||||
type Poller struct {
|
||||
client client.Client
|
||||
runner *run.Runner
|
||||
@@ -38,6 +40,7 @@ type Poller struct {
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
// New creates a new Poller instance.
|
||||
func New(cfg *config.Config, client client.Client, runner *run.Runner) *Poller {
|
||||
pollingCtx, shutdownPolling := context.WithCancel(context.Background())
|
||||
|
||||
@@ -65,6 +68,7 @@ func (p *Poller) SetBandwidthManager(bm *envcheck.BandwidthManager) {
|
||||
p.bandwidthManager = bm
|
||||
}
|
||||
|
||||
// Poll starts polling for tasks with the configured capacity.
|
||||
func (p *Poller) Poll() {
|
||||
limiter := rate.NewLimiter(rate.Every(p.cfg.Runner.FetchInterval), 1)
|
||||
wg := &sync.WaitGroup{}
|
||||
@@ -78,6 +82,7 @@ func (p *Poller) Poll() {
|
||||
close(p.done)
|
||||
}
|
||||
|
||||
// PollOnce polls for a single task and then exits.
|
||||
func (p *Poller) PollOnce() {
|
||||
limiter := rate.NewLimiter(rate.Every(p.cfg.Runner.FetchInterval), 1)
|
||||
|
||||
@@ -87,18 +92,19 @@ func (p *Poller) PollOnce() {
|
||||
close(p.done)
|
||||
}
|
||||
|
||||
// Shutdown gracefully stops the poller.
|
||||
func (p *Poller) Shutdown(ctx context.Context) error {
|
||||
p.shutdownPolling()
|
||||
|
||||
select {
|
||||
// graceful shutdown completed succesfully
|
||||
// graceful shutdown completed successfully
|
||||
case <-p.done:
|
||||
return nil
|
||||
|
||||
// our timeout for shutting down ran out
|
||||
case <-ctx.Done():
|
||||
// when both the timeout fires and the graceful shutdown
|
||||
// completed succsfully, this branch of the select may
|
||||
// completed successfully, this branch of the select may
|
||||
// fire. Do a non-blocking check here against the graceful
|
||||
// shutdown status to avoid sending an error if we don't need to.
|
||||
_, ok := <-p.done
|
||||
@@ -110,7 +116,7 @@ func (p *Poller) Shutdown(ctx context.Context) error {
|
||||
p.shutdownJobs()
|
||||
|
||||
// wait for running jobs to report their status to Gitea
|
||||
_, _ = <-p.done
|
||||
<-p.done
|
||||
|
||||
return ctx.Err()
|
||||
}
|
||||
@@ -173,13 +179,13 @@ func (p *Poller) fetchTask(ctx context.Context) (*runnerv1.Task, bool) {
|
||||
caps.Bandwidth = p.bandwidthManager.GetLastResult()
|
||||
}
|
||||
|
||||
capsJson := caps.ToJSON()
|
||||
capsJSON := caps.ToJSON()
|
||||
|
||||
// Load the version value that was in the cache when the request was sent.
|
||||
v := p.tasksVersion.Load()
|
||||
fetchReq := &runnerv1.FetchTaskRequest{
|
||||
TasksVersion: v,
|
||||
CapabilitiesJson: capsJson,
|
||||
CapabilitiesJson: capsJSON,
|
||||
}
|
||||
resp, err := p.client.FetchTask(reqCtx, connect.NewRequest(fetchReq))
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Package run provides the core runner functionality for executing tasks.
|
||||
package run
|
||||
|
||||
import (
|
||||
|
||||
@@ -85,6 +85,7 @@ func (r *Runner) CleanStaleJobCaches(maxAge time.Duration) {
|
||||
}
|
||||
}
|
||||
|
||||
// NewRunner creates a new Runner with the given configuration, registration, and client.
|
||||
func NewRunner(cfg *config.Config, reg *config.Registration, cli client.Client) *Runner {
|
||||
ls := labels.Labels{}
|
||||
for _, v := range reg.Labels {
|
||||
@@ -133,6 +134,7 @@ func NewRunner(cfg *config.Config, reg *config.Registration, cli client.Client)
|
||||
}
|
||||
}
|
||||
|
||||
// Run executes a task from the server.
|
||||
func (r *Runner) Run(ctx context.Context, task *runnerv1.Task) error {
|
||||
if _, ok := r.runningTasks.Load(task.Id); ok {
|
||||
return fmt.Errorf("task %d is already running", task.Id)
|
||||
@@ -161,7 +163,7 @@ func (r *Runner) Run(ctx context.Context, task *runnerv1.Task) error {
|
||||
// getDefaultActionsURL
|
||||
// when DEFAULT_ACTIONS_URL == "https://github.com" and GithubMirror is not blank,
|
||||
// it should be set to GithubMirror first.
|
||||
func (r *Runner) getDefaultActionsURL(ctx context.Context, task *runnerv1.Task) string {
|
||||
func (r *Runner) getDefaultActionsURL(_ context.Context, task *runnerv1.Task) string {
|
||||
giteaDefaultActionsURL := task.Context.Fields["gitea_default_actions_url"].GetStringValue()
|
||||
if giteaDefaultActionsURL == "https://github.com" && r.cfg.Runner.GithubMirror != "" {
|
||||
return r.cfg.Runner.GithubMirror
|
||||
@@ -219,8 +221,8 @@ func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report.
|
||||
preset.Token = t
|
||||
}
|
||||
|
||||
if actionsIdTokenRequestUrl := taskContext["actions_id_token_request_url"].GetStringValue(); actionsIdTokenRequestUrl != "" {
|
||||
r.envs["ACTIONS_ID_TOKEN_REQUEST_URL"] = actionsIdTokenRequestUrl
|
||||
if actionsIDTokenRequestURL := taskContext["actions_id_token_request_url"].GetStringValue(); actionsIDTokenRequestURL != "" {
|
||||
r.envs["ACTIONS_ID_TOKEN_REQUEST_URL"] = actionsIDTokenRequestURL
|
||||
r.envs["ACTIONS_ID_TOKEN_REQUEST_TOKEN"] = taskContext["actions_id_token_request_token"].GetStringValue()
|
||||
task.Secrets["ACTIONS_ID_TOKEN_REQUEST_TOKEN"] = r.envs["ACTIONS_ID_TOKEN_REQUEST_TOKEN"]
|
||||
}
|
||||
@@ -305,10 +307,11 @@ func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report.
|
||||
return execErr
|
||||
}
|
||||
|
||||
func (r *Runner) Declare(ctx context.Context, labels []string, capabilitiesJson string) (*connect.Response[runnerv1.DeclareResponse], error) {
|
||||
// Declare sends the runner's labels and capabilities to the server.
|
||||
func (r *Runner) Declare(ctx context.Context, labels []string, capabilitiesJSON string) (*connect.Response[runnerv1.DeclareResponse], error) {
|
||||
return r.client.Declare(ctx, connect.NewRequest(&runnerv1.DeclareRequest{
|
||||
Version: ver.Version(),
|
||||
Labels: labels,
|
||||
CapabilitiesJson: capabilitiesJson,
|
||||
CapabilitiesJson: capabilitiesJSON,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2026 MarketAlly. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Package artifact provides utilities for handling artifact uploads.
|
||||
package artifact
|
||||
|
||||
import (
|
||||
@@ -88,7 +89,7 @@ func (u *UploadHelper) prewarmConnection(url string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp.Body.Close()
|
||||
_ = resp.Body.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -98,7 +99,7 @@ func (u *UploadHelper) doUpload(client *http.Client, url, token, filepath string
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open file: %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
defer func() { _ = file.Close() }()
|
||||
|
||||
stat, err := file.Stat()
|
||||
if err != nil {
|
||||
@@ -118,7 +119,7 @@ func (u *UploadHelper) doUpload(client *http.Client, url, token, filepath string
|
||||
if _, err := io.Copy(part, file); err != nil {
|
||||
return fmt.Errorf("failed to copy file to form: %w", err)
|
||||
}
|
||||
writer.Close()
|
||||
_ = writer.Close()
|
||||
|
||||
req, err := http.NewRequest("POST", url, body)
|
||||
if err != nil {
|
||||
@@ -133,7 +134,7 @@ func (u *UploadHelper) doUpload(client *http.Client, url, token, filepath string
|
||||
if err != nil {
|
||||
return fmt.Errorf("upload request failed: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
respBody, _ := io.ReadAll(resp.Body)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Package client provides the HTTP client for communicating with the runner API.
|
||||
package client
|
||||
|
||||
import (
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
package client
|
||||
|
||||
// HTTP header constants for runner authentication and identification.
|
||||
const (
|
||||
UUIDHeader = "x-runner-uuid"
|
||||
TokenHeader = "x-runner-token"
|
||||
|
||||
@@ -63,10 +63,12 @@ func New(endpoint string, insecure bool, uuid, token, version string, opts ...co
|
||||
}
|
||||
}
|
||||
|
||||
// Address returns the endpoint URL of the client.
|
||||
func (c *HTTPClient) Address() string {
|
||||
return c.endpoint
|
||||
}
|
||||
|
||||
// Insecure returns whether TLS verification is disabled.
|
||||
func (c *HTTPClient) Insecure() bool {
|
||||
return c.insecure
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Package config provides configuration loading and management for the runner.
|
||||
package config
|
||||
|
||||
import (
|
||||
|
||||
@@ -5,5 +5,7 @@ package config
|
||||
|
||||
import _ "embed"
|
||||
|
||||
// Example contains the example configuration file content.
|
||||
//
|
||||
//go:embed config.example.yaml
|
||||
var Example []byte
|
||||
|
||||
@@ -23,12 +23,13 @@ type Registration struct {
|
||||
Ephemeral bool `json:"ephemeral"`
|
||||
}
|
||||
|
||||
// LoadRegistration loads the runner registration from a JSON file.
|
||||
func LoadRegistration(file string) (*Registration, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
defer func() { _ = f.Close() }()
|
||||
|
||||
var reg Registration
|
||||
if err := json.NewDecoder(f).Decode(®); err != nil {
|
||||
@@ -40,12 +41,13 @@ func LoadRegistration(file string) (*Registration, error) {
|
||||
return ®, nil
|
||||
}
|
||||
|
||||
// SaveRegistration saves the runner registration to a JSON file.
|
||||
func SaveRegistration(file string, reg *Registration) error {
|
||||
f, err := os.Create(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
defer func() { _ = f.Close() }()
|
||||
|
||||
reg.Warning = registrationWarning
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ func testLatency(ctx context.Context, serverURL string) float64 {
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
resp.Body.Close()
|
||||
_ = resp.Body.Close()
|
||||
|
||||
latency := time.Since(start).Seconds() * 1000 // Convert to ms
|
||||
return float64(int(latency*100)) / 100 // Round to 2 decimals
|
||||
@@ -169,7 +169,7 @@ func testDownloadSpeed(ctx context.Context, serverURL string) float64 {
|
||||
}
|
||||
|
||||
n, _ := io.Copy(io.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
_ = resp.Body.Close()
|
||||
cancel()
|
||||
|
||||
duration := time.Since(start)
|
||||
|
||||
@@ -83,7 +83,7 @@ type CapabilityFeatures struct {
|
||||
// DetectCapabilities detects the runner's capabilities
|
||||
// workingDir is the directory where builds will run (for disk space detection)
|
||||
func DetectCapabilities(ctx context.Context, dockerHost string, workingDir string, capacity int) *RunnerCapabilities {
|
||||
cap := &RunnerCapabilities{
|
||||
caps := &RunnerCapabilities{
|
||||
Capacity: capacity,
|
||||
OS: runtime.GOOS,
|
||||
Arch: runtime.GOARCH,
|
||||
@@ -105,40 +105,40 @@ func DetectCapabilities(ctx context.Context, dockerHost string, workingDir strin
|
||||
|
||||
// Detect Linux distribution
|
||||
if runtime.GOOS == "linux" {
|
||||
cap.Distro = detectLinuxDistro()
|
||||
caps.Distro = detectLinuxDistro()
|
||||
}
|
||||
|
||||
// Detect macOS Xcode/iOS
|
||||
if runtime.GOOS == "darwin" {
|
||||
cap.Xcode = detectXcode(ctx)
|
||||
caps.Xcode = detectXcode(ctx)
|
||||
}
|
||||
|
||||
// Detect Docker
|
||||
cap.Docker, cap.ContainerRuntime = detectDocker(ctx, dockerHost)
|
||||
if cap.Docker {
|
||||
cap.DockerCompose = detectDockerCompose(ctx)
|
||||
cap.Features.Services = true
|
||||
caps.Docker, caps.ContainerRuntime = detectDocker(ctx, dockerHost)
|
||||
if caps.Docker {
|
||||
caps.DockerCompose = detectDockerCompose(ctx)
|
||||
caps.Features.Services = true
|
||||
}
|
||||
|
||||
// Detect common tools
|
||||
detectTools(ctx, cap)
|
||||
detectTools(ctx, caps)
|
||||
|
||||
// Detect build tools
|
||||
detectBuildTools(ctx, cap)
|
||||
detectBuildTools(ctx, caps)
|
||||
|
||||
// Detect package managers
|
||||
detectPackageManagers(ctx, cap)
|
||||
detectPackageManagers(ctx, caps)
|
||||
|
||||
// Detect disk space on the working directory's filesystem
|
||||
cap.Disk = detectDiskSpace(workingDir)
|
||||
caps.Disk = detectDiskSpace(workingDir)
|
||||
|
||||
// Detect CPU load
|
||||
cap.CPU = detectCPULoad()
|
||||
caps.CPU = detectCPULoad()
|
||||
|
||||
// Generate suggested labels based on detected capabilities
|
||||
cap.SuggestedLabels = generateSuggestedLabels(cap)
|
||||
caps.SuggestedLabels = generateSuggestedLabels(caps)
|
||||
|
||||
return cap
|
||||
return caps
|
||||
}
|
||||
|
||||
// detectXcode detects Xcode and iOS development capabilities on macOS
|
||||
@@ -227,18 +227,19 @@ func detectLinuxDistro() *DistroInfo {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer file.Close()
|
||||
defer func() { _ = file.Close() }()
|
||||
|
||||
distro := &DistroInfo{}
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.HasPrefix(line, "ID=") {
|
||||
switch {
|
||||
case strings.HasPrefix(line, "ID="):
|
||||
distro.ID = strings.Trim(strings.TrimPrefix(line, "ID="), "\"")
|
||||
} else if strings.HasPrefix(line, "VERSION_ID=") {
|
||||
case strings.HasPrefix(line, "VERSION_ID="):
|
||||
distro.VersionID = strings.Trim(strings.TrimPrefix(line, "VERSION_ID="), "\"")
|
||||
} else if strings.HasPrefix(line, "PRETTY_NAME=") {
|
||||
case strings.HasPrefix(line, "PRETTY_NAME="):
|
||||
distro.PrettyName = strings.Trim(strings.TrimPrefix(line, "PRETTY_NAME="), "\"")
|
||||
}
|
||||
}
|
||||
@@ -251,7 +252,7 @@ func detectLinuxDistro() *DistroInfo {
|
||||
}
|
||||
|
||||
// generateSuggestedLabels creates industry-standard labels based on capabilities
|
||||
func generateSuggestedLabels(cap *RunnerCapabilities) []string {
|
||||
func generateSuggestedLabels(caps *RunnerCapabilities) []string {
|
||||
labels := []string{}
|
||||
seen := make(map[string]bool)
|
||||
|
||||
@@ -263,7 +264,7 @@ func generateSuggestedLabels(cap *RunnerCapabilities) []string {
|
||||
}
|
||||
|
||||
// OS labels
|
||||
switch cap.OS {
|
||||
switch caps.OS {
|
||||
case "linux":
|
||||
addLabel("linux")
|
||||
addLabel("linux-latest")
|
||||
@@ -276,17 +277,17 @@ func generateSuggestedLabels(cap *RunnerCapabilities) []string {
|
||||
}
|
||||
|
||||
// Distro labels (Linux only)
|
||||
if cap.Distro != nil && cap.Distro.ID != "" {
|
||||
distro := strings.ToLower(cap.Distro.ID)
|
||||
if caps.Distro != nil && caps.Distro.ID != "" {
|
||||
distro := strings.ToLower(caps.Distro.ID)
|
||||
addLabel(distro)
|
||||
addLabel(distro + "-latest")
|
||||
}
|
||||
|
||||
// Xcode/iOS labels (macOS only)
|
||||
if cap.Xcode != nil {
|
||||
if caps.Xcode != nil {
|
||||
addLabel("xcode")
|
||||
// Check for SDKs
|
||||
for _, sdk := range cap.Xcode.SDKs {
|
||||
for _, sdk := range caps.Xcode.SDKs {
|
||||
sdkLower := strings.ToLower(sdk)
|
||||
if strings.Contains(sdkLower, "ios") {
|
||||
addLabel("ios")
|
||||
@@ -302,24 +303,24 @@ func generateSuggestedLabels(cap *RunnerCapabilities) []string {
|
||||
}
|
||||
}
|
||||
// If simulators available, add simulator label
|
||||
if len(cap.Xcode.Simulators) > 0 {
|
||||
if len(caps.Xcode.Simulators) > 0 {
|
||||
addLabel("ios-simulator")
|
||||
}
|
||||
}
|
||||
|
||||
// Tool-based labels
|
||||
if _, ok := cap.Tools["dotnet"]; ok {
|
||||
if _, ok := caps.Tools["dotnet"]; ok {
|
||||
addLabel("dotnet")
|
||||
}
|
||||
if _, ok := cap.Tools["java"]; ok {
|
||||
if _, ok := caps.Tools["java"]; ok {
|
||||
addLabel("java")
|
||||
}
|
||||
if _, ok := cap.Tools["node"]; ok {
|
||||
if _, ok := caps.Tools["node"]; ok {
|
||||
addLabel("node")
|
||||
}
|
||||
|
||||
// Build tool labels
|
||||
for _, tool := range cap.BuildTools {
|
||||
for _, tool := range caps.BuildTools {
|
||||
switch tool {
|
||||
case "msbuild":
|
||||
addLabel("msbuild")
|
||||
@@ -384,7 +385,7 @@ func detectDocker(ctx context.Context, dockerHost string) (bool, string) {
|
||||
if err != nil {
|
||||
return false, ""
|
||||
}
|
||||
defer cli.Close()
|
||||
defer func() { _ = cli.Close() }()
|
||||
|
||||
timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
@@ -420,7 +421,7 @@ func detectDockerCompose(ctx context.Context) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func detectTools(ctx context.Context, cap *RunnerCapabilities) {
|
||||
func detectTools(ctx context.Context, caps *RunnerCapabilities) {
|
||||
toolDetectors := map[string]func(context.Context) []string{
|
||||
"node": detectNodeVersions,
|
||||
"go": detectGoVersions,
|
||||
@@ -439,7 +440,7 @@ func detectTools(ctx context.Context, cap *RunnerCapabilities) {
|
||||
|
||||
for tool, detector := range toolDetectors {
|
||||
if versions := detector(ctx); len(versions) > 0 {
|
||||
cap.Tools[tool] = versions
|
||||
caps.Tools[tool] = versions
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,23 +461,23 @@ func detectTools(ctx context.Context, cap *RunnerCapabilities) {
|
||||
|
||||
for name, cmd := range simpleTools {
|
||||
if v := detectSimpleToolVersion(ctx, cmd); v != "" {
|
||||
cap.Tools[name] = []string{v}
|
||||
caps.Tools[name] = []string{v}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func detectBuildTools(ctx context.Context, cap *RunnerCapabilities) {
|
||||
func detectBuildTools(ctx context.Context, caps *RunnerCapabilities) {
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
detectWindowsBuildTools(ctx, cap)
|
||||
detectWindowsBuildTools(ctx, caps)
|
||||
case "darwin":
|
||||
detectMacOSBuildTools(ctx, cap)
|
||||
detectMacOSBuildTools(caps)
|
||||
case "linux":
|
||||
detectLinuxBuildTools(ctx, cap)
|
||||
detectLinuxBuildTools(caps)
|
||||
}
|
||||
}
|
||||
|
||||
func detectWindowsBuildTools(ctx context.Context, cap *RunnerCapabilities) {
|
||||
func detectWindowsBuildTools(ctx context.Context, caps *RunnerCapabilities) {
|
||||
// Check for Visual Studio via vswhere
|
||||
vswherePaths := []string{
|
||||
`C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe`,
|
||||
@@ -486,7 +487,7 @@ func detectWindowsBuildTools(ctx context.Context, cap *RunnerCapabilities) {
|
||||
if _, err := os.Stat(vswhere); err == nil {
|
||||
cmd := exec.CommandContext(ctx, vswhere, "-latest", "-property", "displayName")
|
||||
if output, err := cmd.Output(); err == nil && len(output) > 0 {
|
||||
cap.BuildTools = append(cap.BuildTools, "visual-studio")
|
||||
caps.BuildTools = append(caps.BuildTools, "visual-studio")
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -503,7 +504,7 @@ func detectWindowsBuildTools(ctx context.Context, cap *RunnerCapabilities) {
|
||||
}
|
||||
for _, msbuild := range msbuildPaths {
|
||||
if _, err := os.Stat(msbuild); err == nil {
|
||||
cap.BuildTools = append(cap.BuildTools, "msbuild")
|
||||
caps.BuildTools = append(caps.BuildTools, "msbuild")
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -517,14 +518,14 @@ func detectWindowsBuildTools(ctx context.Context, cap *RunnerCapabilities) {
|
||||
}
|
||||
for _, iscc := range innoSetupPaths {
|
||||
if _, err := os.Stat(iscc); err == nil {
|
||||
cap.BuildTools = append(cap.BuildTools, "inno-setup")
|
||||
caps.BuildTools = append(caps.BuildTools, "inno-setup")
|
||||
break
|
||||
}
|
||||
}
|
||||
// Also check PATH
|
||||
if _, err := exec.LookPath("iscc"); err == nil {
|
||||
if !contains(cap.BuildTools, "inno-setup") {
|
||||
cap.BuildTools = append(cap.BuildTools, "inno-setup")
|
||||
if !contains(caps.BuildTools, "inno-setup") {
|
||||
caps.BuildTools = append(caps.BuildTools, "inno-setup")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -535,13 +536,13 @@ func detectWindowsBuildTools(ctx context.Context, cap *RunnerCapabilities) {
|
||||
}
|
||||
for _, nsis := range nsisPaths {
|
||||
if _, err := os.Stat(nsis); err == nil {
|
||||
cap.BuildTools = append(cap.BuildTools, "nsis")
|
||||
caps.BuildTools = append(caps.BuildTools, "nsis")
|
||||
break
|
||||
}
|
||||
}
|
||||
if _, err := exec.LookPath("makensis"); err == nil {
|
||||
if !contains(cap.BuildTools, "nsis") {
|
||||
cap.BuildTools = append(cap.BuildTools, "nsis")
|
||||
if !contains(caps.BuildTools, "nsis") {
|
||||
caps.BuildTools = append(caps.BuildTools, "nsis")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -552,7 +553,7 @@ func detectWindowsBuildTools(ctx context.Context, cap *RunnerCapabilities) {
|
||||
}
|
||||
for _, wix := range wixPaths {
|
||||
if _, err := os.Stat(wix); err == nil {
|
||||
cap.BuildTools = append(cap.BuildTools, "wix")
|
||||
caps.BuildTools = append(caps.BuildTools, "wix")
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -560,63 +561,63 @@ func detectWindowsBuildTools(ctx context.Context, cap *RunnerCapabilities) {
|
||||
// Check for signtool (Windows SDK)
|
||||
signtoolPaths, _ := filepath.Glob(`C:\Program Files (x86)\Windows Kits\10\bin\*\x64\signtool.exe`)
|
||||
if len(signtoolPaths) > 0 {
|
||||
cap.BuildTools = append(cap.BuildTools, "signtool")
|
||||
caps.BuildTools = append(caps.BuildTools, "signtool")
|
||||
}
|
||||
}
|
||||
|
||||
func detectMacOSBuildTools(ctx context.Context, cap *RunnerCapabilities) {
|
||||
func detectMacOSBuildTools(caps *RunnerCapabilities) {
|
||||
// Check for xcpretty
|
||||
if _, err := exec.LookPath("xcpretty"); err == nil {
|
||||
cap.BuildTools = append(cap.BuildTools, "xcpretty")
|
||||
caps.BuildTools = append(caps.BuildTools, "xcpretty")
|
||||
}
|
||||
|
||||
// Check for fastlane
|
||||
if _, err := exec.LookPath("fastlane"); err == nil {
|
||||
cap.BuildTools = append(cap.BuildTools, "fastlane")
|
||||
caps.BuildTools = append(caps.BuildTools, "fastlane")
|
||||
}
|
||||
|
||||
// Check for CocoaPods
|
||||
if _, err := exec.LookPath("pod"); err == nil {
|
||||
cap.BuildTools = append(cap.BuildTools, "cocoapods")
|
||||
caps.BuildTools = append(caps.BuildTools, "cocoapods")
|
||||
}
|
||||
|
||||
// Check for Carthage
|
||||
if _, err := exec.LookPath("carthage"); err == nil {
|
||||
cap.BuildTools = append(cap.BuildTools, "carthage")
|
||||
caps.BuildTools = append(caps.BuildTools, "carthage")
|
||||
}
|
||||
|
||||
// Check for SwiftLint
|
||||
if _, err := exec.LookPath("swiftlint"); err == nil {
|
||||
cap.BuildTools = append(cap.BuildTools, "swiftlint")
|
||||
caps.BuildTools = append(caps.BuildTools, "swiftlint")
|
||||
}
|
||||
|
||||
// Check for create-dmg or similar
|
||||
if _, err := exec.LookPath("create-dmg"); err == nil {
|
||||
cap.BuildTools = append(cap.BuildTools, "create-dmg")
|
||||
caps.BuildTools = append(caps.BuildTools, "create-dmg")
|
||||
}
|
||||
|
||||
// Check for Packages (packagesbuild)
|
||||
if _, err := exec.LookPath("packagesbuild"); err == nil {
|
||||
cap.BuildTools = append(cap.BuildTools, "packages")
|
||||
caps.BuildTools = append(caps.BuildTools, "packages")
|
||||
}
|
||||
|
||||
// Check for pkgbuild (built-in)
|
||||
if _, err := exec.LookPath("pkgbuild"); err == nil {
|
||||
cap.BuildTools = append(cap.BuildTools, "pkgbuild")
|
||||
caps.BuildTools = append(caps.BuildTools, "pkgbuild")
|
||||
}
|
||||
|
||||
// Check for codesign (built-in)
|
||||
if _, err := exec.LookPath("codesign"); err == nil {
|
||||
cap.BuildTools = append(cap.BuildTools, "codesign")
|
||||
caps.BuildTools = append(caps.BuildTools, "codesign")
|
||||
}
|
||||
|
||||
// Check for notarytool (built-in with Xcode)
|
||||
if _, err := exec.LookPath("notarytool"); err == nil {
|
||||
cap.BuildTools = append(cap.BuildTools, "notarytool")
|
||||
caps.BuildTools = append(caps.BuildTools, "notarytool")
|
||||
}
|
||||
}
|
||||
|
||||
func detectLinuxBuildTools(ctx context.Context, cap *RunnerCapabilities) {
|
||||
func detectLinuxBuildTools(caps *RunnerCapabilities) {
|
||||
// Check for common Linux build tools
|
||||
tools := []string{
|
||||
"gcc", "g++", "clang", "clang++",
|
||||
@@ -628,54 +629,54 @@ func detectLinuxBuildTools(ctx context.Context, cap *RunnerCapabilities) {
|
||||
|
||||
for _, tool := range tools {
|
||||
if _, err := exec.LookPath(tool); err == nil {
|
||||
cap.BuildTools = append(cap.BuildTools, tool)
|
||||
caps.BuildTools = append(caps.BuildTools, tool)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func detectPackageManagers(ctx context.Context, cap *RunnerCapabilities) {
|
||||
func detectPackageManagers(_ context.Context, caps *RunnerCapabilities) {
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
if _, err := exec.LookPath("choco"); err == nil {
|
||||
cap.PackageManagers = append(cap.PackageManagers, "chocolatey")
|
||||
caps.PackageManagers = append(caps.PackageManagers, "chocolatey")
|
||||
}
|
||||
if _, err := exec.LookPath("scoop"); err == nil {
|
||||
cap.PackageManagers = append(cap.PackageManagers, "scoop")
|
||||
caps.PackageManagers = append(caps.PackageManagers, "scoop")
|
||||
}
|
||||
if _, err := exec.LookPath("winget"); err == nil {
|
||||
cap.PackageManagers = append(cap.PackageManagers, "winget")
|
||||
caps.PackageManagers = append(caps.PackageManagers, "winget")
|
||||
}
|
||||
case "darwin":
|
||||
if _, err := exec.LookPath("brew"); err == nil {
|
||||
cap.PackageManagers = append(cap.PackageManagers, "homebrew")
|
||||
caps.PackageManagers = append(caps.PackageManagers, "homebrew")
|
||||
}
|
||||
if _, err := exec.LookPath("port"); err == nil {
|
||||
cap.PackageManagers = append(cap.PackageManagers, "macports")
|
||||
caps.PackageManagers = append(caps.PackageManagers, "macports")
|
||||
}
|
||||
case "linux":
|
||||
if _, err := exec.LookPath("apt"); err == nil {
|
||||
cap.PackageManagers = append(cap.PackageManagers, "apt")
|
||||
caps.PackageManagers = append(caps.PackageManagers, "apt")
|
||||
}
|
||||
if _, err := exec.LookPath("yum"); err == nil {
|
||||
cap.PackageManagers = append(cap.PackageManagers, "yum")
|
||||
caps.PackageManagers = append(caps.PackageManagers, "yum")
|
||||
}
|
||||
if _, err := exec.LookPath("dnf"); err == nil {
|
||||
cap.PackageManagers = append(cap.PackageManagers, "dnf")
|
||||
caps.PackageManagers = append(caps.PackageManagers, "dnf")
|
||||
}
|
||||
if _, err := exec.LookPath("pacman"); err == nil {
|
||||
cap.PackageManagers = append(cap.PackageManagers, "pacman")
|
||||
caps.PackageManagers = append(caps.PackageManagers, "pacman")
|
||||
}
|
||||
if _, err := exec.LookPath("zypper"); err == nil {
|
||||
cap.PackageManagers = append(cap.PackageManagers, "zypper")
|
||||
caps.PackageManagers = append(caps.PackageManagers, "zypper")
|
||||
}
|
||||
if _, err := exec.LookPath("apk"); err == nil {
|
||||
cap.PackageManagers = append(cap.PackageManagers, "apk")
|
||||
caps.PackageManagers = append(caps.PackageManagers, "apk")
|
||||
}
|
||||
if _, err := exec.LookPath("snap"); err == nil {
|
||||
cap.PackageManagers = append(cap.PackageManagers, "snap")
|
||||
caps.PackageManagers = append(caps.PackageManagers, "snap")
|
||||
}
|
||||
if _, err := exec.LookPath("flatpak"); err == nil {
|
||||
cap.PackageManagers = append(cap.PackageManagers, "flatpak")
|
||||
caps.PackageManagers = append(caps.PackageManagers, "flatpak")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -813,13 +814,8 @@ func detectPwshVersion(ctx context.Context, cmd string) string {
|
||||
timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// Use -Command to get version
|
||||
var c *exec.Cmd
|
||||
if cmd == "pwsh" {
|
||||
c = exec.CommandContext(timeoutCtx, cmd, "-Command", "$PSVersionTable.PSVersion.ToString()")
|
||||
} else {
|
||||
c = exec.CommandContext(timeoutCtx, cmd, "-Command", "$PSVersionTable.PSVersion.ToString()")
|
||||
}
|
||||
// Use -Command to get version (same command works for both pwsh and powershell)
|
||||
c := exec.CommandContext(timeoutCtx, cmd, "-Command", "$PSVersionTable.PSVersion.ToString()")
|
||||
|
||||
output, err := c.Output()
|
||||
if err != nil {
|
||||
@@ -1042,15 +1038,9 @@ func getContainerCPUUsage() float64 {
|
||||
}
|
||||
}
|
||||
|
||||
// Try reading /proc/stat for this process's CPU usage
|
||||
if data, err := os.ReadFile("/proc/self/stat"); err == nil {
|
||||
fields := strings.Fields(string(data))
|
||||
if len(fields) >= 15 {
|
||||
// Fields 14 and 15 are utime and stime (in clock ticks)
|
||||
// This is cumulative, not instantaneous
|
||||
// For containers, we'll report 0 rather than misleading host data
|
||||
}
|
||||
}
|
||||
// Note: Reading /proc/self/stat could give us utime and stime (fields 14 and 15),
|
||||
// but these are cumulative values, not instantaneous. For containers, we report 0
|
||||
// rather than misleading host data.
|
||||
|
||||
return -1 // Unable to determine - caller should handle
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/docker/docker/client"
|
||||
)
|
||||
|
||||
// CheckIfDockerRunning verifies that the Docker daemon is running and accessible.
|
||||
func CheckIfDockerRunning(ctx context.Context, configDockerHost string) error {
|
||||
opts := []client.Opt{
|
||||
client.FromEnv,
|
||||
@@ -23,7 +24,7 @@ func CheckIfDockerRunning(ctx context.Context, configDockerHost string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
defer func() { _ = cli.Close() }()
|
||||
|
||||
_, err = cli.Ping(ctx)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Package labels provides utilities for parsing and managing runner labels.
|
||||
package labels
|
||||
|
||||
import (
|
||||
@@ -8,17 +9,20 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Label scheme constants define the execution environments.
|
||||
const (
|
||||
SchemeHost = "host"
|
||||
SchemeDocker = "docker"
|
||||
)
|
||||
|
||||
// Label represents a parsed runner label with name, schema, and optional argument.
|
||||
type Label struct {
|
||||
Name string
|
||||
Schema string
|
||||
Arg string
|
||||
}
|
||||
|
||||
// Parse parses a label string in the format "name:schema:arg" and returns a Label.
|
||||
func Parse(str string) (*Label, error) {
|
||||
splits := strings.SplitN(str, ":", 3)
|
||||
label := &Label{
|
||||
@@ -38,8 +42,10 @@ func Parse(str string) (*Label, error) {
|
||||
return label, nil
|
||||
}
|
||||
|
||||
// Labels is a slice of Label pointers.
|
||||
type Labels []*Label
|
||||
|
||||
// RequireDocker returns true if any label uses the docker schema.
|
||||
func (l Labels) RequireDocker() bool {
|
||||
for _, label := range l {
|
||||
if label.Schema == SchemeDocker {
|
||||
@@ -49,6 +55,7 @@ func (l Labels) RequireDocker() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// PickPlatform selects the appropriate platform based on the runsOn requirements.
|
||||
func (l Labels) PickPlatform(runsOn []string) string {
|
||||
platforms := make(map[string]string, len(l))
|
||||
for _, label := range l {
|
||||
@@ -82,6 +89,7 @@ func (l Labels) PickPlatform(runsOn []string) string {
|
||||
return "docker.gitea.com/runner-images:ubuntu-latest"
|
||||
}
|
||||
|
||||
// Names returns the names of all labels.
|
||||
func (l Labels) Names() []string {
|
||||
names := make([]string, 0, len(l))
|
||||
for _, label := range l {
|
||||
@@ -90,6 +98,7 @@ func (l Labels) Names() []string {
|
||||
return names
|
||||
}
|
||||
|
||||
// ToStrings converts labels back to their string representation.
|
||||
func (l Labels) ToStrings() []string {
|
||||
ls := make([]string, 0, len(l))
|
||||
for _, label := range l {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Package report provides task reporting functionality for communicating with the server.
|
||||
package report
|
||||
|
||||
import (
|
||||
@@ -21,6 +22,7 @@ import (
|
||||
"git.marketally.com/gitcaddy/gitcaddy-runner/internal/pkg/client"
|
||||
)
|
||||
|
||||
// Reporter handles logging and state reporting for running tasks.
|
||||
type Reporter struct {
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
@@ -42,6 +44,7 @@ type Reporter struct {
|
||||
stopCommandEndToken string
|
||||
}
|
||||
|
||||
// NewReporter creates a new Reporter for the given task.
|
||||
func NewReporter(ctx context.Context, cancel context.CancelFunc, client client.Client, task *runnerv1.Task) *Reporter {
|
||||
var oldnew []string
|
||||
if v := task.Context.Fields["token"].GetStringValue(); v != "" {
|
||||
@@ -72,6 +75,7 @@ func NewReporter(ctx context.Context, cancel context.CancelFunc, client client.C
|
||||
return rv
|
||||
}
|
||||
|
||||
// ResetSteps initializes the step states with the given number of steps.
|
||||
func (r *Reporter) ResetSteps(l int) {
|
||||
r.stateMu.Lock()
|
||||
defer r.stateMu.Unlock()
|
||||
@@ -82,6 +86,7 @@ func (r *Reporter) ResetSteps(l int) {
|
||||
}
|
||||
}
|
||||
|
||||
// Levels returns all log levels that this hook should fire for.
|
||||
func (r *Reporter) Levels() []log.Level {
|
||||
return log.AllLevels
|
||||
}
|
||||
@@ -93,6 +98,7 @@ func appendIfNotNil[T any](s []*T, v *T) []*T {
|
||||
return s
|
||||
}
|
||||
|
||||
// Fire processes a log entry and updates the task state accordingly.
|
||||
func (r *Reporter) Fire(entry *log.Entry) error {
|
||||
r.stateMu.Lock()
|
||||
defer r.stateMu.Unlock()
|
||||
@@ -175,6 +181,7 @@ func (r *Reporter) Fire(entry *log.Entry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunDaemon starts the periodic reporting of logs and state.
|
||||
func (r *Reporter) RunDaemon() {
|
||||
if r.closed {
|
||||
return
|
||||
@@ -189,6 +196,7 @@ func (r *Reporter) RunDaemon() {
|
||||
time.AfterFunc(time.Second, r.RunDaemon)
|
||||
}
|
||||
|
||||
// Logf adds a formatted log message to the report.
|
||||
func (r *Reporter) Logf(format string, a ...interface{}) {
|
||||
r.stateMu.Lock()
|
||||
defer r.stateMu.Unlock()
|
||||
@@ -205,6 +213,7 @@ func (r *Reporter) logf(format string, a ...interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// SetOutputs stores the job outputs to be reported to the server.
|
||||
func (r *Reporter) SetOutputs(outputs map[string]string) {
|
||||
r.stateMu.Lock()
|
||||
defer r.stateMu.Unlock()
|
||||
@@ -225,6 +234,7 @@ func (r *Reporter) SetOutputs(outputs map[string]string) {
|
||||
}
|
||||
}
|
||||
|
||||
// Close finalizes the report and sends any remaining logs and state.
|
||||
func (r *Reporter) Close(lastWords string) error {
|
||||
r.closed = true
|
||||
|
||||
@@ -260,6 +270,7 @@ func (r *Reporter) Close(lastWords string) error {
|
||||
}, retry.Context(r.ctx))
|
||||
}
|
||||
|
||||
// ReportLog sends accumulated log rows to the server.
|
||||
func (r *Reporter) ReportLog(noMore bool) error {
|
||||
r.clientM.Lock()
|
||||
defer r.clientM.Unlock()
|
||||
@@ -295,6 +306,7 @@ func (r *Reporter) ReportLog(noMore bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReportState sends the current task state to the server.
|
||||
func (r *Reporter) ReportState() error {
|
||||
r.clientM.Lock()
|
||||
defer r.clientM.Unlock()
|
||||
@@ -373,7 +385,7 @@ func (r *Reporter) parseResult(result interface{}) (runnerv1.Result, bool) {
|
||||
|
||||
var cmdRegex = regexp.MustCompile(`^::([^ :]+)( .*)?::(.*)$`)
|
||||
|
||||
func (r *Reporter) handleCommand(originalContent, command, parameters, value string) *string {
|
||||
func (r *Reporter) handleCommand(originalContent, command, _ /* parameters */, value string) *string {
|
||||
if r.stopCommandEndToken != "" && command != r.stopCommandEndToken {
|
||||
return &originalContent
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Package ver provides version information for the runner.
|
||||
package ver
|
||||
|
||||
// go build -ldflags "-X git.marketally.com/gitcaddy/gitcaddy-runner/internal/pkg/ver.version=1.2.3"
|
||||
var version = "dev"
|
||||
|
||||
// Version returns the current runner version.
|
||||
func Version() string {
|
||||
return version
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user