Skip to content

fix(code): cloud repo picker fetches when only team GitHub integration exists#1989

Closed
VojtechBartos wants to merge 2 commits intomainfrom
posthog-code/fix-cloud-repo-picker-fallback
Closed

fix(code): cloud repo picker fetches when only team GitHub integration exists#1989
VojtechBartos wants to merge 2 commits intomainfrom
posthog-code/fix-cloud-repo-picker-fallback

Conversation

@VojtechBartos
Copy link
Copy Markdown
Member

@VojtechBartos VojtechBartos commented May 4, 2026

Problem

After #1951, the cloud repo picker only reads from the user's personal GitHub integration. Users without one see an empty picker with no network activity — the inner useQueries skips entirely when githubIntegrations.length === 0.

PR authorship-wise, falling back to the team integration is also valid (per the original Slack design: "team integration is still a fallback or primary option in case the user integration is not present or invalid"), but there's nothing in the UI surfacing that fact, so users end up with bot-authored PRs without realizing why.

Solution

  • Add useCloudRepositoryIntegration / useCloudGithubRepositories / useCloudGithubBranches in useIntegrations.ts. They prefer the user-level integration and fall back to the team integration when no personal one is linked. Both branches are always mounted with mutually-exclusive enabled gates so React's hook order stays stable.
  • Drop the cloudRunSource === "signal_report" gate in the task-creation saga. With the unified picker, mutual exclusion is enforced upstream — the saga just forwards whichever ID is populated.
  • Add an inline amber callout below the prompt input (CloudRepoFallbackNotice) when the team-fallback is active, with a one-click "Connect GitHub" action.
  • Extract useConnectUserGithub to deduplicate the connect flow shared with the inbox GitHubConnectionBanner.
  • Add placeholderData: (prev) => prev to useUserGithubRepositories to match the search-stability fix from fix(repo-selector): preserve results while searching #1968 on the team-side path.

Screenshots

Screenshot 2026-05-04 at 11 33 34

Test plan

  • Sign in as a user without a personal GitHub link → cloud workspace mode → repo picker fetches and shows the team's repos.
  • Confirm the amber notice renders below the prompt input. Click "Connect GitHub" → install URL opens in browser.
  • Sign in as a user with a personal GitHub link → notice does not render; picker uses the user integration.
  • Create a cloud task in each scenario → handoff succeeds; check the request payload sends the right github_integration / github_user_integration.

Created with PostHog Code

Repo picker for cloud tasks now flows through useCloudRepositoryIntegration,
which prefers the user's personal GitHub integration and falls back to the
team integration when the user has not linked one. The saga forwards
whichever integration ID is populated, dropping the cloudRunSource gate so
team-fallback tasks no longer drop the integration ID before POST.

Generated-By: PostHog Code
Task-Id: 19c36b01-cbf3-4cd2-b99b-efa50da2256a
…ation

Renders an inline amber callout below the cloud repo picker when the user has
no personal GitHub linked, with a one-click connect action so PRs can be
authored as the user. Extracts the connect flow into a shared
useConnectUserGithub hook reused by the inbox banner.

Generated-By: PostHog Code
Task-Id: 19c36b01-cbf3-4cd2-b99b-efa50da2256a
@VojtechBartos VojtechBartos self-assigned this May 4, 2026
@VojtechBartos VojtechBartos marked this pull request as ready for review May 4, 2026 09:37
@VojtechBartos VojtechBartos requested a review from a team May 4, 2026 09:37
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 4, 2026

Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
apps/code/src/renderer/hooks/useConnectUserGithub.ts:64
**`window.open` fallback removed**

The original `openUrlInBrowser` helper silently fell back to `window.open` when `trpcClient.os.openExternal.mutate` threw. The new code lets the throw propagate to the outer `catch`, so the user sees an error toast instead of the URL opening. In non-Electron environments (tests, browser builds) or if the IPC channel is unavailable, the install flow now silently fails rather than opening the tab. Consider restoring the fallback:

```suggestion
      try {
        await trpcClient.os.openExternal.mutate({ url: installUrl });
      } catch {
        window.open(installUrl, "_blank", "noopener,noreferrer");
      }
```

### Issue 2 of 2
apps/code/src/renderer/sagas/task/task-creation.test.ts:466-502
**Missing `prAuthorshipMode` assertion**

The two adjacent tests (user-integration path) both verify `createTaskRunMock` received `prAuthorshipMode: "user"`. For the team-integration path `hasUserGitHubIntegration` is `false`, so the saga should use `prAuthorshipMode: "bot"`. The new test doesn't assert this, leaving the authorship-mode branch for the team fallback untested.

```suggestion
    expect(result.success).toBe(true);
    expect(createTaskMock).toHaveBeenCalledWith(
      expect.objectContaining({
        repository: "posthog/posthog",
        github_integration: 42,
        github_user_integration: undefined,
      }),
    );
    expect(createTaskRunMock).toHaveBeenCalledWith(
      "task-123",
      expect.objectContaining({
        prAuthorshipMode: "bot",
        runSource: "manual",
      }),
    );
```

Reviews (1): Last reviewed commit: "chore(code): notify users when cloud pic..." | Re-trigger Greptile

);
return;
}
await trpcClient.os.openExternal.mutate({ url: installUrl });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 window.open fallback removed

The original openUrlInBrowser helper silently fell back to window.open when trpcClient.os.openExternal.mutate threw. The new code lets the throw propagate to the outer catch, so the user sees an error toast instead of the URL opening. In non-Electron environments (tests, browser builds) or if the IPC channel is unavailable, the install flow now silently fails rather than opening the tab. Consider restoring the fallback:

Suggested change
await trpcClient.os.openExternal.mutate({ url: installUrl });
try {
await trpcClient.os.openExternal.mutate({ url: installUrl });
} catch {
window.open(installUrl, "_blank", "noopener,noreferrer");
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/renderer/hooks/useConnectUserGithub.ts
Line: 64

Comment:
**`window.open` fallback removed**

The original `openUrlInBrowser` helper silently fell back to `window.open` when `trpcClient.os.openExternal.mutate` threw. The new code lets the throw propagate to the outer `catch`, so the user sees an error toast instead of the URL opening. In non-Electron environments (tests, browser builds) or if the IPC channel is unavailable, the install flow now silently fails rather than opening the tab. Consider restoring the fallback:

```suggestion
      try {
        await trpcClient.os.openExternal.mutate({ url: installUrl });
      } catch {
        window.open(installUrl, "_blank", "noopener,noreferrer");
      }
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mmm maybe we don;t need this

Comment on lines +466 to 502
it("forwards the team GitHub integration when no user integration is selected", async () => {
const createdTask = createTask({ github_user_integration: null });
const startedTask = createTask({ latest_run: createRun() });
const createTaskMock = vi.fn().mockResolvedValue(createdTask);
const createTaskRunMock = vi.fn().mockResolvedValue(createRun());
const startTaskRunMock = vi.fn().mockResolvedValue(startedTask);

const saga = new TaskCreationSaga({
posthogClient: {
createTask: createTaskMock,
deleteTask: vi.fn(),
getTask: vi.fn(),
createTaskRun: createTaskRunMock,
startTaskRun: startTaskRunMock,
sendRunCommand: vi.fn(),
updateTask: vi.fn(),
} as never,
});

const result = await saga.run({
content: "Ship the fix",
repository: "posthog/posthog",
workspaceMode: "cloud",
branch: "main",
githubIntegrationId: 42,
});

expect(result.success).toBe(true);
expect(createTaskMock).toHaveBeenCalledWith(
expect.objectContaining({
repository: "posthog/posthog",
github_integration: 42,
github_user_integration: undefined,
}),
);
});
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Missing prAuthorshipMode assertion

The two adjacent tests (user-integration path) both verify createTaskRunMock received prAuthorshipMode: "user". For the team-integration path hasUserGitHubIntegration is false, so the saga should use prAuthorshipMode: "bot". The new test doesn't assert this, leaving the authorship-mode branch for the team fallback untested.

Suggested change
it("forwards the team GitHub integration when no user integration is selected", async () => {
const createdTask = createTask({ github_user_integration: null });
const startedTask = createTask({ latest_run: createRun() });
const createTaskMock = vi.fn().mockResolvedValue(createdTask);
const createTaskRunMock = vi.fn().mockResolvedValue(createRun());
const startTaskRunMock = vi.fn().mockResolvedValue(startedTask);
const saga = new TaskCreationSaga({
posthogClient: {
createTask: createTaskMock,
deleteTask: vi.fn(),
getTask: vi.fn(),
createTaskRun: createTaskRunMock,
startTaskRun: startTaskRunMock,
sendRunCommand: vi.fn(),
updateTask: vi.fn(),
} as never,
});
const result = await saga.run({
content: "Ship the fix",
repository: "posthog/posthog",
workspaceMode: "cloud",
branch: "main",
githubIntegrationId: 42,
});
expect(result.success).toBe(true);
expect(createTaskMock).toHaveBeenCalledWith(
expect.objectContaining({
repository: "posthog/posthog",
github_integration: 42,
github_user_integration: undefined,
}),
);
});
});
expect(result.success).toBe(true);
expect(createTaskMock).toHaveBeenCalledWith(
expect.objectContaining({
repository: "posthog/posthog",
github_integration: 42,
github_user_integration: undefined,
}),
);
expect(createTaskRunMock).toHaveBeenCalledWith(
"task-123",
expect.objectContaining({
prAuthorshipMode: "bot",
runSource: "manual",
}),
);
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/renderer/sagas/task/task-creation.test.ts
Line: 466-502

Comment:
**Missing `prAuthorshipMode` assertion**

The two adjacent tests (user-integration path) both verify `createTaskRunMock` received `prAuthorshipMode: "user"`. For the team-integration path `hasUserGitHubIntegration` is `false`, so the saga should use `prAuthorshipMode: "bot"`. The new test doesn't assert this, leaving the authorship-mode branch for the team fallback untested.

```suggestion
    expect(result.success).toBe(true);
    expect(createTaskMock).toHaveBeenCalledWith(
      expect.objectContaining({
        repository: "posthog/posthog",
        github_integration: 42,
        github_user_integration: undefined,
      }),
    );
    expect(createTaskRunMock).toHaveBeenCalledWith(
      "task-123",
      expect.objectContaining({
        prAuthorshipMode: "bot",
        runSource: "manual",
      }),
    );
```

How can I resolve this? If you propose a fix, please make it concise.

@VojtechBartos
Copy link
Copy Markdown
Member Author

As we discussed over slack, user gh integration is the future way to go, so closing in favour of this one #2027

@VojtechBartos VojtechBartos deleted the posthog-code/fix-cloud-repo-picker-fallback branch May 5, 2026 11:52
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.

2 participants