detached 5a86d44

feat(api): add Run.name, the GitHub name of a run

commit
5a86d44af445dc946b0b5b65eebc6e09d8f56911
author
brice · · 2026-10-13 03:32 UTC
parent
f8f6441
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
3 files · +60 -9
M gen/ermite/run.pb.go +25 -6
@@ -45,10 +45,14 @@ type Run struct {
4545 // ".github/workflows/ci.yml".
4646 WorkflowPath string `protobuf:"bytes,5,opt,name=workflow_path,json=workflowPath,proto3" json:"workflow_path,omitempty"`
4747 // WorkflowName is the "name" of the workflow, or workflow_path when it has
48- // none (as GitHub does).
48+ // none (as GitHub does). It is the "github.workflow" of the run and the
49+ // workflow name of its checks. See name for the name of the run itself.
4950 WorkflowName string `protobuf:"bytes,6,opt,name=workflow_name,json=workflowName,proto3" json:"workflow_name,omitempty"`
50- // Title is the first line of the message of the commit sha, at most 256
51- // characters (GitHub's display title).
51+ // Title is GitHub's display title, at most 256 characters: the evaluated
52+ // "run-name" of the workflow when it has one, else for a push to a branch
53+ // the first line of the message of the commit sha, and for a push of a tag
54+ // the name of the workflow registered for workflow_path (the "name" of that
55+ // file on the default branch, else workflow_name).
5256 Title string `protobuf:"bytes,7,opt,name=title,proto3" json:"title,omitempty"`
5357 // Event is the event that triggered the run, in GitHub's name: "push" (the
5458 // only one for now; push to a branch or a tag, and merge of a merge
@@ -90,7 +94,14 @@ type Run struct {
9094 // one at every change and never goes back, also across attempts. Events are
9195 // not delivered in order, and a client that holds two copies of a run keeps
9296 // the one with the higher version and drops the other.
93- Version int64 `protobuf:"varint,18,opt,name=version,proto3" json:"version,omitempty"`
97+ Version int64 `protobuf:"varint,18,opt,name=version,proto3" json:"version,omitempty"`
98+ // Name is the name of the run, GitHub's "name" of a workflow run: the
99+ // evaluated "run-name" of the workflow when it has one, else the same value
100+ // as workflow_name. It is what GitHub lists as the run's name, whereas
101+ // workflow_name stays the name of the workflow ("github.workflow") even when
102+ // the workflow has a "run-name". A run stored before this field existed
103+ // reads as workflow_name.
104+ Name string `protobuf:"bytes,19,opt,name=name,proto3" json:"name,omitempty"`
94105 unknownFields protoimpl.UnknownFields
95106 sizeCache protoimpl.SizeCache
96107 }
@@ -251,6 +262,13 @@ func (x *Run) GetVersion() int64 {
251262 return 0
252263 }
253264
265+func (x *Run) GetName() string {
266+ if x != nil {
267+ return x.Name
268+ }
269+ return ""
270+}
271+
254272 // RunJob is a job of a run as people see it: the state of one job instance
255273 // (one matrix combination is one job) in one attempt. It is not Job, which is
256274 // what a runner receives.
@@ -2013,7 +2031,7 @@ var File_ermite_run_proto protoreflect.FileDescriptor
20132031
20142032 const file_ermite_run_proto_rawDesc = "" +
20152033 "\n" +
2016- "\x10ermite/run.proto\x12\x06ermite\x1a\x13ermite/runner.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xd0\x04\n" +
2034+ "\x10ermite/run.proto\x12\x06ermite\x1a\x13ermite/runner.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xe4\x04\n" +
20172035 "\x03Run\x12\x12\n" +
20182036 "\x04repo\x18\x01 \x01(\tR\x04repo\x12\x0e\n" +
20192037 "\x02id\x18\x02 \x01(\x03R\x02id\x12\x16\n" +
@@ -2037,7 +2055,8 @@ const file_ermite_run_proto_rawDesc = "" +
20372055 "\n" +
20382056 "started_at\x18\x10 \x01(\v2\x1a.google.protobuf.TimestampR\tstartedAt\x12=\n" +
20392057 "\fcompleted_at\x18\x11 \x01(\v2\x1a.google.protobuf.TimestampR\vcompletedAt\x12\x18\n" +
2040- "\aversion\x18\x12 \x01(\x03R\aversion\"\x8f\x05\n" +
2058+ "\aversion\x18\x12 \x01(\x03R\aversion\x12\x12\n" +
2059+ "\x04name\x18\x13 \x01(\tR\x04name\"\x8f\x05\n" +
20412060 "\x06RunJob\x12\x0e\n" +
20422061 "\x02id\x18\x01 \x01(\tR\x02id\x12\x15\n" +
20432062 "\x06run_id\x18\x02 \x01(\x03R\x05runId\x12\x18\n" +
@@ -45,10 +45,14 @@ type Run struct {
45 // ".github/workflows/ci.yml".45 // ".github/workflows/ci.yml".
46 WorkflowPath string `protobuf:"bytes,5,opt,name=workflow_path,json=workflowPath,proto3" json:"workflow_path,omitempty"`46 WorkflowPath string `protobuf:"bytes,5,opt,name=workflow_path,json=workflowPath,proto3" json:"workflow_path,omitempty"`
47 // WorkflowName is the "name" of the workflow, or workflow_path when it has47 // WorkflowName is the "name" of the workflow, or workflow_path when it has
48- // none (as GitHub does).48+ // none (as GitHub does). It is the "github.workflow" of the run and the
49+ // workflow name of its checks. See name for the name of the run itself.
49 WorkflowName string `protobuf:"bytes,6,opt,name=workflow_name,json=workflowName,proto3" json:"workflow_name,omitempty"`50 WorkflowName string `protobuf:"bytes,6,opt,name=workflow_name,json=workflowName,proto3" json:"workflow_name,omitempty"`
50- // Title is the first line of the message of the commit sha, at most 25651+ // Title is GitHub's display title, at most 256 characters: the evaluated
51- // characters (GitHub's display title).52+ // "run-name" of the workflow when it has one, else for a push to a branch
53+ // the first line of the message of the commit sha, and for a push of a tag
54+ // the name of the workflow registered for workflow_path (the "name" of that
55+ // file on the default branch, else workflow_name).
52 Title string `protobuf:"bytes,7,opt,name=title,proto3" json:"title,omitempty"`56 Title string `protobuf:"bytes,7,opt,name=title,proto3" json:"title,omitempty"`
53 // Event is the event that triggered the run, in GitHub's name: "push" (the57 // Event is the event that triggered the run, in GitHub's name: "push" (the
54 // only one for now; push to a branch or a tag, and merge of a merge58 // only one for now; push to a branch or a tag, and merge of a merge
@@ -90,7 +94,14 @@ type Run struct {
90 // one at every change and never goes back, also across attempts. Events are94 // one at every change and never goes back, also across attempts. Events are
91 // not delivered in order, and a client that holds two copies of a run keeps95 // not delivered in order, and a client that holds two copies of a run keeps
92 // the one with the higher version and drops the other.96 // the one with the higher version and drops the other.
93- Version int64 `protobuf:"varint,18,opt,name=version,proto3" json:"version,omitempty"`97+ Version int64 `protobuf:"varint,18,opt,name=version,proto3" json:"version,omitempty"`
98+ // Name is the name of the run, GitHub's "name" of a workflow run: the
99+ // evaluated "run-name" of the workflow when it has one, else the same value
100+ // as workflow_name. It is what GitHub lists as the run's name, whereas
101+ // workflow_name stays the name of the workflow ("github.workflow") even when
102+ // the workflow has a "run-name". A run stored before this field existed
103+ // reads as workflow_name.
104+ Name string `protobuf:"bytes,19,opt,name=name,proto3" json:"name,omitempty"`
94 unknownFields protoimpl.UnknownFields105 unknownFields protoimpl.UnknownFields
95 sizeCache protoimpl.SizeCache106 sizeCache protoimpl.SizeCache
96 }107 }
@@ -251,6 +262,13 @@ func (x *Run) GetVersion() int64 {
251 return 0262 return 0
252 }263 }
253 264
265+func (x *Run) GetName() string {
266+ if x != nil {
267+ return x.Name
268+ }
269+ return ""
270+}
271+
254 // RunJob is a job of a run as people see it: the state of one job instance272 // RunJob is a job of a run as people see it: the state of one job instance
255 // (one matrix combination is one job) in one attempt. It is not Job, which is273 // (one matrix combination is one job) in one attempt. It is not Job, which is
256 // what a runner receives.274 // what a runner receives.
@@ -2013,7 +2031,7 @@ var File_ermite_run_proto protoreflect.FileDescriptor
2013 2031
2014 const file_ermite_run_proto_rawDesc = "" +2032 const file_ermite_run_proto_rawDesc = "" +
2015 "\n" +2033 "\n" +
2016- "\x10ermite/run.proto\x12\x06ermite\x1a\x13ermite/runner.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xd0\x04\n" +2034+ "\x10ermite/run.proto\x12\x06ermite\x1a\x13ermite/runner.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xe4\x04\n" +
2017 "\x03Run\x12\x12\n" +2035 "\x03Run\x12\x12\n" +
2018 "\x04repo\x18\x01 \x01(\tR\x04repo\x12\x0e\n" +2036 "\x04repo\x18\x01 \x01(\tR\x04repo\x12\x0e\n" +
2019 "\x02id\x18\x02 \x01(\x03R\x02id\x12\x16\n" +2037 "\x02id\x18\x02 \x01(\x03R\x02id\x12\x16\n" +
@@ -2037,7 +2055,8 @@ const file_ermite_run_proto_rawDesc = "" +
2037 "\n" +2055 "\n" +
2038 "started_at\x18\x10 \x01(\v2\x1a.google.protobuf.TimestampR\tstartedAt\x12=\n" +2056 "started_at\x18\x10 \x01(\v2\x1a.google.protobuf.TimestampR\tstartedAt\x12=\n" +
2039 "\fcompleted_at\x18\x11 \x01(\v2\x1a.google.protobuf.TimestampR\vcompletedAt\x12\x18\n" +2057 "\fcompleted_at\x18\x11 \x01(\v2\x1a.google.protobuf.TimestampR\vcompletedAt\x12\x18\n" +
2040- "\aversion\x18\x12 \x01(\x03R\aversion\"\x8f\x05\n" +2058+ "\aversion\x18\x12 \x01(\x03R\aversion\x12\x12\n" +
2059+ "\x04name\x18\x13 \x01(\tR\x04name\"\x8f\x05\n" +
2041 "\x06RunJob\x12\x0e\n" +2060 "\x06RunJob\x12\x0e\n" +
2042 "\x02id\x18\x01 \x01(\tR\x02id\x12\x15\n" +2061 "\x02id\x18\x01 \x01(\tR\x02id\x12\x15\n" +
2043 "\x06run_id\x18\x02 \x01(\x03R\x05runId\x12\x18\n" +2062 "\x06run_id\x18\x02 \x01(\x03R\x05runId\x12\x18\n" +
M gen_test.go +21 -0
@@ -329,3 +329,24 @@ func TestCompleteJobRoundTrip(t *testing.T) {
329329 t.Errorf("unexpected response %v", r)
330330 }
331331 }
332+
333+// TestRunNameField pins the number of Run.name, the GitHub name of the run
334+// that sits next to workflow_name, and that it survives the wire.
335+func TestRunNameField(t *testing.T) {
336+ fd := (&ermite.Run{}).ProtoReflect().Descriptor().Fields().ByName("name")
337+ if fd == nil || fd.Number() != 19 {
338+ t.Fatalf("Run.name = %v, want field 19", fd)
339+ }
340+ in := &ermite.Run{WorkflowName: "Names Workflow", Name: "run push on branch by someone", Title: "run push on branch by someone"}
341+ b, err := proto.Marshal(in)
342+ if err != nil {
343+ t.Fatal(err)
344+ }
345+ var out ermite.Run
346+ if err := proto.Unmarshal(b, &out); err != nil {
347+ t.Fatal(err)
348+ }
349+ if out.GetName() != in.GetName() || out.GetWorkflowName() != "Names Workflow" {
350+ t.Errorf("round trip: name %q, workflow_name %q", out.GetName(), out.GetWorkflowName())
351+ }
352+}
@@ -329,3 +329,24 @@ func TestCompleteJobRoundTrip(t *testing.T) {
329 t.Errorf("unexpected response %v", r)329 t.Errorf("unexpected response %v", r)
330 }330 }
331 }331 }
332+
333+// TestRunNameField pins the number of Run.name, the GitHub name of the run
334+// that sits next to workflow_name, and that it survives the wire.
335+func TestRunNameField(t *testing.T) {
336+ fd := (&ermite.Run{}).ProtoReflect().Descriptor().Fields().ByName("name")
337+ if fd == nil || fd.Number() != 19 {
338+ t.Fatalf("Run.name = %v, want field 19", fd)
339+ }
340+ in := &ermite.Run{WorkflowName: "Names Workflow", Name: "run push on branch by someone", Title: "run push on branch by someone"}
341+ b, err := proto.Marshal(in)
342+ if err != nil {
343+ t.Fatal(err)
344+ }
345+ var out ermite.Run
346+ if err := proto.Unmarshal(b, &out); err != nil {
347+ t.Fatal(err)
348+ }
349+ if out.GetName() != in.GetName() || out.GetWorkflowName() != "Names Workflow" {
350+ t.Errorf("round trip: name %q, workflow_name %q", out.GetName(), out.GetWorkflowName())
351+ }
352+}
M proto/ermite/run.proto +14 -3
@@ -27,10 +27,14 @@ message Run {
2727 // ".github/workflows/ci.yml".
2828 string workflow_path = 5;
2929 // WorkflowName is the "name" of the workflow, or workflow_path when it has
30- // none (as GitHub does).
30+ // none (as GitHub does). It is the "github.workflow" of the run and the
31+ // workflow name of its checks. See name for the name of the run itself.
3132 string workflow_name = 6;
32- // Title is the first line of the message of the commit sha, at most 256
33- // characters (GitHub's display title).
33+ // Title is GitHub's display title, at most 256 characters: the evaluated
34+ // "run-name" of the workflow when it has one, else for a push to a branch
35+ // the first line of the message of the commit sha, and for a push of a tag
36+ // the name of the workflow registered for workflow_path (the "name" of that
37+ // file on the default branch, else workflow_name).
3438 string title = 7;
3539 // Event is the event that triggered the run, in GitHub's name: "push" (the
3640 // only one for now; push to a branch or a tag, and merge of a merge
@@ -73,6 +77,13 @@ message Run {
7377 // not delivered in order, and a client that holds two copies of a run keeps
7478 // the one with the higher version and drops the other.
7579 int64 version = 18;
80+ // Name is the name of the run, GitHub's "name" of a workflow run: the
81+ // evaluated "run-name" of the workflow when it has one, else the same value
82+ // as workflow_name. It is what GitHub lists as the run's name, whereas
83+ // workflow_name stays the name of the workflow ("github.workflow") even when
84+ // the workflow has a "run-name". A run stored before this field existed
85+ // reads as workflow_name.
86+ string name = 19;
7687 }
7788
7889 // RunJob is a job of a run as people see it: the state of one job instance
@@ -27,10 +27,14 @@ message Run {
27 // ".github/workflows/ci.yml".27 // ".github/workflows/ci.yml".
28 string workflow_path = 5;28 string workflow_path = 5;
29 // WorkflowName is the "name" of the workflow, or workflow_path when it has29 // WorkflowName is the "name" of the workflow, or workflow_path when it has
30- // none (as GitHub does).30+ // none (as GitHub does). It is the "github.workflow" of the run and the
31+ // workflow name of its checks. See name for the name of the run itself.
31 string workflow_name = 6;32 string workflow_name = 6;
32- // Title is the first line of the message of the commit sha, at most 25633+ // Title is GitHub's display title, at most 256 characters: the evaluated
33- // characters (GitHub's display title).34+ // "run-name" of the workflow when it has one, else for a push to a branch
35+ // the first line of the message of the commit sha, and for a push of a tag
36+ // the name of the workflow registered for workflow_path (the "name" of that
37+ // file on the default branch, else workflow_name).
34 string title = 7;38 string title = 7;
35 // Event is the event that triggered the run, in GitHub's name: "push" (the39 // Event is the event that triggered the run, in GitHub's name: "push" (the
36 // only one for now; push to a branch or a tag, and merge of a merge40 // only one for now; push to a branch or a tag, and merge of a merge
@@ -73,6 +77,13 @@ message Run {
73 // not delivered in order, and a client that holds two copies of a run keeps77 // not delivered in order, and a client that holds two copies of a run keeps
74 // the one with the higher version and drops the other.78 // the one with the higher version and drops the other.
75 int64 version = 18;79 int64 version = 18;
80+ // Name is the name of the run, GitHub's "name" of a workflow run: the
81+ // evaluated "run-name" of the workflow when it has one, else the same value
82+ // as workflow_name. It is what GitHub lists as the run's name, whereas
83+ // workflow_name stays the name of the workflow ("github.workflow") even when
84+ // the workflow has a "run-name". A run stored before this field existed
85+ // reads as workflow_name.
86+ string name = 19;
76 }87 }
77 88
78 // RunJob is a job of a run as people see it: the state of one job instance89 // RunJob is a job of a run as people see it: the state of one job instance

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 18

↑↓ moveenter openesc close