forked from actions/act_runner
Compare commits
6 Commits
e9c297600c
...
54308690d0
Author | SHA1 | Date | |
---|---|---|---|
54308690d0 | |||
4b90fa4325 | |||
5302c25feb | |||
a616ed1a10 | |||
f0b5aff3bb | |||
44b4736703 |
@ -52,7 +52,7 @@ func runRegister(ctx context.Context, regArgs *registerArgs, configFile *string)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
go func() {
|
go func() {
|
||||||
if err := registerInteractive(ctx, *configFile); err != nil {
|
if err := registerInteractive(ctx, *configFile, regArgs); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -127,6 +127,22 @@ func validateLabels(ls []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *registerInputs) stageValue(stage registerStage) string {
|
||||||
|
switch stage {
|
||||||
|
case StageInputInstance:
|
||||||
|
return r.InstanceAddr
|
||||||
|
case StageInputToken:
|
||||||
|
return r.Token
|
||||||
|
case StageInputRunnerName:
|
||||||
|
return r.RunnerName
|
||||||
|
case StageInputLabels:
|
||||||
|
if len(r.Labels) > 0 {
|
||||||
|
return strings.Join(r.Labels, ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func (r *registerInputs) assignToNext(stage registerStage, value string, cfg *config.Config) registerStage {
|
func (r *registerInputs) assignToNext(stage registerStage, value string, cfg *config.Config) registerStage {
|
||||||
// 必须设置实例地址和令牌。
|
// 必须设置实例地址和令牌。
|
||||||
// 如果为空,保持当前阶段。
|
// 如果为空,保持当前阶段。
|
||||||
@ -181,6 +197,7 @@ func (r *registerInputs) assignToNext(stage registerStage, value string, cfg *co
|
|||||||
|
|
||||||
if validateLabels(r.Labels) != nil {
|
if validateLabels(r.Labels) != nil {
|
||||||
log.Infoln("无效的标签, 请重新输入, 留空以使用默认标签 (例如, debian-latest:lcr.loongnix.cn/library/debian:latest) ")
|
log.Infoln("无效的标签, 请重新输入, 留空以使用默认标签 (例如, debian-latest:lcr.loongnix.cn/library/debian:latest) ")
|
||||||
|
r.Labels = nil
|
||||||
return StageInputLabels
|
return StageInputLabels
|
||||||
}
|
}
|
||||||
return StageWaitingForRegistration
|
return StageWaitingForRegistration
|
||||||
@ -188,11 +205,25 @@ func (r *registerInputs) assignToNext(stage registerStage, value string, cfg *co
|
|||||||
return StageUnknown
|
return StageUnknown
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerInteractive(ctx context.Context, configFile string) error {
|
func initInputs(regArgs *registerArgs) *registerInputs {
|
||||||
|
inputs := ®isterInputs{
|
||||||
|
InstanceAddr: regArgs.InstanceAddr,
|
||||||
|
Token: regArgs.Token,
|
||||||
|
RunnerName: regArgs.RunnerName,
|
||||||
|
Ephemeral: regArgs.Ephemeral,
|
||||||
|
}
|
||||||
|
regArgs.Labels = strings.TrimSpace(regArgs.Labels)
|
||||||
|
// command line flag.
|
||||||
|
if regArgs.Labels != "" {
|
||||||
|
inputs.Labels = strings.Split(regArgs.Labels, ",")
|
||||||
|
}
|
||||||
|
return inputs
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerInteractive(ctx context.Context, configFile string, regArgs *registerArgs) error {
|
||||||
var (
|
var (
|
||||||
reader = bufio.NewReader(os.Stdin)
|
reader = bufio.NewReader(os.Stdin)
|
||||||
stage = StageInputInstance
|
stage = StageInputInstance
|
||||||
inputs = new(registerInputs)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
cfg, err := config.LoadDefault(configFile)
|
cfg, err := config.LoadDefault(configFile)
|
||||||
@ -202,14 +233,18 @@ func registerInteractive(ctx context.Context, configFile string) error {
|
|||||||
if f, err := os.Stat(cfg.Runner.File); err == nil && !f.IsDir() {
|
if f, err := os.Stat(cfg.Runner.File); err == nil && !f.IsDir() {
|
||||||
stage = StageOverwriteLocalConfig
|
stage = StageOverwriteLocalConfig
|
||||||
}
|
}
|
||||||
|
inputs := initInputs(regArgs)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
cmdString := inputs.stageValue(stage)
|
||||||
|
if cmdString == "" {
|
||||||
printStageHelp(stage)
|
printStageHelp(stage)
|
||||||
|
var err error
|
||||||
cmdString, err := reader.ReadString('\n')
|
cmdString, err = reader.ReadString('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
stage = inputs.assignToNext(stage, strings.TrimSpace(cmdString), cfg)
|
stage = inputs.assignToNext(stage, strings.TrimSpace(cmdString), cfg)
|
||||||
|
|
||||||
if stage == StageWaitingForRegistration {
|
if stage == StageWaitingForRegistration {
|
||||||
@ -255,18 +290,7 @@ func registerNoInteractive(ctx context.Context, configFile string, regArgs *regi
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
inputs := ®isterInputs{
|
inputs := initInputs(regArgs)
|
||||||
InstanceAddr: regArgs.InstanceAddr,
|
|
||||||
Token: regArgs.Token,
|
|
||||||
RunnerName: regArgs.RunnerName,
|
|
||||||
Labels: defaultLabels,
|
|
||||||
Ephemeral: regArgs.Ephemeral,
|
|
||||||
}
|
|
||||||
regArgs.Labels = strings.TrimSpace(regArgs.Labels)
|
|
||||||
// 命令行标志。
|
|
||||||
if regArgs.Labels != "" {
|
|
||||||
inputs.Labels = strings.Split(regArgs.Labels, ",")
|
|
||||||
}
|
|
||||||
// 配置文件中指定的标签。
|
// 配置文件中指定的标签。
|
||||||
if len(cfg.Runner.Labels) > 0 {
|
if len(cfg.Runner.Labels) > 0 {
|
||||||
if regArgs.Labels != "" {
|
if regArgs.Labels != "" {
|
||||||
@ -274,6 +298,9 @@ func registerNoInteractive(ctx context.Context, configFile string, regArgs *regi
|
|||||||
}
|
}
|
||||||
inputs.Labels = cfg.Runner.Labels
|
inputs.Labels = cfg.Runner.Labels
|
||||||
}
|
}
|
||||||
|
if len(inputs.Labels) == 0 {
|
||||||
|
inputs.Labels = defaultLabels
|
||||||
|
}
|
||||||
|
|
||||||
if inputs.RunnerName == "" {
|
if inputs.RunnerName == "" {
|
||||||
inputs.RunnerName, _ = os.Hostname()
|
inputs.RunnerName, _ = os.Hostname()
|
||||||
@ -281,7 +308,7 @@ func registerNoInteractive(ctx context.Context, configFile string, regArgs *regi
|
|||||||
}
|
}
|
||||||
if err := inputs.validate(); err != nil {
|
if err := inputs.validate(); err != nil {
|
||||||
log.WithError(err).Errorf("无效输入,请重新运行 act 命令。")
|
log.WithError(err).Errorf("无效输入,请重新运行 act 命令。")
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
if err := doRegister(ctx, cfg, inputs); err != nil {
|
if err := doRegister(ctx, cfg, inputs); err != nil {
|
||||||
return fmt.Errorf("注册运行器失败: %w", err)
|
return fmt.Errorf("注册运行器失败: %w", err)
|
||||||
|
19
internal/app/cmd/register_test.go
Normal file
19
internal/app/cmd/register_test.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gotest.tools/v3/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRegisterNonInteractiveReturnsLabelValidationError(t *testing.T) {
|
||||||
|
err := registerNoInteractive(t.Context(), "", ®isterArgs{
|
||||||
|
Labels: "label:invalid",
|
||||||
|
Token: "token",
|
||||||
|
InstanceAddr: "http://localhost:3000",
|
||||||
|
})
|
||||||
|
assert.Error(t, err, "unsupported schema: invalid")
|
||||||
|
}
|
@ -173,6 +173,12 @@ func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report.
|
|||||||
preset.Token = t
|
preset.Token = t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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"]
|
||||||
|
}
|
||||||
|
|
||||||
giteaRuntimeToken := taskContext["gitea_runtime_token"].GetStringValue()
|
giteaRuntimeToken := taskContext["gitea_runtime_token"].GetStringValue()
|
||||||
if giteaRuntimeToken == "" {
|
if giteaRuntimeToken == "" {
|
||||||
// 兼容旧版本 Gitea Server
|
// 兼容旧版本 Gitea Server
|
||||||
|
@ -6,6 +6,6 @@ package client
|
|||||||
const (
|
const (
|
||||||
UUIDHeader = "x-runner-uuid"
|
UUIDHeader = "x-runner-uuid"
|
||||||
TokenHeader = "x-runner-token"
|
TokenHeader = "x-runner-token"
|
||||||
// Deprecated: could be removed after Gitea 1.20 released
|
// 已弃用: 可以在Gitea 1.20发布后删除
|
||||||
VersionHeader = "x-runner-version"
|
VersionHeader = "x-runner-version"
|
||||||
)
|
)
|
||||||
|
@ -27,7 +27,7 @@ func getHTTPClient(endpoint string, insecure bool) *http.Client {
|
|||||||
return http.DefaultClient
|
return http.DefaultClient
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new runner client.
|
// New返回一个新的runner客户端。
|
||||||
func New(endpoint string, insecure bool, uuid, token, version string, opts ...connect.ClientOption) *HTTPClient {
|
func New(endpoint string, insecure bool, uuid, token, version string, opts ...connect.ClientOption) *HTTPClient {
|
||||||
baseURL := strings.TrimRight(endpoint, "/") + "/api/actions"
|
baseURL := strings.TrimRight(endpoint, "/") + "/api/actions"
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ func New(endpoint string, insecure bool, uuid, token, version string, opts ...co
|
|||||||
if token != "" {
|
if token != "" {
|
||||||
req.Header().Set(TokenHeader, token)
|
req.Header().Set(TokenHeader, token)
|
||||||
}
|
}
|
||||||
// TODO: version will be removed from request header after Gitea 1.20 released.
|
// TODO:version将在Gitea 1.20发布后从请求标头中删除。
|
||||||
if version != "" {
|
if version != "" {
|
||||||
req.Header().Set(VersionHeader, version)
|
req.Header().Set(VersionHeader, version)
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ func (c *HTTPClient) Insecure() bool {
|
|||||||
|
|
||||||
var _ Client = (*HTTPClient)(nil)
|
var _ Client = (*HTTPClient)(nil)
|
||||||
|
|
||||||
// An HTTPClient manages communication with the runner API.
|
// HTTPClient管理与runner API的通信。
|
||||||
type HTTPClient struct {
|
type HTTPClient struct {
|
||||||
pingv1connect.PingServiceClient
|
pingv1connect.PingServiceClient
|
||||||
runnerv1connect.RunnerServiceClient
|
runnerv1connect.RunnerServiceClient
|
||||||
|
2
main.go
2
main.go
@ -14,6 +14,6 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||||
defer stop()
|
defer stop()
|
||||||
// run the command
|
// 运行命令
|
||||||
cmd.Execute(ctx)
|
cmd.Execute(ctx)
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,13 @@ EXTRA_ARGS=""
|
|||||||
if [[ ! -z "${GITEA_RUNNER_LABELS}" ]]; then
|
if [[ ! -z "${GITEA_RUNNER_LABELS}" ]]; then
|
||||||
EXTRA_ARGS="${EXTRA_ARGS} --labels ${GITEA_RUNNER_LABELS}"
|
EXTRA_ARGS="${EXTRA_ARGS} --labels ${GITEA_RUNNER_LABELS}"
|
||||||
fi
|
fi
|
||||||
|
if [[ ! -z "${GITEA_RUNNER_EPHEMERAL}" ]]; then
|
||||||
|
EXTRA_ARGS="${EXTRA_ARGS} --ephemeral"
|
||||||
|
fi
|
||||||
|
RUN_ARGS=""
|
||||||
|
if [[ ! -z "${GITEA_RUNNER_ONCE}" ]]; then
|
||||||
|
RUN_ARGS="${RUN_ARGS} --once"
|
||||||
|
fi
|
||||||
|
|
||||||
# 如果没有设置令牌,可以从文件中读取令牌,例如从 Docker Secret
|
# 如果没有设置令牌,可以从文件中读取令牌,例如从 Docker Secret
|
||||||
if [[ -z "${GITEA_RUNNER_REGISTRATION_TOKEN}" ]] && [[ -f "${GITEA_RUNNER_REGISTRATION_TOKEN_FILE}" ]]; then
|
if [[ -z "${GITEA_RUNNER_REGISTRATION_TOKEN}" ]] && [[ -f "${GITEA_RUNNER_REGISTRATION_TOKEN_FILE}" ]]; then
|
||||||
@ -60,4 +67,4 @@ unset GITEA_RUNNER_REGISTRATION_TOKEN
|
|||||||
unset GITEA_RUNNER_REGISTRATION_TOKEN_FILE
|
unset GITEA_RUNNER_REGISTRATION_TOKEN_FILE
|
||||||
|
|
||||||
# 启动 act_runner 守护进程
|
# 启动 act_runner 守护进程
|
||||||
exec act_runner daemon ${CONFIG_ARG}
|
exec act_runner daemon ${CONFIG_ARG} ${RUN_ARGS}
|
||||||
|
Reference in New Issue
Block a user