| @@ -60,17 +60,20 @@ func ProcessCommitMessages(st *store.Store, dir string, repo store.Repo, actorID |
| 60 | 60 | // they are what lands — but the intent is written in the merge request |
| 61 | 61 | // just as often, and a "Closes #N" there used to close nothing. |
| 62 | 62 | // |
| 63 | | // The dedup key is the merged sha, shared with ProcessCommitMessages, so |
| 64 | | // an issue named in both a commit and the description is acted on once. |
| 65 | | func ProcessMRDescription(st *store.Store, repo store.Repo, mr store.MR, actorID int64, sha string) { |
| 63 | // Acting once is guaranteed by the state check, not by the dedup key: a |
| 64 | // commit that closed the issue leaves it closed, and this skips it. The |
| 65 | // key is per merge request rather than the merged sha, because sharing |
| 66 | // the sha let a bare "#N" in a commit message claim it first and silently |
| 67 | // suppress the close. |
| 68 | func ProcessMRDescription(st *store.Store, repo store.Repo, mr store.MR, actorID int64) { |
| 66 | 69 | for _, n := range closingRefs(mr.Title + "\n" + mr.Body) { |
| 67 | 70 | issue, err := st.IssueByNumber(repo.ID, n) |
| 68 | 71 | if err != nil || issue.State != "open" { |
| 69 | 72 | continue // no such issue, or a commit already closed it |
| 70 | 73 | } |
| 71 | | fresh, err := st.TryRecordCommitRef(issue.ID, sha) |
| 74 | fresh, err := st.TryRecordCommitRef(issue.ID, mrRefKey(mr.Number)) |
| 72 | 75 | if err != nil || !fresh { |
| 73 | | continue |
| 76 | continue // this merge request already acted on this issue |
| 74 | 77 | } |
| 75 | 78 | if err := st.SetIssueState(issue.ID, "closed"); err != nil { |
| 76 | 79 | slog.Error("mr refs: closing issue", "issue", n, "err", err) |
| @@ -84,6 +87,12 @@ func ProcessMRDescription(st *store.Store, repo store.Repo, mr store.MR, actorID |
| 84 | 87 | } |
| 85 | 88 | } |
| 86 | 89 | |
| 90 | // mrRefKey namespaces a merge request's dedup record so it cannot |
| 91 | // collide with a commit sha. |
| 92 | func mrRefKey(number int64) string { |
| 93 | return fmt.Sprintf("mr-%d", number) |
| 94 | } |
| 95 | |
| 87 | 96 | // closingRefs returns the issue numbers a text closes, in no order. |
| 88 | 97 | func closingRefs(text string) []int64 { |
| 89 | 98 | seen := map[int64]bool{} |