fix(ci): match GitHub's push payload in the github context
Checked against the ermite-conformance recordings: repository.default_branch and master_branch are the default branch, event.compare uses 12-character ids (the commit page for a created ref, before...after for an update), the commits carry their tree id, and retention_days is a string taken from the configured retention.
- commit
- 1beb9dbf29973085c746ab03ca24d00534a1a80c
- author
- brice · · 2026-10-12 19:17 UTC
- parent
- 5e9332c
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +79 -13
M internal/app/ci_flow_test.go +37 -0
| @@ -4,6 +4,7 @@ package app | |||
| 4 | 4 | ||
| 5 | 5 | import ( | |
| 6 | 6 | "context" | |
| 7 | + | "encoding/json" | |
| 7 | 8 | "fmt" | |
| 8 | 9 | "net/http/httptest" | |
| 9 | 10 | "os" | |
| @@ -647,3 +648,39 @@ func TestCIAcknowledgedAssignmentIsNotRepeated(t *testing.T) { | |||
| 647 | 648 | require.NoError(t, err) | |
| 648 | 649 | assert.Nil(t, again, "the acknowledged assignment is not handed out again") | |
| 649 | 650 | } | |
| 651 | + | ||
| 652 | + | // The push payload follows GitHub's (checked against the recordings of | |
| 653 | + | // ermite-conformance): 12-character ids in "compare", the commit page for a | |
| 654 | + | // created ref and a compare range for an update, the default branch of the | |
| 655 | + | // repository, a tree id, and string counters. | |
| 656 | + | func TestCIGithubContextOfAPush(t *testing.T) { | |
| 657 | + | c := newCIHarness(t, nil) | |
| 658 | + | runner := c.registerRunner("alpha", "ubuntu-latest") | |
| 659 | + | oneJobWF := strings.Split(ciWorkflow, " test:")[0] | |
| 660 | + | first := c.push("main", map[string]string{".github/workflows/ci.yml": oneJobWF}, "") | |
| 661 | + | ev := func() (map[string]any, map[string]any) { | |
| 662 | + | job := runner.await() | |
| 663 | + | var ctxs map[string]map[string]any | |
| 664 | + | require.NoError(t, json.Unmarshal([]byte(job.GetContexts()), &ctxs)) | |
| 665 | + | gh := ctxs["github"] | |
| 666 | + | runner.runJob(job, pb.CiConclusion_CI_CONCLUSION_SUCCESS, nil, "x") | |
| 667 | + | return gh, gh["event"].(map[string]any) | |
| 668 | + | } | |
| 669 | + | ||
| 670 | + | gh, event := ev() | |
| 671 | + | assert.Equal(t, publicOrigin+"/proj/commit/"+first[:12], event["compare"], "a created ref compares as its commit") | |
| 672 | + | assert.Equal(t, true, event["created"]) | |
| 673 | + | assert.Equal(t, domain.ZeroOID, event["before"]) | |
| 674 | + | repo := event["repository"].(map[string]any) | |
| 675 | + | assert.Equal(t, "main", repo["default_branch"]) | |
| 676 | + | assert.Equal(t, "main", repo["master_branch"]) | |
| 677 | + | assert.Equal(t, "90", gh["retention_days"], "a string, from the configured retention") | |
| 678 | + | head := event["head_commit"].(map[string]any) | |
| 679 | + | tree := strings.TrimSpace(c.bareGit("proj", "rev-parse", first+"^{tree}")) | |
| 680 | + | assert.Equal(t, tree, head["tree_id"]) | |
| 681 | + | ||
| 682 | + | second := c.push("main", map[string]string{"a.txt": "a\n"}, "") | |
| 683 | + | _, event = ev() | |
| 684 | + | assert.Equal(t, publicOrigin+"/proj/compare/"+first[:12]+"..."+second[:12], event["compare"]) | |
| 685 | + | assert.Equal(t, false, event["created"]) | |
| 686 | + | } | |
| @@ -4,6 +4,7 @@ package app | |||||
| 4 | 4 | ||||
| 5 | import ( | 5 | import ( | ||
| 6 | "context" | 6 | "context" | ||
| 7 | + | "encoding/json" | |||
| 7 | "fmt" | 8 | "fmt" | ||
| 8 | "net/http/httptest" | 9 | "net/http/httptest" | ||
| 9 | "os" | 10 | "os" | ||
| @@ -647,3 +648,39 @@ func TestCIAcknowledgedAssignmentIsNotRepeated(t *testing.T) { | |||||
| 647 | require.NoError(t, err) | 648 | require.NoError(t, err) | ||
| 648 | assert.Nil(t, again, "the acknowledged assignment is not handed out again") | 649 | assert.Nil(t, again, "the acknowledged assignment is not handed out again") | ||
| 649 | } | 650 | } | ||
| 651 | + | ||||
| 652 | + | // The push payload follows GitHub's (checked against the recordings of | |||
| 653 | + | // ermite-conformance): 12-character ids in "compare", the commit page for a | |||
| 654 | + | // created ref and a compare range for an update, the default branch of the | |||
| 655 | + | // repository, a tree id, and string counters. | |||
| 656 | + | func TestCIGithubContextOfAPush(t *testing.T) { | |||
| 657 | + | c := newCIHarness(t, nil) | |||
| 658 | + | runner := c.registerRunner("alpha", "ubuntu-latest") | |||
| 659 | + | oneJobWF := strings.Split(ciWorkflow, " test:")[0] | |||
| 660 | + | first := c.push("main", map[string]string{".github/workflows/ci.yml": oneJobWF}, "") | |||
| 661 | + | ev := func() (map[string]any, map[string]any) { | |||
| 662 | + | job := runner.await() | |||
| 663 | + | var ctxs map[string]map[string]any | |||
| 664 | + | require.NoError(t, json.Unmarshal([]byte(job.GetContexts()), &ctxs)) | |||
| 665 | + | gh := ctxs["github"] | |||
| 666 | + | runner.runJob(job, pb.CiConclusion_CI_CONCLUSION_SUCCESS, nil, "x") | |||
| 667 | + | return gh, gh["event"].(map[string]any) | |||
| 668 | + | } | |||
| 669 | + | ||||
| 670 | + | gh, event := ev() | |||
| 671 | + | assert.Equal(t, publicOrigin+"/proj/commit/"+first[:12], event["compare"], "a created ref compares as its commit") | |||
| 672 | + | assert.Equal(t, true, event["created"]) | |||
| 673 | + | assert.Equal(t, domain.ZeroOID, event["before"]) | |||
| 674 | + | repo := event["repository"].(map[string]any) | |||
| 675 | + | assert.Equal(t, "main", repo["default_branch"]) | |||
| 676 | + | assert.Equal(t, "main", repo["master_branch"]) | |||
| 677 | + | assert.Equal(t, "90", gh["retention_days"], "a string, from the configured retention") | |||
| 678 | + | head := event["head_commit"].(map[string]any) | |||
| 679 | + | tree := strings.TrimSpace(c.bareGit("proj", "rev-parse", first+"^{tree}")) | |||
| 680 | + | assert.Equal(t, tree, head["tree_id"]) | |||
| 681 | + | ||||
| 682 | + | second := c.push("main", map[string]string{"a.txt": "a\n"}, "") | |||
| 683 | + | _, event = ev() | |||
| 684 | + | assert.Equal(t, publicOrigin+"/proj/compare/"+first[:12]+"..."+second[:12], event["compare"]) | |||
| 685 | + | assert.Equal(t, false, event["created"]) | |||
| 686 | + | } | |||
M internal/usecase/ci_trigger.go +42 -13
| @@ -130,6 +130,8 @@ type pushFacts struct { | |||
| 130 | 130 | filesTruncated bool | |
| 131 | 131 | tagCount int | |
| 132 | 132 | isTag bool | |
| 133 | + | // defaultBranch is the default branch of the repository, "" when unknown. | |
| 134 | + | defaultBranch string | |
| 133 | 135 | } | |
| 134 | 136 | ||
| 135 | 137 | func (c *CI) handleRef(ctx context.Context, t ciTrigger, u domain.RefUpdate, tagCount int) error { | |
| @@ -179,6 +181,9 @@ func (c *CI) collect(ctx context.Context, repo domain.RepoName, u domain.RefUpda | |||
| 179 | 181 | return pushFacts{}, err | |
| 180 | 182 | } | |
| 181 | 183 | f := pushFacts{update: u, created: u.IsCreate(), isTag: isTag, tagCount: tagCount} | |
| 184 | + | if def, _, err := c.cfg.Repos.DefaultBranch(ctx, repo); err == nil { | |
| 185 | + | f.defaultBranch = def | |
| 186 | + | } | |
| 182 | 187 | res, err := c.cfg.Reader.ResolveRevision(ctx, repo, domain.RevisionOf(newID)) | |
| 183 | 188 | if err != nil { | |
| 184 | 189 | return f, fmt.Errorf("resolve %s: %w", u.New, err) | |
| @@ -381,7 +386,7 @@ func (c *CI) startRun(ctx context.Context, repo domain.Repo, t ciTrigger, f push | |||
| 381 | 386 | Status: domain.CIQueued, CreatedAt: now, | |
| 382 | 387 | } | |
| 383 | 388 | d := ports.CIRunDraft{Run: run, Source: domain.CIRunSource{ | |
| 384 | - | Repo: repo.Name, WorkflowYAML: yaml, GithubJSON: c.githubJSON(repo, run, f, wf), | |
| 389 | + | Repo: repo.Name, WorkflowYAML: yaml, GithubJSON: c.githubJSON(ctx, repo, run, f, wf), | |
| 385 | 390 | }} | |
| 386 | 391 | for i, j := range wf.Jobs { | |
| 387 | 392 | job := domain.CIJob{ | |
| @@ -413,14 +418,33 @@ func (c *CI) startRun(ctx context.Context, repo domain.Repo, t ciTrigger, f push | |||
| 413 | 418 | ||
| 414 | 419 | // --- the github context --- | |
| 415 | 420 | ||
| 421 | + | // shortID is the 12-character form of an object id that GitHub puts in the | |
| 422 | + | // compare URL of a push. | |
| 423 | + | func shortID(id string) string { | |
| 424 | + | if len(id) > 12 { | |
| 425 | + | return id[:12] | |
| 426 | + | } | |
| 427 | + | return id | |
| 428 | + | } | |
| 429 | + | ||
| 430 | + | // retentionDays is the retention in days, as github.retention_days shows it | |
| 431 | + | // (at least 1). | |
| 432 | + | func (c *CI) retentionDays() int { | |
| 433 | + | return max(int(c.cfg.Retention/(24*time.Hour)), 1) | |
| 434 | + | } | |
| 435 | + | ||
| 416 | 436 | type obj = map[string]any | |
| 417 | 437 | ||
| 418 | 438 | func person(name, email string) obj { return obj{"name": name, "email": email} } | |
| 419 | 439 | ||
| 420 | - | func (c *CI) commitJSON(repo domain.Repo, cm domain.Commit) obj { | |
| 440 | + | func (c *CI) commitJSON(ctx context.Context, repo domain.Repo, cm domain.Commit) obj { | |
| 421 | 441 | ts := cm.Committer.Time.UTC().Format(time.RFC3339) | |
| 442 | + | tree := "" | |
| 443 | + | if id, err := c.cfg.Git.CommitTree(ctx, repo.Name, cm.ID); err == nil { | |
| 444 | + | tree = id.String() | |
| 445 | + | } | |
| 422 | 446 | return obj{ | |
| 423 | - | "id": cm.ID.String(), "tree_id": "", "distinct": true, "message": cm.Message, "timestamp": ts, | |
| 447 | + | "id": cm.ID.String(), "tree_id": tree, "distinct": true, "message": cm.Message, "timestamp": ts, | |
| 424 | 448 | "url": c.cfg.PublicURL + "/" + repo.Name.String() + "/commit/" + cm.ID.String(), | |
| 425 | 449 | "author": obj{"name": cm.Author.Name, "email": cm.Author.Email, "username": ""}, | |
| 426 | 450 | "committer": obj{"name": cm.Committer.Name, "email": cm.Committer.Email, "username": ""}, | |
| @@ -432,10 +456,15 @@ func (c *CI) commitJSON(repo domain.Repo, cm domain.Commit) obj { | |||
| 432 | 456 | // (the job-dependent keys are added when a job is planned). Values that | |
| 433 | 457 | // GitHub's documentation does not settle are marked for the recordings. | |
| 434 | 458 | // | |
| 435 | - | // TODO(verify with recording): the exact types of run_id, run_number, | |
| 436 | - | // run_attempt (strings) and retention_days (a number), the empty tree_id and | |
| 437 | - | // the empty added/removed/modified lists of the push commits. | |
| 438 | - | func (c *CI) githubJSON(repo domain.Repo, run domain.CIRun, f pushFacts, wf *workflow.Workflow) string { | |
| 459 | + | // Checked against the recordings of ermite-conformance (push-branch-create, | |
| 460 | + | // push-tag, push-force, ctx-github-names): ids and counters are strings, so is | |
| 461 | + | // retention_days; "compare" has 12-character ids, the commit page for a created | |
| 462 | + | // ref and "<before>...<after>" for an update; repository.default_branch and | |
| 463 | + | // master_branch are the default branch. | |
| 464 | + | // | |
| 465 | + | // TODO(verify with recording): the empty added/removed/modified lists of the | |
| 466 | + | // push commits. | |
| 467 | + | func (c *CI) githubJSON(ctx context.Context, repo domain.Repo, run domain.CIRun, f pushFacts, wf *workflow.Workflow) string { | |
| 439 | 468 | full := c.cfg.Owner + "/" + repo.Name.String() | |
| 440 | 469 | refName, refType := strings.TrimPrefix(run.Ref, "refs/heads/"), "branch" | |
| 441 | 470 | if f.isTag { | |
| @@ -446,22 +475,22 @@ func (c *CI) githubJSON(repo domain.Repo, run domain.CIRun, f pushFacts, wf *wor | |||
| 446 | 475 | if f.created { | |
| 447 | 476 | before = domain.ZeroOID | |
| 448 | 477 | } | |
| 449 | - | compare := repoURL + "/compare/" + before + "..." + f.update.New | |
| 478 | + | compare := repoURL + "/compare/" + shortID(before) + "..." + shortID(f.update.New) | |
| 450 | 479 | if f.created { | |
| 451 | - | compare = repoURL + "/commit/" + f.update.New | |
| 480 | + | compare = repoURL + "/commit/" + shortID(f.update.New) | |
| 452 | 481 | } | |
| 453 | 482 | commits := make([]any, 0, len(f.commits)) | |
| 454 | 483 | for _, cm := range f.commits { | |
| 455 | - | commits = append(commits, c.commitJSON(repo, cm)) | |
| 484 | + | commits = append(commits, c.commitJSON(ctx, repo, cm)) | |
| 456 | 485 | } | |
| 457 | 486 | event := obj{ | |
| 458 | 487 | "ref": run.Ref, "before": before, "after": f.update.New, "created": f.created, "deleted": false, "forced": f.forced, | |
| 459 | - | "base_ref": nil, "compare": compare, "commits": commits, "head_commit": c.commitJSON(repo, f.head), | |
| 488 | + | "base_ref": nil, "compare": compare, "commits": commits, "head_commit": c.commitJSON(ctx, repo, f.head), | |
| 460 | 489 | "pusher": person(run.Actor, ""), | |
| 461 | 490 | "repository": obj{ | |
| 462 | 491 | "name": repo.Name.String(), "full_name": full, "private": repo.Visibility == domain.VisibilityPrivate, | |
| 463 | 492 | "owner": obj{"login": c.cfg.Owner, "name": c.cfg.Owner}, "html_url": repoURL, "clone_url": repoURL + ".git", | |
| 464 | - | "default_branch": "", "url": repoURL, | |
| 493 | + | "default_branch": f.defaultBranch, "master_branch": f.defaultBranch, "url": repoURL, | |
| 465 | 494 | }, | |
| 466 | 495 | "sender": obj{"login": run.Actor, "type": "User"}, | |
| 467 | 496 | } | |
| @@ -472,7 +501,7 @@ func (c *CI) githubJSON(repo domain.Repo, run domain.CIRun, f pushFacts, wf *wor | |||
| 472 | 501 | "actor": run.Actor, "triggering_actor": run.Actor, "workflow": run.WorkflowName, "workflow_ref": wfRef, | |
| 473 | 502 | "workflow_sha": run.Sha, "run_id": strconv.FormatInt(run.ID, 10), "run_number": strconv.FormatInt(run.Number, 10), | |
| 474 | 503 | "server_url": c.cfg.PublicURL, "api_url": c.cfg.PublicURL + "/-/github/api/v3", | |
| 475 | - | "graphql_url": c.cfg.PublicURL + "/-/github/api/graphql", "retention_days": domain.CIRetentionDays, | |
| 504 | + | "graphql_url": c.cfg.PublicURL + "/-/github/api/graphql", "retention_days": strconv.Itoa(c.retentionDays()), | |
| 476 | 505 | "head_ref": "", "base_ref": "", | |
| 477 | 506 | } | |
| 478 | 507 | b, err := json.Marshal(gh) | |
| @@ -130,6 +130,8 @@ type pushFacts struct { | |||||
| 130 | filesTruncated bool | 130 | filesTruncated bool | ||
| 131 | tagCount int | 131 | tagCount int | ||
| 132 | isTag bool | 132 | isTag bool | ||
| 133 | + | // defaultBranch is the default branch of the repository, "" when unknown. | |||
| 134 | + | defaultBranch string | |||
| 133 | } | 135 | } | ||
| 134 | 136 | ||||
| 135 | func (c *CI) handleRef(ctx context.Context, t ciTrigger, u domain.RefUpdate, tagCount int) error { | 137 | func (c *CI) handleRef(ctx context.Context, t ciTrigger, u domain.RefUpdate, tagCount int) error { | ||
| @@ -179,6 +181,9 @@ func (c *CI) collect(ctx context.Context, repo domain.RepoName, u domain.RefUpda | |||||
| 179 | return pushFacts{}, err | 181 | return pushFacts{}, err | ||
| 180 | } | 182 | } | ||
| 181 | f := pushFacts{update: u, created: u.IsCreate(), isTag: isTag, tagCount: tagCount} | 183 | f := pushFacts{update: u, created: u.IsCreate(), isTag: isTag, tagCount: tagCount} | ||
| 184 | + | if def, _, err := c.cfg.Repos.DefaultBranch(ctx, repo); err == nil { | |||
| 185 | + | f.defaultBranch = def | |||
| 186 | + | } | |||
| 182 | res, err := c.cfg.Reader.ResolveRevision(ctx, repo, domain.RevisionOf(newID)) | 187 | res, err := c.cfg.Reader.ResolveRevision(ctx, repo, domain.RevisionOf(newID)) | ||
| 183 | if err != nil { | 188 | if err != nil { | ||
| 184 | return f, fmt.Errorf("resolve %s: %w", u.New, err) | 189 | return f, fmt.Errorf("resolve %s: %w", u.New, err) | ||
| @@ -381,7 +386,7 @@ func (c *CI) startRun(ctx context.Context, repo domain.Repo, t ciTrigger, f push | |||||
| 381 | Status: domain.CIQueued, CreatedAt: now, | 386 | Status: domain.CIQueued, CreatedAt: now, | ||
| 382 | } | 387 | } | ||
| 383 | d := ports.CIRunDraft{Run: run, Source: domain.CIRunSource{ | 388 | d := ports.CIRunDraft{Run: run, Source: domain.CIRunSource{ | ||
| 384 | - | Repo: repo.Name, WorkflowYAML: yaml, GithubJSON: c.githubJSON(repo, run, f, wf), | 389 | + | Repo: repo.Name, WorkflowYAML: yaml, GithubJSON: c.githubJSON(ctx, repo, run, f, wf), |
| 385 | }} | 390 | }} | ||
| 386 | for i, j := range wf.Jobs { | 391 | for i, j := range wf.Jobs { | ||
| 387 | job := domain.CIJob{ | 392 | job := domain.CIJob{ | ||
| @@ -413,14 +418,33 @@ func (c *CI) startRun(ctx context.Context, repo domain.Repo, t ciTrigger, f push | |||||
| 413 | 418 | ||||
| 414 | // --- the github context --- | 419 | // --- the github context --- | ||
| 415 | 420 | ||||
| 421 | + | // shortID is the 12-character form of an object id that GitHub puts in the | |||
| 422 | + | // compare URL of a push. | |||
| 423 | + | func shortID(id string) string { | |||
| 424 | + | if len(id) > 12 { | |||
| 425 | + | return id[:12] | |||
| 426 | + | } | |||
| 427 | + | return id | |||
| 428 | + | } | |||
| 429 | + | ||||
| 430 | + | // retentionDays is the retention in days, as github.retention_days shows it | |||
| 431 | + | // (at least 1). | |||
| 432 | + | func (c *CI) retentionDays() int { | |||
| 433 | + | return max(int(c.cfg.Retention/(24*time.Hour)), 1) | |||
| 434 | + | } | |||
| 435 | + | ||||
| 416 | type obj = map[string]any | 436 | type obj = map[string]any | ||
| 417 | 437 | ||||
| 418 | func person(name, email string) obj { return obj{"name": name, "email": email} } | 438 | func person(name, email string) obj { return obj{"name": name, "email": email} } | ||
| 419 | 439 | ||||
| 420 | - | func (c *CI) commitJSON(repo domain.Repo, cm domain.Commit) obj { | 440 | + | func (c *CI) commitJSON(ctx context.Context, repo domain.Repo, cm domain.Commit) obj { |
| 421 | ts := cm.Committer.Time.UTC().Format(time.RFC3339) | 441 | ts := cm.Committer.Time.UTC().Format(time.RFC3339) | ||
| 442 | + | tree := "" | |||
| 443 | + | if id, err := c.cfg.Git.CommitTree(ctx, repo.Name, cm.ID); err == nil { | |||
| 444 | + | tree = id.String() | |||
| 445 | + | } | |||
| 422 | return obj{ | 446 | return obj{ | ||
| 423 | - | "id": cm.ID.String(), "tree_id": "", "distinct": true, "message": cm.Message, "timestamp": ts, | 447 | + | "id": cm.ID.String(), "tree_id": tree, "distinct": true, "message": cm.Message, "timestamp": ts, |
| 424 | "url": c.cfg.PublicURL + "/" + repo.Name.String() + "/commit/" + cm.ID.String(), | 448 | "url": c.cfg.PublicURL + "/" + repo.Name.String() + "/commit/" + cm.ID.String(), | ||
| 425 | "author": obj{"name": cm.Author.Name, "email": cm.Author.Email, "username": ""}, | 449 | "author": obj{"name": cm.Author.Name, "email": cm.Author.Email, "username": ""}, | ||
| 426 | "committer": obj{"name": cm.Committer.Name, "email": cm.Committer.Email, "username": ""}, | 450 | "committer": obj{"name": cm.Committer.Name, "email": cm.Committer.Email, "username": ""}, | ||
| @@ -432,10 +456,15 @@ func (c *CI) commitJSON(repo domain.Repo, cm domain.Commit) obj { | |||||
| 432 | // (the job-dependent keys are added when a job is planned). Values that | 456 | // (the job-dependent keys are added when a job is planned). Values that | ||
| 433 | // GitHub's documentation does not settle are marked for the recordings. | 457 | // GitHub's documentation does not settle are marked for the recordings. | ||
| 434 | // | 458 | // | ||
| 435 | - | // TODO(verify with recording): the exact types of run_id, run_number, | 459 | + | // Checked against the recordings of ermite-conformance (push-branch-create, |
| 436 | - | // run_attempt (strings) and retention_days (a number), the empty tree_id and | 460 | + | // push-tag, push-force, ctx-github-names): ids and counters are strings, so is |
| 437 | - | // the empty added/removed/modified lists of the push commits. | 461 | + | // retention_days; "compare" has 12-character ids, the commit page for a created |
| 438 | - | func (c *CI) githubJSON(repo domain.Repo, run domain.CIRun, f pushFacts, wf *workflow.Workflow) string { | 462 | + | // ref and "<before>...<after>" for an update; repository.default_branch and |
| 463 | + | // master_branch are the default branch. | |||
| 464 | + | // | |||
| 465 | + | // TODO(verify with recording): the empty added/removed/modified lists of the | |||
| 466 | + | // push commits. | |||
| 467 | + | func (c *CI) githubJSON(ctx context.Context, repo domain.Repo, run domain.CIRun, f pushFacts, wf *workflow.Workflow) string { | |||
| 439 | full := c.cfg.Owner + "/" + repo.Name.String() | 468 | full := c.cfg.Owner + "/" + repo.Name.String() | ||
| 440 | refName, refType := strings.TrimPrefix(run.Ref, "refs/heads/"), "branch" | 469 | refName, refType := strings.TrimPrefix(run.Ref, "refs/heads/"), "branch" | ||
| 441 | if f.isTag { | 470 | if f.isTag { | ||
| @@ -446,22 +475,22 @@ func (c *CI) githubJSON(repo domain.Repo, run domain.CIRun, f pushFacts, wf *wor | |||||
| 446 | if f.created { | 475 | if f.created { | ||
| 447 | before = domain.ZeroOID | 476 | before = domain.ZeroOID | ||
| 448 | } | 477 | } | ||
| 449 | - | compare := repoURL + "/compare/" + before + "..." + f.update.New | 478 | + | compare := repoURL + "/compare/" + shortID(before) + "..." + shortID(f.update.New) |
| 450 | if f.created { | 479 | if f.created { | ||
| 451 | - | compare = repoURL + "/commit/" + f.update.New | 480 | + | compare = repoURL + "/commit/" + shortID(f.update.New) |
| 452 | } | 481 | } | ||
| 453 | commits := make([]any, 0, len(f.commits)) | 482 | commits := make([]any, 0, len(f.commits)) | ||
| 454 | for _, cm := range f.commits { | 483 | for _, cm := range f.commits { | ||
| 455 | - | commits = append(commits, c.commitJSON(repo, cm)) | 484 | + | commits = append(commits, c.commitJSON(ctx, repo, cm)) |
| 456 | } | 485 | } | ||
| 457 | event := obj{ | 486 | event := obj{ | ||
| 458 | "ref": run.Ref, "before": before, "after": f.update.New, "created": f.created, "deleted": false, "forced": f.forced, | 487 | "ref": run.Ref, "before": before, "after": f.update.New, "created": f.created, "deleted": false, "forced": f.forced, | ||
| 459 | - | "base_ref": nil, "compare": compare, "commits": commits, "head_commit": c.commitJSON(repo, f.head), | 488 | + | "base_ref": nil, "compare": compare, "commits": commits, "head_commit": c.commitJSON(ctx, repo, f.head), |
| 460 | "pusher": person(run.Actor, ""), | 489 | "pusher": person(run.Actor, ""), | ||
| 461 | "repository": obj{ | 490 | "repository": obj{ | ||
| 462 | "name": repo.Name.String(), "full_name": full, "private": repo.Visibility == domain.VisibilityPrivate, | 491 | "name": repo.Name.String(), "full_name": full, "private": repo.Visibility == domain.VisibilityPrivate, | ||
| 463 | "owner": obj{"login": c.cfg.Owner, "name": c.cfg.Owner}, "html_url": repoURL, "clone_url": repoURL + ".git", | 492 | "owner": obj{"login": c.cfg.Owner, "name": c.cfg.Owner}, "html_url": repoURL, "clone_url": repoURL + ".git", | ||
| 464 | - | "default_branch": "", "url": repoURL, | 493 | + | "default_branch": f.defaultBranch, "master_branch": f.defaultBranch, "url": repoURL, |
| 465 | }, | 494 | }, | ||
| 466 | "sender": obj{"login": run.Actor, "type": "User"}, | 495 | "sender": obj{"login": run.Actor, "type": "User"}, | ||
| 467 | } | 496 | } | ||
| @@ -472,7 +501,7 @@ func (c *CI) githubJSON(repo domain.Repo, run domain.CIRun, f pushFacts, wf *wor | |||||
| 472 | "actor": run.Actor, "triggering_actor": run.Actor, "workflow": run.WorkflowName, "workflow_ref": wfRef, | 501 | "actor": run.Actor, "triggering_actor": run.Actor, "workflow": run.WorkflowName, "workflow_ref": wfRef, | ||
| 473 | "workflow_sha": run.Sha, "run_id": strconv.FormatInt(run.ID, 10), "run_number": strconv.FormatInt(run.Number, 10), | 502 | "workflow_sha": run.Sha, "run_id": strconv.FormatInt(run.ID, 10), "run_number": strconv.FormatInt(run.Number, 10), | ||
| 474 | "server_url": c.cfg.PublicURL, "api_url": c.cfg.PublicURL + "/-/github/api/v3", | 503 | "server_url": c.cfg.PublicURL, "api_url": c.cfg.PublicURL + "/-/github/api/v3", | ||
| 475 | - | "graphql_url": c.cfg.PublicURL + "/-/github/api/graphql", "retention_days": domain.CIRetentionDays, | 504 | + | "graphql_url": c.cfg.PublicURL + "/-/github/api/graphql", "retention_days": strconv.Itoa(c.retentionDays()), |
| 476 | "head_ref": "", "base_ref": "", | 505 | "head_ref": "", "base_ref": "", | ||
| 477 | } | 506 | } | ||
| 478 | b, err := json.Marshal(gh) | 507 | b, err := json.Marshal(gh) | ||