Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

Add event, schedule and manual workflow triggers

eb07ff5696e0d83201215966e3ea1e6a24467581 · Keenan Nemetz · 8d ago · parent 1cde8b9e

Add event, schedule and manual workflow triggers

Workflows can now react to change requests, issues, comments, cron
schedules and manual runs, and a push trigger can filter by the paths it
changed. Branch and tag patterns gain ! exclusion.

Event runs are pinned with a JSON payload and the runner exposes it as
VOLE_EVENT, VOLE_EVENT_ACTION and VOLE_EVENT_PATH. Change-request runs
check out the base tip and carry the head and changed files, so an event
never executes an unapproved contributor commit.

Workflow dispatch resolves typed inputs and is available from the
workflows page and `vole workflow dispatch`. Deduplication now includes
an occurrence so the same commit can run for a later event or schedule
slot while a push remains idempotent.

Part of: #138

server/ssh/server.go +20−1

@@ -108,6 +108,10 @@ type Config struct {
108 108 // MaxGitProcesses bounds git processes across all connections. Zero uses a
109 109 // default; see server/ssh's maxGitProcesses.
110 110 MaxGitProcesses int
111 // DispatchWorkflow queues a manual run. The server wires it after construction
112 // because the dispatcher lives on the instance and the SSH server is one of its
113 // callers, not the other way round.
114 DispatchWorkflow func(repo, workflow, ref string, inputs map[string]string, actor string) (int, error)
111 115 // HandshakeTimeout bounds how long a connection may take to complete the SSH
112 116 // handshake. Zero uses the default.
113 117 HandshakeTimeout time.Duration
@@ -131,6 +135,13 @@ type Server struct {
131 135 refusedAt time.Time
132 136 }
133 137
138 // SetDispatchWorkflow wires the instance's manual-run operation after the SSH
139 // server exists. It is a setter rather than a Config field because the two objects
140 // reference each other through the instance.
141 func (s *Server) SetDispatchWorkflow(fn func(repo, workflow, ref string, inputs map[string]string, actor string) (int, error)) {
142 s.cfg.DispatchWorkflow = fn
143 }
144
134 145 // maxConnections is the configured listener cap, or the default when unset.
135 146 func (c Config) maxConnections() int {
136 147 if c.MaxConnections > 0 {
@@ -411,6 +422,14 @@ func (s *Server) exec(ch xssh.Channel, req *xssh.Request, command, user, fp, rem
411 422 exit(ch, s.serveChangeStatus(ch, argv, user, remote))
412 423 return
413 424 }
425 // A manual workflow run is a write to the repository's CI queue, not to a ref.
426 // The verb is the CLI counterpart of the browser's Run workflow form; the
427 // dispatcher re-checks the maintainer capability before it queues anything.
428 if len(argv) >= 1 && argv[0] == "vole-workflow-dispatch" {
429 req.Reply(true, nil)
430 exit(ch, s.serveWorkflowDispatch(ch, argv, user))
431 return
432 }
414 433 // The admin API is a fixed command set, not a shell. It is available only to
415 434 // accounts marked as instance admins.
416 435 if len(argv) >= 1 && argv[0] == "vole-admin" {
@@ -452,7 +471,7 @@ func (s *Server) exec(ch xssh.Channel, req *xssh.Request, command, user, fp, rem
452 471 return
453 472 }
454 473 if len(argv) != 2 {
455 refuse("only git-upload-pack, git-receive-pack, vole-admin, vole-roster, vole-whoami, vole-runner, vole-change-merge and vole-change-status are available")
474 refuse("only git-upload-pack, git-receive-pack, vole-admin, vole-roster, vole-whoami, vole-runner, vole-change-merge, vole-change-status and vole-workflow-dispatch are available")
456 475 return
457 476 }
458 477 verb := argv[0]