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.

Blame · server/ssh/status.go

Line attribution on main · 91 line(s)

e5478085
Keenan Nemetz
11d ago
1 package ssh
2
3 // `vole change show` asks the instance whether the landing tree has been tested.
4 // A clone can see the commits and the refs, but not the approvals or the run
5 // results that decide whether a landing is allowed, so the answer comes from the
6 // same plan the merge button and the push hook use.
7
8 import (
9 "fmt"
10 "strings"
11 "time"
12
13 xssh "golang.org/x/crypto/ssh"
14
d37d301f
Keenan Nemetz
15h ago
15 "rodent.software/vole/ci/runs"
16 "rodent.software/vole/forge/access"
17 "rodent.software/vole/forge/landing"
18 "rodent.software/vole/internal/format"
19 "rodent.software/vole/metadata"
e5478085
Keenan Nemetz
11d ago
20 )
21
22 func (s *Server) serveChangeStatus(ch xssh.Channel, argv []string, user, remote string) int {
23 if len(argv) != 3 {
24 fmt.Fprint(ch, "vole: usage: vole-change-status <repository> <request-id>\n")
25 return 129
26 }
27 name, ok := repoName(argv[1])
28 if !ok {
29 fmt.Fprint(ch, "vole: invalid repository name\n")
30 return 129
31 }
32 id := strings.TrimSpace(argv[2])
33 m, err := s.cfg.Repos.Open(name)
34 if err != nil {
35 fmt.Fprintf(ch, "vole: repository %q not found\n", name)
36 return 1
37 }
38 a, err := m.ACL()
39 if err != nil {
40 fmt.Fprintf(ch, "vole: cannot read access rules for %s\n", name)
41 return 1
42 }
43 role := a.EffectiveRole(user, s.cfg.Identity != nil && s.cfg.Identity.IsAdmin(user))
44 if !role.AtLeast(access.Read) {
45 fmt.Fprintf(ch, "vole: %s may not read change requests in %s\n", user, name)
46 return 1
47 }
48 req, err := metadata.GetRequest(m.Git(), id)
49 if err != nil {
50 fmt.Fprintf(ch, "vole: %v\n", err)
51 return 1
52 }
53 if !req.Open() {
54 fmt.Fprintf(ch, "combined: not needed (%s)\n", req.State)
55 return 0
56 }
57 gate := landing.Gate{
58 Repo: m.Git(), Name: m.Name, ACL: a,
59 Actor: user, Role: role,
60 Runs: func() (*runs.Store, error) { return s.cfg.Runs, nil },
61 }
62 plan, err := landing.Prepare(gate, req.ID, user, time.Now().UTC())
63 if err != nil {
64 fmt.Fprintf(ch, "combined: cannot tell (%v)\n", err)
65 return 0
66 }
67 switch {
68 case len(plan.Conflicts) > 0:
69 fmt.Fprintf(ch, "combined: conflict with %s in %s\n", plan.Base, strings.Join(plan.Conflicts, ", "))
70 case !plan.MergeCommit:
71 fmt.Fprint(ch, "combined: not needed (fast-forward)\n")
72 case plan.Ready:
73 fmt.Fprintf(ch, "combined: passed %s\n", format.SHA(plan.NewTip))
74 case !plan.Checks:
75 fmt.Fprintf(ch, "combined: no checks required %s\n", format.SHA(plan.NewTip))
76 case len(plan.Gaps) == 0:
77 fmt.Fprintf(ch, "combined: untested %s\n", format.SHA(plan.NewTip))
78 case plan.Pending:
79 fmt.Fprintf(ch, "combined: testing %s\n", format.SHA(plan.NewTip))
80 default:
81 fmt.Fprintf(ch, "combined: failed %s\n", format.SHA(plan.NewTip))
82 }
83 if plan.Blocked != "" {
84 fmt.Fprintf(ch, "landing: blocked (%s)\n", plan.Blocked)
85 } else if plan.Ready {
86 fmt.Fprint(ch, "landing: ready\n")
87 } else if len(plan.Gaps) > 0 {
88 fmt.Fprint(ch, "landing: waiting for the combined result\n")
89 }
90 return 0
91 }