zyv4yk opened a new pull request, #9086:
URL: https://github.com/apache/devlake/pull/9086
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
### ⚠️ Pre Checklist
- [x] I have read through the [Contributing
Documentation](https://devlake.apache.org/community/).
- [x] I have added relevant tests.
- [ ] I have added relevant documentation.
- [x] I will add labels to the PR, such as `pr-type/bug-fix`,
`pr-type/feature-development`, etc.
### Summary
When the GitHub connection runs on GraphQL, every pull request, issue and
review opened by an actor of type `Bot` — GitHub Apps, Dependabot, Renovate,
GitHub Actions — is stored with no author: `author_name = ''`, `author_id = 0`,
and no `pull_requests.author_id` in the domain layer.
`author`, `mergedBy` and review authors are typed `Actor` in the GitHub
schema, and `Actor` is implemented by `User`, `Bot`, `Organization`,
`Mannequin` and `EnterpriseUserAccount`. `GraphqlInlineAccountQuery` spread
only `... on User`, so a `Bot` author came back as an empty selection set and
the `Id == 0` guard in `extractGraphqlPreAccount` then dropped the account. The
REST collector is unaffected, which is why the same repo shows bot PRs on REST
and none on GraphQL.
**The fragment cannot just be added to the existing struct.**
`GraphqlInlineAccountQuery` is reused for fields the schema types as `User` —
PR and issue assignees, and `commit.author.user` — and GitHub rejects the
*entire* query when `... on Bot` is spread there:
```
Fragment on Bot can't be spread inside User
```
So this PR splits the two cases:
- `GraphqlInlineAccountQuery` — unchanged shape, for `User`-typed fields
(assignees, commit authors).
- `GraphqlInlineActorQuery` — `... on User` + `... on Bot`, for
`Actor`-typed fields (`PullRequest.author`, `PullRequest.mergedBy`,
`PullRequestReview.author`, `Issue.author`).
Both expose `Account() GithubAccountEdge`, so the extractors read one
normalized account and stop caring which type the actor resolved to. The
accessor is nil-safe, which also removes the `!= nil` checks at the call sites.
Two details in the normalization:
1. **`Bot.login` has no `[bot]` suffix.** GraphQL returns `dependabot`, REST
returns `dependabot[bot]`, both with `databaseId` `49699333`. The suffix is
appended so one actor does not end up with two logins depending on the
collector. This also keeps the `is_bot` flag from #9000 working: its fallback
is `strings.HasSuffix(login, "[bot]")`, and `_tool_github_accounts.type` is
never populated on the GraphQL path.
2. **`Bot` exposes a narrower field set** than `User` — no `name`, `company`
or `email` — hence a separate `GithubBotEdge`. `Name`, `Company` and `Email`
are left empty, which is exactly what the REST collector stores for a bot (`GET
/users/dependabot[bot]` returns `null` for all three).
One follow-on: `Collect Users` looks bot logins up through `user(login:)`,
which resolves Users only and answers `Could not resolve to a User with the
login of 'dependabot[bot]'`. Errors there are already ignored, but now that bot
logins reach `_tool_github_repo_accounts` that would be one guaranteed
`NOT_FOUND` per bot on every sync, so the cursor skips them. Bots still become
accounts — `ConvertAccounts` reads `_tool_github_repo_accounts` and only
enriches from `_tool_github_accounts` when a row exists.
### Does this close any open issues?
Closes #9085
### Screenshots
Running the query this PR generates against the live API, `nodes { author {
login databaseId } }` on `grafana/grafana`:
| | before | after |
|---|---|---|
| `#131864` | `""` / `0` | `cursor` / `206951365` |
| `#131868` review authors | `""`, `""` | `github-actions`, `cursor` |
| `#131851` review authors | `""`, `""`, `""` |
`copilot-pull-request-reviewer`, `cursor`, `PranshulSoni` |
The single-field version of the same check, which needs nothing but a token:
```
gh api graphql -f query='
{
search(query: "repo:grafana/grafana is:pr author:app/dependabot", type:
ISSUE, first: 1) {
nodes { ... on PullRequest {
number
userFragmentOnly: author { ... on User { login databaseId } }
withBotFragment: author { __typename ... on User { login databaseId }
... on Bot { login databaseId } }
} }
}
}'
{"number":131544,
"userFragmentOnly":{},
"withBotFragment":{"__typename":"Bot","login":"dependabot","databaseId":49699333}}
```
### Other Information
**Tests.** `account_graphql_pre_extractor_test.go` covers the accessor for
both query types (user, bot, bot login that already carries the suffix,
unresolved actor, nil), the raw-layer JSON round trip in both the new and the
pre-fix shape, and — the part that actually guards the regression —
`graphql.ConstructQuery` output, asserting `... on Bot` reaches the actor
fields and never the `User`-typed ones. `go build`, `go vet` and `golangci-lint
run ./plugins/github_graphql/...` are clean. The `e2e` package needs
`E2E_DB_URL` and was not run locally; the only `github_graphql` e2e fixture
covers deployments, which this PR does not touch.
**Existing data.** The author is already empty in `_raw_github_graphql_prs`,
so rows collected before this fix are not repaired by re-running extract or
convert — they need a re-collect in Full Refresh mode.
**Labels.** I do not have permission to set them; this is `pr-type/bug-fix`.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]