Skip to content

Resync onto upstream mattermost-plugin-github (supersedes #7)#10

Open
hstern wants to merge 107 commits into
hhru:masterfrom
hstern:resync/upstream-master
Open

Resync onto upstream mattermost-plugin-github (supersedes #7)#10
hstern wants to merge 107 commits into
hhru:masterfrom
hstern:resync/upstream-master

Conversation

@hstern

@hstern hstern commented Jun 6, 2026

Copy link
Copy Markdown

Per your note on #7 ("pull the master branch up to upstream"), this rebuilds the fork on top of current mattermost/mattermost-plugin-github (e82bb15, 104 commits ahead of the prior sync point) and re-applies the Forgejo adaptation as 3 clean commits on top — server, webapp, build-glue — rather than one unreviewable merge blob. Supersedes #7 (its prod-dep / Node-build fixes are moot on the modern upstream toolchain).

Approach

Branched from upstream/master, then replayed the Forgejo layer (F-struct webhook payloads, REST sidebar in place of GitHub GraphQL, /forgejo command, ForgejoOrg/ForgejoOAuth* config, github_*forgejo_* webapp renames) onto upstream's newer code — folding in upstream's generic improvements and reconciling its partial TypeScript migration (the label selector, user_attribute, and client are now .tsx/.ts).

Verified — headless

  • server builds all 5 targets · go test ./... green · golangci-lint v2.9.0 0 issues
  • webapp tsc check-types + eslint clean · make dist bundles

Verified — live

On a real Mattermost 11.7.2 + Forgejo instance: the plugin activates cleanly, OAuth connect/complete works, and a webhook round-trip (create + pull_request) was received → F-struct-parsed → rendered into a subscribed channel with correct Forgejo URLs.

Intentionally dropped

GitHub-only / GraphQL-dependent features with no Forgejo equivalent: PR-review SLA digest, MM34646 token refresh, telemetry, review-comment mention/author notifications, workflow_run event, default-repo command. (workflow_job, issues, PRs, pushes, and comments are retained.)


Pre-existing issues found during live testing

These are not introduced by this PR — they exist in 2.3.0 — but surfaced while testing and are worth tracking. (Issues are disabled on this repo, so I'm listing them here.) I'm happy to fix these in follow-up PRs once this resync lands and the codebase is reconciled with upstream:

  1. issues webhook events never post. eventTypeMapping has no "issues" entry, so issue open/close/edit events fall through to github.ParseWebHook, which fails on the Forgejo payload (json: cannot unmarshal string into Go struct field Repository.issue.repository.owner of type github.User). Fix: add an FIssueEvent struct + map "issues" to it, like the other F* handlers.
  2. Rotated Forgejo OAuth refresh tokens aren't persisted. Forgejo rotates refresh tokens on use; the plugin doesn't store the rotated token, so after the access token expires (or the plugin restarts) the next refresh fails with oauth2: "unauthorized_client" "token was already used", breaking per-user API calls (private-repo permission checks, sidebar, todo) until /forgejo disconnect + /forgejo connect. Fix: wrap the oauth2.TokenSource to persist refreshed tokens back to the KV store.
  3. makeForgejoRequest can nil-panic. When forgejoClient.Get() returns an error the response is nil, but the function proceeds to json.NewDecoder(response.Body) → nil-pointer dereference (e.g. triggered by HH-258530 sync with upstream and fix tests #2). Fix: return the zero value on error / nil response.

This is offered to save you the effort you mentioned — please treat it as a starting point. Take it whole, cherry-pick, or set it aside for your own sync; I've kept the commits reviewable and deferred to your runtime testing. Happy to adjust anything.

🤖 Generated with Claude Code

Kshitij-Katiyar and others added 30 commits January 9, 2025 17:18
…o TS (mattermost#851)

* [MM-944]: Typescript migration and converting github_label_selector to TS

* [MM-944]

* [MM-944]: removed the use of any

* [MM-944]: fixed lint
…h revoked/invalid token (mattermost#832)

* [MM-809]: fix the issue of getting errors when using github api with revoked/invalid token

* [MM-809]: Added proper error log in using github client

* [MM-809]: Fixed lint

* Update server/plugin/plugin.go

* Update server/plugin/plugin.go

* [MM-809]: review fixes

---------

Co-authored-by: Doug Lauder <wiggin77@warpmail.net>
…tion (mattermost#859)

* [MM-856]: Added the requested reviewers in the pulls_created notification

* Update server/plugin/template.go

Co-authored-by: Raghav Aggarwal <raghav.aggarwal@brightscout.com>

---------

Co-authored-by: Raghav Aggarwal <raghav.aggarwal@brightscout.com>
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.27.0 to 0.33.0.
- [Commits](golang/net@v0.27.0...v0.33.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Apply and enforce file-level license headers

Use `mattermost-govet` and `eslint`'s `header/header` to ensure each
file begins with the appropriate header, then fix all instances.

```
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
```

Note that this renames `LICENSE` to `LICENSE.txt` purely to align on the
copyright messaging across repos.

* align plugin-ci with go.mod version

* switch to 2018

* bundle LICENSE.txt and NOTICE.txt if they exist

* updated NOTICE.txt and configuration
…channel (mattermost#806)

* [MM-611]: Added the feature to select the default repository for the channel per User

* [MM-611]: Updated the help text

* [MM-611]: review fixes

* [MM-611]: review fixes

* [MM-611]: review fixes

* [MM-611]: Fixed the lint issue

* [MM-611]: resolved map accessing empty array error

* [MM-611]: review fixes

* updated json for repo data
* [MM-408]: Made username clickable in RHS PRs/Issues

* made link openeing in new tab
* Template PR for server unit test cases

* Fixed lint errors

* added testcase for some functions in server/api.go

* Fixed lint issue

* added testcase for server/api.go UpdateSetting function

* Added testcase for CheckPluginRequest middleware function

* merge master into branch
* Template PR for server unit test cases

* Fixed lint errors

* added testcase for some functions in server/api.go

* addede testcase for some functions in server/command.go

* Fixed lint issue

* added testcase for server/api.go UpdateSetting function

* Updated the getMutedUser function to return proper response

* added logs to the new error check

* Added testcase for CheckPluginRequest middleware function

* fixed grammar of error msgs in command.go

* merge master into branch

* review fixes

* updated muted list testcases
* Template PR for server unit test cases

* Fixed lint errors

* added testcase for some functions in server/api.go

* addede testcase for some functions in server/command.go

* Fixed lint issue

* added testcase for server/api.go UpdateSetting function

* Added testcase for more functions in api/command.go

* review fixes

* fixed lint

* added license to new file
* [MM-770]: Added webapp testcase for create issue modal

* [MM-770]: removed extra comments

* [MM-770]: fixed lint issues

* [MM-770]: review fixes
Snyk has created this PR to upgrade pg from 8.10.0 to 8.13.1.

See this package in npm:
pg

See this project in Snyk:
https://app.snyk.io/org/mattermost-core/project/ba8e6130-260b-4063-b7c5-2e03cc658662?utm_source=github-enterprise&utm_medium=referral&page=upgrade-pr

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
* Add license header to setup.tsx

* updated snapshot, resolved imports in webapp testcases  and added react-dom

---------

Co-authored-by: kshitij katiyar <kshitij.katiyar@brightscout.com>
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.6.0 to 6.6.1.
- [Commits](indutny/elliptic@v6.6.0...v6.6.1)

---
updated-dependencies:
- dependency-name: elliptic
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…al lock (mattermost#892)

* fix attach comment to issue feature

* fixed lint

* updated snapshot

* Update server/plugin/utils.go

* Update server/plugin/utils.go

* Review fix

* Remove package-lock changes

* Code refactoring

* Fix lint error

* Fix lint error

* Fix lint

---------

Co-authored-by: Doug Lauder <wiggin77@warpmail.net>
Co-authored-by: raghavaggarwal2308 <raghav.aggarwal@brightscout.com>
…attermost#891)

* add events to be selected in webhook

* added header to webapp file

* fixed testcase

* add updated snapshot

* Revert package-lock changes

---------

Co-authored-by: raghavaggarwal2308 <raghav.aggarwal@brightscout.com>
* Fix issue with getting same msg for different discussion events

* Fix comment events

* Handle discussion edited event
… among valid org list (mattermost#902)

* Fix issue of invalid repo not listing with orgs

* fixed attach to issue modal
Bumps [image-size](https://github.com/image-size/image-size) from 1.2.0 to 1.2.1.
- [Release notes](https://github.com/image-size/image-size/releases)
- [Commits](image-size/image-size@v1.2.0...v1.2.1)

---
updated-dependencies:
- dependency-name: image-size
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…bscriptions (mattermost#797)

* Add --include-only-org-members flag for channel subscriptions

* Refactor method's name includeOnlyConfigOrgMembers => shouldDenyEventDueToNotOrgMember (mattermost#797)

* Refactor return state for readability (mattermost#797)

* fixed lint

* fixed lint

* fixed issue of filter not working

* fixed lint

* fixed misspelling

* fixed lint

---------

Co-authored-by: kshitij katiyar <kshitij.katiyar@brightscout.com>
…#847)

* Template PR for server unit test cases

* Fixed lint errors

* added testcase for some functions in server/api.go

* addede testcase for some functions in server/command.go

* Fixed lint issue

* added testcase for server/api.go UpdateSetting function

* Added testcase for more functions in api/command.go

* [MM-918]: Added testcase for more functions in command.go

* [MM-946]: Added testcases for some functions in command.go (mattermost#854)

* [MM-946]: Added testcases for some functions in command.go

* [MM-946]: reduced permissions to test os

* review fixes

* Added license header
* Bump golang.org/x/crypto from 0.31.0 to 0.35.0

Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.31.0 to 0.35.0.
- [Commits](golang/crypto@v0.31.0...v0.35.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.35.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix linter

* CI go ver

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: wiggin77 <wiggin77@warpmail.net>
Bumps  and [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime). These dependencies needed to be updated together.

Updates `@babel/runtime` from 7.11.2 to 7.27.1
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.27.1/packages/babel-runtime)

Updates `@babel/runtime` from 7.24.7 to 7.27.1
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.27.1/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-version: 7.27.1
  dependency-type: direct:development
- dependency-name: "@babel/runtime"
  dependency-version: 7.27.1
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.33.0 to 0.38.0.
- [Commits](golang/net@v0.33.0...v0.38.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.38.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…draft PRs (mattermost#804)

* [MM-594] Added config setting for getting notification for draft PRs

* updated help text and display name for GetNotificationForDraftPRs config

Co-authored-by: Doug Lauder <wiggin77@warpmail.net>

* improved logic

* get notificaiton for readyForReview in all cases

---------

Co-authored-by: kshitij katiyar <90389917+Kshitij-Katiyar@users.noreply.github.com>
Co-authored-by: Doug Lauder <wiggin77@warpmail.net>
Co-authored-by: kshitij katiyar <kshitij.katiyar@brightscout.com>
…nod:issue-669 (mattermost#766)

* rebased changes + typescript reducers

* resolved manifest import in gihub repo selector

* fix logs

* fixed testcases

* review fixes

---------

Co-authored-by: kshitij katiyar <kshitij.katiyar@brightscout.com>
dependabot Bot and others added 27 commits March 23, 2026 17:49
* Bump flatted from 3.3.3 to 3.4.2 in /webapp

Bumps [flatted](https://github.com/WebReflection/flatted) from 3.3.3 to 3.4.2.
- [Commits](WebReflection/flatted@v3.3.3...v3.4.2)

---
updated-dependencies:
- dependency-name: flatted
  dependency-version: 3.4.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Fixing linter issue with govet reading webapp

* Fixing year for license files

* Excluding path for golangci

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: avasconcelos114 <andre.onogoro@gmail.com>
* Add PR review SLA for todo, sidebar, and optional channel alerts

- System Console: optional review target (days) and overdue alert channel ID
- /github todo and daily reminder: per-review due/overdue from PR open date
- Left sidebar: color review counter when SLA enabled (clear vs overdue)
- Post to configured channel once per user/day on daily reminder when overdue
* Added missing checks for muted notifications in webhook handlers

* Fixing issue with possible false positives returned by string evalutation

* Added test cases for muted flows

* Ensuring muting is case insensitive

* Fixing linter errors
Bumps [yaml](https://github.com/eemeli/yaml) from 1.10.2 to 1.10.3.
- [Release notes](https://github.com/eemeli/yaml/releases)
- [Commits](eemeli/yaml@v1.10.2...v1.10.3)

---
updated-dependencies:
- dependency-name: yaml
  dependency-version: 1.10.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps  and [picomatch](https://github.com/micromatch/picomatch). These dependencies needed to be updated together.

Updates `picomatch` from 2.3.1 to 2.3.2
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](micromatch/picomatch@2.3.1...2.3.2)

Updates `picomatch` from 4.0.3 to 4.0.4
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](micromatch/picomatch@2.3.1...2.3.2)

---
updated-dependencies:
- dependency-name: picomatch
  dependency-version: 2.3.2
  dependency-type: indirect
- dependency-name: picomatch
  dependency-version: 4.0.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
)

* WIP: Adding support for workflow run events

* Removing unused values

* Refactoring for simplicity and removing redundant functions

* Fixing linter error

* Added missing subscription filter checks

* Added tests, improving workflow handler flow

* Fixing org repo order in text fixture

* Updated test assertions and added cancelled and timed_out cases
Bumps [picomatch](https://github.com/micromatch/picomatch) from 2.3.1 to 2.3.2.
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](micromatch/picomatch@2.3.1...2.3.2)

---
updated-dependencies:
- dependency-name: picomatch
  dependency-version: 2.3.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…ermost#988)

* Fix input validation in PR details and issue creation endpoints

* Coderabbit review

* PR feedback

* Harden input validation for edge cases

Made-with: Cursor

---------

Co-authored-by: Nevyana Angelova <nevyangelova@192.168.100.29>
* MM-67613 Added handling of encryption key rotation with force disconnect fallback

* Added force disconnect fallback on normal disconnect flow

- Ensuring that even if an environment somehow bypasses the OnConfigurationChanged hook, a user can still disconnect and re-connect their accounts instead of being locked

* Ensuring any failure to fetch a page of KV entries doesn't abort the entire rotation flow

* PR review fixes

* Improving behavior in clustered environments to prevent race conditions

* Addressing multiple issues with rotation

- Making sure rotation is non-blocking
- Passing correct references to remove risk of race conditions
- Applying stricter unpad logic

* Added audit logging to migration process

* Fixing issue with force disconnect not working
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.23 to 4.18.1.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](lodash/lodash@4.17.23...4.18.1)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
)

Co-authored-by: Nevyana Angelova <nevyangelova@192.168.100.47>
…ata exposure (mattermost#997)

Co-authored-by: Nevyana Angelova <nevyangelova@192.168.100.47>
* MM-68539: exclude draft PRs from review search results

Drafts are not ready for review and shouldn't appear in /github todo,
the daily reminder DM, or the SLA overdue digest. Add draft:false to
the shared review search query so all three call sites filter drafts
consistently.

* MM-68539: bucket the SLA digest into fixed overdue ranges

Replace the per-day buckets with seven fixed ranges (1-3 / 4-7 / 8-14 /
15-30 / 31-90 / 91-365 / >1 year) so a digest with many overdue PRs
stays scannable instead of producing dozens of single-day headers.

Also surface the configured SLA target in the top-level header so
readers can see what threshold the buckets are measured against.

* MM-68539: link PRs from each digest line

Render the PR title as a markdown link so readers can click straight
through from the channel digest to the pull request. Escape `]` and
`\` in titles so JIRA-prefixed names like "[MM-12345] Fix thing" do
not terminate the link early.

* MM-68539: render Mattermost mentions for digest reviewers

Map each reviewer's GitHub login to their Mattermost username via the
existing getGitHubToUsernameMapping helper so the digest produces real
Mattermost @-mentions:

  - @harrison (hmhealey) - owner/repo - [title](url)

Reviewers who haven't connected the GitHub plugin render as
"(not connected) - <githublogin>" so the digest still surfaces them
without misleading anyone with an @ that won't notify.

* MM-68539: backfill SLA start time from PR timeline

The digest's days-overdue clock previously used the cached time of the
review_requested webhook, falling back to the PR open date when no KV
record existed. PRs whose most recent review was requested before the
plugin was installed therefore showed nonsense numbers like 86 days
overdue when the actual outstanding review was a few days old.

When the digest collector encounters a PR with no cached SLA start, it
now pages the issue timeline once to find the most recent surviving
review_requested event for the reviewer and caches the result under
the existing slarr_v1_* key. Subsequent runs are free.

Only the digest path uses the new effectiveReviewSLAStartForDigest
variant; /github todo and the RHS panel keep using the no-network
effectiveReviewSLAStart so user-facing requests stay fast.

* MM-68539: scan all org PRs for overdue reviewers

The digest used to iterate over each connected Mattermost user and run a
separate GitHub search per user. That meant a reviewer was only included
when they had personally connected their GitHub account, which is why the
first run only listed hmhealey.

Replace that loop with a single org-wide GraphQL search per configured
organization. The query asks for every open non-draft PR plus its
requestedReviewers (users and teams). Team review requests are expanded
once per run via the Teams API, with results cached so we don't refetch
the same team on every PR. Each (PR, reviewer) pair is deduped before
being scored against the SLA target.

The org scan needs an authenticated caller, so we pick the first
connected Mattermost user as a service user. If no Mattermost user has
connected a GitHub account yet, the digest logs a warning and skips
posting rather than running with no token.

Also cleans up an embedded-field selector in
findMostRecentReviewRequestTime that staticcheck flagged after the
timeline backfill commit landed.

* MM-68539: show review due dates in the RHS panel

The "Pull Requests Needing Review" panel showed each PR's open date but
not whether the review was actually overdue against the configured SLA,
so engineers had no way to spot urgent items at a glance.

Render an SLA badge per review item with one of three states:
"Overdue by N days" (red), "Due today" (amber), or "Due in N days"
(neutral). The badge only appears in the REVIEWS panel and only when an
admin has set a positive Review Target Days; other RHS panels and
unconfigured installs are unchanged.

Extract the SLA-start and overdue computation into webapp/src/utils/sla
so the existing red-button indicator on the sidebar buttons and the new
per-item badge agree on what "overdue" means. The math mirrors the
server's calendar-day diff (UTC midnight to UTC midnight) so a PR that
is overdue in the digest is overdue in the RHS too. The shared util
prefers review_sla_start (which the server already populates from the
review_request webhook or timeline backfill) and falls back to
created_at, matching the digest's effectiveReviewSLAStart.

Also tightens the configuration reducer's typing so review_target_days
flows through getSidebarData without needing per-call assertions.

* MM-68539: instantiate digest GraphQL query response per call

orgOpenPRsQuery was a package-level var that the graphql library
decoded into. Concurrent callers — e.g. the daily digest scheduler
running alongside an LHS fetch on a different goroutine — could
clobber each other's Search.Nodes mid-decode, producing partial or
duplicated PR lists.

Define the type at package scope (so the graphql library can still
reflect on its tags) but instantiate locally per call so each caller
writes into its own struct.

* MM-68539: decompose SLA digest into testable helpers

The digest's collectAllOverdueSLAItems was a 90-line function that
forged synthetic *github.Issue values to feed into helpers designed
for search-result PRs. Replace that with a small abstraction and
pull each concern into its own function that can be tested in
isolation.

- Introduce prRef as the minimal PR identity SLA code needs (owner,
  repo, number, created_at). effectiveReviewSLAStart now takes prRef
  directly; user-facing call sites build one via prRefFromIssue. The
  digest constructs prRef directly from graphql.DigestPR with no
  forging.
- Extract storeReviewSLAStart so the live review_requested webhook
  and the timeline backfill share one wire-format codepath instead
  of duplicating the RFC3339Nano encode-and-Set logic.
- Extract fetchPRTimeline so timeline events can be cached at the
  digest level. Previously a PR with N requested reviewers triggered
  N timeline fetches; now it's one fetch shared across all reviewers
  on that PR.
- Split collectAllOverdueSLAItems into fetchAllOrgOpenPRs,
  newTeamMemberResolver, gatherReviewersForPR,
  newDigestSLAStartResolver, and evaluateOverdueForReviewer.
- Make pickServiceGitHubUser deterministic by sorting all token-key
  pages before iterating. Without this, a multi-node cluster could
  silently pick different service users on different days as KV
  iteration order shifted, changing which private repos and teams
  the digest could see.
- newDigestSLAStartResolver returns a summarize() callback the
  caller invokes via defer, so its Info-level "backfill summary" log
  fires after the resolver has actually been used (rather than at
  closure-construction time as a defer in the constructor would have
  done). Counters log as plain ints so structured-log backends can
  scrape them numerically. The digest skips constructing the
  resolver entirely when no PRs were fetched, so the summary line
  doesn't fire on degenerate runs.
- Document in the review search query that drafts are excluded but
  the SLA clock still runs through any draft period: webhook-recorded
  starts persist regardless of draft state, so a PR review-requested
  while draft and later un-drafted retains its original SLA start.

New tests cover prRefFromIssue, gatherReviewersForPR,
pickServiceGitHubUser (deterministic ordering, broken-token skip,
no-connected-users), and the summarize() semantics of
newDigestSLAStartResolver (no fire at construction, exactly one fire
on summarize()).

* MM-68539: fix gofmt alignment in SLA digest test

CI's gofmt check flagged the var-block in
TestNewDigestSLAStartResolver_LogsAccurateCounters: the type column
was over-indented by one space because each name had been padded by
one too many.

* MM-68539: address CodeRabbit review feedback

Four findings, all addressed:

1. (sidebar_buttons.jsx) Treat negative reviewTargetDays as disabled.
   reviewButtonStyle's `!targetDays` guard let a negative value through and
   would render the green "online" indicator instead of leaving the button
   neutral. Match the canonical `!targetDays || targetDays <= 0` guard used by
   getReviewSLAStatus / reviewsHaveOverdue.

2. (sla_digest.go) Differentiate "digest could not run" from "nothing
   overdue." collectAllOverdueSLAItems now returns (entries, ok). ok is false
   when no orgs are configured, no connected service user is available, or
   every configured org's GraphQL search failed (tracked via a new
   anyOrgOK return from fetchAllOrgOpenPRs). The caller only advances
   slaDigestDayKVKey when ok is true, so a transient first-of-day failure
   no longer skips every retry until tomorrow.

3. (sla_digest.go) Suppress the "SLA digest backfill summary" log when
   neither timeline_pages_fetched nor kv_hits moved. Prevents a misleading
   "0,0" line on degenerate runs (e.g. PRs without requested reviewers, or
   every reviewer hitting the early-return paths in resolve).

4. (sla_digest.go / review_sla.go) Preserve team-request provenance through
   SLA evaluation. gatherReviewersForPR now returns []reviewerRequest with
   each reviewer's originating teams attached and dedupes case-insensitively
   on login. The digest resolver, when no user-scoped review_requested
   timeline event exists for a reviewer, falls back to the earliest still-
   surviving team-scoped review_requested event via the new
   findEarliestSurvivingTeamRequestTime helper. This fixes the cold-cache
   case where a user pending solely because their team was requested would
   fall all the way back to pr.CreatedAt and overstate days-overdue. The
   resolved time is written to KV under the user-scoped key so subsequent
   runs hit the fast path.

New tests:
- TestGatherReviewersForPR cases for team-only origin, dedup of direct +
  team into a single entry retaining team origin, multi-team accumulation,
  and case-insensitive dedup.
- TestNewDigestSLAStartResolver_SkipsSummaryLogWhenNoLookups locks in the
  guarded summarize() behavior.
- TestFindEarliestSurvivingTeamRequestTime covers add/remove, multi-team
  earliest-wins semantics, defensive sort, and case-insensitive slug match.

* MM-68539: drop redundant loop-variable shadow in gatherReviewersForPR

golangci-lint's modernize linter (the rule that runs as part of
`make check-style`) flagged `team := team` inside the
RequestedTeams loop. Go 1.22+ gives every iteration its own loop
variable, so the manual capture is no longer needed. The inner
`add` call already dereferences `*team` and copies the value into
out[idx].Teams, so removing the shadow does not affect aliasing
either way.

Caught by `make check-style`; the previous commit was checked
with go vet / gofmt / ReadLints / eslint only, which all miss
golangci-lint's modernize ruleset.

* MM-68539: treat ctx cancellation as 'could not run' in SLA digest

CodeRabbit caught that the previous "differentiate could-not-run from
nothing-overdue" change still returned ok=true on a context-canceled
mid-scan, which would advance slaDigestDayKVKey for an interrupted
(partial) walk and suppress retries until the next local day.

Two call sites had this hole; both now return (nil, false) on
ctx.Err():

1. collectAllOverdueSLAItems' per-PR loop: a partial entry list is
   not a real scan, so the caller must not record the day marker.

2. fetchAllOrgOpenPRs' per-org loop: even if some orgs already
   responded successfully, a cancellation interrupted the walk;
   anyOK must be false so the caller treats it as an interrupted
   scan rather than a "real but quiet" one.

New test TestFetchAllOrgOpenPRs_CanceledContextReturnsNotOK locks
in (a) the (nil, false) contract and (b) that the cancellation path
fast-fails without dereferencing the GraphQL client.

* MM-68539: group digest entries by reviewer within each bucket

Before: every overdue (reviewer, PR) pair rendered as its own bullet
with the reviewer prefix repeated on every row, so a reviewer with
five overdue PRs in a single bucket got @-mentioned five times in
that bucket and the digest was a wall of duplicated names.

After: within each bucket, entries are grouped by reviewer. Each
reviewer appears once as the outer bullet (@-mention is also issued
once per bucket), with the per-PR bodies as indented sub-bullets.
Reviewers within a bucket sort case-insensitively; PR bodies within
a reviewer group sort alphabetically. A reviewer who is overdue in
multiple buckets still gets one header per bucket they appear in.

  #### 1-3 days overdue
  - @alice (alice-gh)
    - mattermost/mattermost - [Fix encryption rotation](url)
  - @harrison (hmhealey)
    - mattermost/mattermost - [Fix race condition](url)
    - mattermost/plugin-github - [Add SLA digest](url)

Implementation:
- slaDigestEntry replaces its single Line field with separate
  ReviewerDisplay and Body fields so the builder can group without
  having to parse the pre-baked line back apart.
- formatChannelOverdueReviewLine becomes formatChannelOverduePRBody:
  returns just "<owner>/<repo> - [title](url)" so callers compose
  the outer bullet and the reviewer header. The same body is used
  under whichever reviewer header it belongs to.
- New groupBucketEntriesByReviewer helper handles the per-bucket
  collation with deterministic ordering (the digest is posted
  verbatim, so map iteration order alone would leave the output
  flaky run-to-run).

Tests:
- TestFormatChannelOverduePRBody retargets the existing line-shape
  invariants (escape, truncate, fallback URL) onto the new body
  helper, and adds an explicit "no leading bullet, no reviewer
  prefix" assertion locking in the composability contract.
- TestBuildSLADigestMessage gains:
    - "multiple PRs by the same reviewer in one bucket render under
      a single reviewer header with sorted indented bodies"
    - "two reviewers in the same bucket render as two separate
      reviewer groups"
    - direct unit test on groupBucketEntriesByReviewer for ordering
      and intra-group body sort.

* MM-68539: pin gatherReviewersForPR empty-login invariant via test

Address @nang2049's nit on PR mattermost#999 about the empty-login guard
being implicit. The current code is correct: both call paths
(pr.RequestedUsers and team-expanded logins) feed the shared add()
closure which has `if login == "" { return }` at the top, AND the
GraphQL layer in digest_query.go already drops empty user logins
upstream.

But the protection isn't visible at the loop sites, and there was
no test pinning the contract down — a future refactor that splits
the closure or replaces the helper could quietly drop the guard.

- Comment on add() now spells out that it's the single chokepoint
  for both paths and explains why the guard belongs there rather
  than being duplicated at each loop body.
- New test "empty logins are dropped from both direct and team-
  expanded paths" exercises empty strings on each input vector at
  once and asserts no reviewerRequest with Login=="" can reach the
  caller. If a future change removes the guard from add() or puts
  it in only one of the two loops, this test breaks loudly.
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.6 to 8.5.12.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](postcss/postcss@8.5.6...8.5.12)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.12
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Bump uuid and jest-junit in /webapp

Bumps [uuid](https://github.com/uuidjs/uuid) to 14.0.0 and updates ancestor dependency [jest-junit](https://github.com/jest-community/jest-junit). These dependencies need to be updated together.


Updates `uuid` from 8.3.2 to 14.0.0
- [Release notes](https://github.com/uuidjs/uuid/releases)
- [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md)
- [Commits](uuidjs/uuid@v8.3.2...v14.0.0)

Updates `jest-junit` from 16.0.0 to 17.0.0
- [Release notes](https://github.com/jest-community/jest-junit/releases)
- [Commits](jest-community/jest-junit@v16.0.0...v17.0.0)

---
updated-dependencies:
- dependency-name: uuid
  dependency-version: 14.0.0
  dependency-type: indirect
- dependency-name: jest-junit
  dependency-version: 17.0.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix playwright node version

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Nevyana Angelova <nevyangelova@192.168.100.47>
…mattermost#1002)

Co-authored-by: Nevyana Angelova <nevyangelova@192.168.100.47>
…rops (mattermost#1003)

Co-authored-by: Nevyana Angelova <nevyangelova@192.168.100.47>
…1004)

Co-authored-by: Nevyana Angelova <nevyangelova@192.168.100.47>
…nd createissuecomment handlers (mattermost#1009)

Co-authored-by: Nevyana Angelova <nevyangelova@192.168.100.47>
…1017)

Bumps [qs](https://github.com/ljharb/qs) to 6.15.2 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together.


Updates `qs` from 6.14.1 to 6.15.2
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](ljharb/qs@v6.14.1...v6.15.2)

Updates `express` from 4.22.1 to 4.22.2
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/v4.22.2/History.md)
- [Commits](expressjs/express@v4.22.1...v4.22.2)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.15.2
  dependency-type: indirect
- dependency-name: express
  dependency-version: 4.22.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [qs](https://github.com/ljharb/qs) to 6.15.2 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together.


Updates `qs` from 6.14.1 to 6.15.2
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](ljharb/qs@v6.14.1...v6.15.2)

Updates `express` from 4.22.1 to 4.22.2
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/v4.22.2/History.md)
- [Commits](expressjs/express@v4.22.1...v4.22.2)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.15.2
  dependency-type: indirect
- dependency-name: express
  dependency-version: 4.22.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Improving UX for DMs sent on PR comments

- Preventing edit or delete PR message events from sending a "new comment" DM notification
- Improving logic that cleans body to prevent issues with html comments in the message from interfering with visibility of message

* Fixing issues found in review

* Removed useless empty string return
…3.0 (mattermost#1019)

* Bump github.com/mattermost/mattermost/server/public from 0.1.21 to 0.3.0

Bumps [github.com/mattermost/mattermost/server/public](https://github.com/mattermost/mattermost) from 0.1.21 to 0.3.0.
- [Release notes](https://github.com/mattermost/mattermost/releases)
- [Changelog](https://github.com/mattermost/mattermost/blob/master/CHANGELOG.md)
- [Commits](mattermost/mattermost@server/public/v0.1.21...server/public/v0.3.0)

---
updated-dependencies:
- dependency-name: github.com/mattermost/mattermost/server/public
  dependency-version: 0.3.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Fixing linter error

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: avasconcelos114 <andre.onogoro@gmail.com>
Rebuild the Forgejo server plugin on top of current
mattermost/mattermost-plugin-github (104 commits ahead of the prior
fork point). The Forgejo adaptation is preserved and folded onto
upstream's newer code:

- Webhook payloads parsed into Forgejo F* structs via the
  X-Forgejo-Event header (api.go type defs, webhook.go dispatch).
- LHS sidebar uses Forgejo REST instead of GitHub GraphQL; the
  graphql package is removed entirely.
- ForgejoUserInfo / ForgejoOrg / ForgejoOAuth* config; /forgejo command.
- Folded in upstream's generic improvements (payload-size guard,
  case-insensitive mutes, draft-PR notifications, modern Go idioms).

Dropped GitHub-only features that have no Forgejo equivalent: the
GraphQL-backed PR-review SLA digest, MM34646 token refresh, telemetry,
review-comment mention/author notifications, the workflow_run event,
and the default-repo command. Server builds for all targets, go test
and golangci-lint (v2) pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Port the github_*->forgejo_* webapp components and types onto upstream's
current webapp. Upstream partially migrated to TypeScript since the fork
branched, so the label selector, user_attribute, and client were taken
from upstream's .tsx/.ts and the Forgejo edits folded in (the stale
.jsx/.js twins are removed). Remaining components resolved as content
merges. check-types and eslint pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
plugin.json keeps the Forgejo id/name and drops the SLA-digest settings
(ReviewTargetDays, OverdueReviewsChannelID) that backed a removed
feature; footer points at the Forgejo repo. .gitignore keeps both
upstream and fork entries; CODEOWNERS stays with the fork maintainer;
Makefile keeps upstream's Darwin-aware bundling. make dist produces the
plugin bundle.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@SCREEN88

Copy link
Copy Markdown

Rebase to master, please. Pushed upstream changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.