-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
feat(webapp) backend changes and backfill for dev branches #4010
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| "@trigger.dev/core": patch | ||
| "trigger.dev": patch | ||
| --- | ||
|
|
||
| Centralize the `"default"` dev-branch sentinel behind a shared `DEFAULT_DEV_BRANCH` constant and `isDefaultDevBranch()` helper in `@trigger.dev/core/v3/utils/gitBranch`, replacing the hardcoded string literals duplicated across the CLI and server. No behavior change — `trigger dev` still targets the root development environment when no branch is specified. |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,11 +1,15 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { GitMeta } from "@trigger.dev/core/v3"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { GitMeta, } from "@trigger.dev/core/v3"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { DEFAULT_DEV_BRANCH } from "@trigger.dev/core/v3/utils/gitBranch"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { type RuntimeEnvironmentType } from "@trigger.dev/database"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { type z } from "zod"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { type Prisma, type PrismaClient, prisma } from "~/db.server"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { type Project } from "~/models/project.server"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { type User } from "~/models/user.server"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { type BranchesOptions } from "~/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.branches/route"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { getCurrentPlan, getPlans } from "~/services/platform.v3.server"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { checkBranchLimit } from "~/services/upsertBranch.server"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { devPresence } from "./DevPresence.server"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { sortEnvironments } from "~/utils/environmentSort"; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| type Result = Awaited<ReturnType<BranchesPresenter["call"]>>; | ||||||||||||||||||||||||||||||||||||||||||||||||
| export type Branch = Result["branches"][number]; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -58,12 +62,14 @@ export class BranchesPresenter { | |||||||||||||||||||||||||||||||||||||||||||||||
| public async call({ | ||||||||||||||||||||||||||||||||||||||||||||||||
| userId, | ||||||||||||||||||||||||||||||||||||||||||||||||
| projectSlug, | ||||||||||||||||||||||||||||||||||||||||||||||||
| env, | ||||||||||||||||||||||||||||||||||||||||||||||||
| showArchived = false, | ||||||||||||||||||||||||||||||||||||||||||||||||
| search, | ||||||||||||||||||||||||||||||||||||||||||||||||
| page = 1, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }: { | ||||||||||||||||||||||||||||||||||||||||||||||||
| userId: User["id"]; | ||||||||||||||||||||||||||||||||||||||||||||||||
| projectSlug: Project["slug"]; | ||||||||||||||||||||||||||||||||||||||||||||||||
| env: "preview" | "development"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } & Options) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| const project = await this.#prismaClient.project.findFirst({ | ||||||||||||||||||||||||||||||||||||||||||||||||
| select: { | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -86,12 +92,16 @@ export class BranchesPresenter { | |||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error("Project not found"); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // TODO audit mishmash of preview/developement preview/dev stg/dev PREVIEW/DEVELOPMENT | ||||||||||||||||||||||||||||||||||||||||||||||||
| const envType = env === "preview" ? "PREVIEW" : "DEVELOPMENT"; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const branchableEnvironment = await this.#prismaClient.runtimeEnvironment.findFirst({ | ||||||||||||||||||||||||||||||||||||||||||||||||
| select: { | ||||||||||||||||||||||||||||||||||||||||||||||||
| id: true, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| where: { | ||||||||||||||||||||||||||||||||||||||||||||||||
| projectId: project.id, | ||||||||||||||||||||||||||||||||||||||||||||||||
| type: envType, | ||||||||||||||||||||||||||||||||||||||||||||||||
| isBranchableEnvironment: true, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -119,23 +129,30 @@ export class BranchesPresenter { | |||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // The default DEV branch has no branchName (it's the root dev env, stored | ||||||||||||||||||||||||||||||||||||||||||||||||
| // with branchName: null), so searching for it by name wouldn't display it. | ||||||||||||||||||||||||||||||||||||||||||||||||
| // Hacky way around that: always include the null-branchName root env. | ||||||||||||||||||||||||||||||||||||||||||||||||
| const branchNameWhere = envType === "DEVELOPMENT" ? | ||||||||||||||||||||||||||||||||||||||||||||||||
| search | ||||||||||||||||||||||||||||||||||||||||||||||||
| ? { OR: [{ contains: search, mode: "insensitive" as const }, { is: null }] } | ||||||||||||||||||||||||||||||||||||||||||||||||
| : {} : | ||||||||||||||||||||||||||||||||||||||||||||||||
| search | ||||||||||||||||||||||||||||||||||||||||||||||||
| ? { contains: search, mode: "insensitive" as const } | ||||||||||||||||||||||||||||||||||||||||||||||||
| : { not: null }; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+132
to
+141
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n apps/webapp/app/presenters/v3/BranchesPresenter.server.ts | sed -n '130,190p'Repository: triggerdotdev/trigger.dev Length of output: 2676 🏁 Script executed: find . -name "*.prisma" -type f | head -20Repository: triggerdotdev/trigger.dev Length of output: 119 🏁 Script executed: grep -A 50 "model RuntimeEnvironment" ./internal-packages/database/prisma/schema.prisma | head -80Repository: triggerdotdev/trigger.dev Length of output: 2821 🏁 Script executed: head -50 apps/webapp/app/presenters/v3/BranchesPresenter.server.tsRepository: triggerdotdev/trigger.dev Length of output: 1999 🏁 Script executed: rg "Prisma.*WhereInput" apps/webapp/app/presenters/v3/BranchesPresenter.server.ts -A 3 -B 3Repository: triggerdotdev/trigger.dev Length of output: 51 🏁 Script executed: cat -n apps/webapp/app/presenters/v3/BranchesPresenter.server.ts | sed -n '1,30p'Repository: triggerdotdev/trigger.dev Length of output: 1585 🏁 Script executed: web_search
Prisma scalar nullable field OR filter syntax StringNullableFilterRepository: triggerdotdev/trigger.dev Length of output: 165 🌐 Web query:
💡 Result: In Prisma, there is no specialized "StringNullableFilter OR" operator. Instead, you use the standard, composable OR operator at the level of your where clause, allowing you to combine any valid filter conditions, including those for nullable scalar fields [1][2][3]. To filter on a nullable string field within an OR condition, you simply place your conditions inside an array assigned to the OR key [1][4]. Example Syntax: const users = await prisma.user.findMany({ where: { OR: [ { name: { equals: "Alice" } }, { bio: { equals: null } }, // Targeting a StringNullableFilter { bio: { contains: "developer" } } ], }, }); Key Considerations: 1. Composition: The OR operator accepts an array of filter objects [1][3]. Each object in the array represents a condition, and at least one must be true for the record to be returned [3]. 2. Nullable Fields: When a field is nullable (StringNullableFilter), you can explicitly filter for null or use string operators like contains, startsWith, or endsWith, which are available on the StringNullableFilter type [5]. 3. Handling Undefined: Be cautious when building dynamic queries. If you pass undefined to a filter, Prisma ignores that specific filter [6]. If all elements of an OR array are omitted due to being undefined, it can lead to unexpected query behavior, such as generating an empty result or a 1=0 SQL clause [7][6]. 4. Nesting: The OR, AND, and NOT operators are fully nestable, allowing you to create complex boolean logic as needed [2][3]. For nullable fields, you can check for null values by setting the field to null directly or using the { equals: null } syntax [8]. Citations:
🏁 Script executed: cat -n apps/webapp/app/presenters/v3/BranchesPresenter.server.ts | sed -n '130,195p'Repository: triggerdotdev/trigger.dev Length of output: 2892 🏁 Script executed: cat -n apps/webapp/app/presenters/v3/BranchesPresenter.server.ts | sed -n '195,210p'Repository: triggerdotdev/trigger.dev Length of output: 619 🏁 Script executed: cat > /tmp/test_prisma_types.ts << 'EOF'
// Testing Prisma filter types
import { type Prisma } from "`@prisma/client`";
// What the current code is trying to do:
const invalidWhere: Prisma.RuntimeEnvironmentWhereInput = {
branchName: {
OR: [{ contains: "test", mode: "insensitive" as const }, { is: null }]
}
};
// What the correct approach should be:
const correctWhere: Prisma.RuntimeEnvironmentWhereInput = {
OR: [
{ branchName: { contains: "test", mode: "insensitive" } },
{ branchName: null }
]
};
// Or using spread approach from the suggested fix:
const correctWhereSpread: Prisma.RuntimeEnvironmentWhereInput = {
branchName: { contains: "test", mode: "insensitive" }
};
export { invalidWhere, correctWhere, correctWhereSpread };
EOF
cat /tmp/test_prisma_types.tsRepository: triggerdotdev/trigger.dev Length of output: 789 Fix Prisma filter composition for Lines 135-141 build an invalid filter structure. The 💡 Suggested fix- const branchNameWhere = envType === "DEVELOPMENT" ?
- search
- ? { OR: [{ contains: search, mode: "insensitive" as const }, { is: null }] }
- : {} :
- search
- ? { contains: search, mode: "insensitive" as const }
- : { not: null };
+ const whereForBranchSearch: Prisma.RuntimeEnvironmentWhereInput =
+ envType === "DEVELOPMENT"
+ ? search
+ ? {
+ OR: [
+ { branchName: { contains: search, mode: "insensitive" } },
+ { branchName: null },
+ ],
+ }
+ : {}
+ : search
+ ? { branchName: { contains: search, mode: "insensitive" } }
+ : { branchName: { not: null } };
@@
- branchName: branchNameWhere,
+ ...whereForBranchSearch,
@@
- branchName: branchNameWhere,
+ ...whereForBranchSearch,📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const orgMemberWhere = envType === "DEVELOPMENT" ? { orgMember: { userId } } : {}; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const visibleCount = await this.#prismaClient.runtimeEnvironment.count({ | ||||||||||||||||||||||||||||||||||||||||||||||||
| where: { | ||||||||||||||||||||||||||||||||||||||||||||||||
| projectId: project.id, | ||||||||||||||||||||||||||||||||||||||||||||||||
| branchName: search | ||||||||||||||||||||||||||||||||||||||||||||||||
| ? { | ||||||||||||||||||||||||||||||||||||||||||||||||
| contains: search, | ||||||||||||||||||||||||||||||||||||||||||||||||
| mode: "insensitive", | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| : { | ||||||||||||||||||||||||||||||||||||||||||||||||
| not: null, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| type: envType, | ||||||||||||||||||||||||||||||||||||||||||||||||
| branchName: branchNameWhere, | ||||||||||||||||||||||||||||||||||||||||||||||||
| ...orgMemberWhere, | ||||||||||||||||||||||||||||||||||||||||||||||||
| ...(showArchived ? {} : { archivedAt: null }), | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // Limits | ||||||||||||||||||||||||||||||||||||||||||||||||
| const limits = await checkBranchLimit(this.#prismaClient, project.organizationId, project.id); | ||||||||||||||||||||||||||||||||||||||||||||||||
| const limits = await checkBranchLimit({ prisma: this.#prismaClient, organizationId: project.organizationId, projectId: project.id, userId, env }); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const [currentPlan, plans] = await Promise.all([ | ||||||||||||||||||||||||||||||||||||||||||||||||
| getCurrentPlan(project.organizationId), | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -161,14 +178,9 @@ export class BranchesPresenter { | |||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| where: { | ||||||||||||||||||||||||||||||||||||||||||||||||
| projectId: project.id, | ||||||||||||||||||||||||||||||||||||||||||||||||
| branchName: search | ||||||||||||||||||||||||||||||||||||||||||||||||
| ? { | ||||||||||||||||||||||||||||||||||||||||||||||||
| contains: search, | ||||||||||||||||||||||||||||||||||||||||||||||||
| mode: "insensitive", | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| : { | ||||||||||||||||||||||||||||||||||||||||||||||||
| not: null, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| type: envType, | ||||||||||||||||||||||||||||||||||||||||||||||||
| branchName: branchNameWhere, | ||||||||||||||||||||||||||||||||||||||||||||||||
| ...orgMemberWhere, | ||||||||||||||||||||||||||||||||||||||||||||||||
| ...(showArchived ? {} : { archivedAt: null }), | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| orderBy: { | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -178,35 +190,34 @@ export class BranchesPresenter { | |||||||||||||||||||||||||||||||||||||||||||||||
| take: BRANCHES_PER_PAGE, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const totalBranchesWhere = envType === "DEVELOPMENT" ? {} : { not: null }; | ||||||||||||||||||||||||||||||||||||||||||||||||
| const totalBranches = await this.#prismaClient.runtimeEnvironment.count({ | ||||||||||||||||||||||||||||||||||||||||||||||||
| where: { | ||||||||||||||||||||||||||||||||||||||||||||||||
| projectId: project.id, | ||||||||||||||||||||||||||||||||||||||||||||||||
| branchName: { | ||||||||||||||||||||||||||||||||||||||||||||||||
| not: null, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| type: envType, | ||||||||||||||||||||||||||||||||||||||||||||||||
| branchName: totalBranchesWhere, | ||||||||||||||||||||||||||||||||||||||||||||||||
| ...orgMemberWhere, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const branchesFiltered = branches | ||||||||||||||||||||||||||||||||||||||||||||||||
| .filter((branch) => envType === "DEVELOPMENT" || branch.branchName !== null) | ||||||||||||||||||||||||||||||||||||||||||||||||
| .map((branch) => ({ | ||||||||||||||||||||||||||||||||||||||||||||||||
| ...branch, | ||||||||||||||||||||||||||||||||||||||||||||||||
| git: processGitMetadata(branch.git), | ||||||||||||||||||||||||||||||||||||||||||||||||
| branchName: branch.branchName ?? DEFAULT_DEV_BRANCH, | ||||||||||||||||||||||||||||||||||||||||||||||||
| })); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const branchesWithActivity = await hydrateEnvsWithActivity(userId, project.id, branchesFiltered); | ||||||||||||||||||||||||||||||||||||||||||||||||
| const branchesSorted = sortEnvironments(branchesWithActivity); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||
| branchableEnvironment, | ||||||||||||||||||||||||||||||||||||||||||||||||
| currentPage: page, | ||||||||||||||||||||||||||||||||||||||||||||||||
| totalPages: Math.ceil(visibleCount / BRANCHES_PER_PAGE), | ||||||||||||||||||||||||||||||||||||||||||||||||
| hasBranches: totalBranches > 0, | ||||||||||||||||||||||||||||||||||||||||||||||||
| branches: branches.flatMap((branch) => { | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (branch.branchName === null) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| return []; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const git = processGitMetadata(branch.git); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| return [ | ||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||
| ...branch, | ||||||||||||||||||||||||||||||||||||||||||||||||
| branchName: branch.branchName, | ||||||||||||||||||||||||||||||||||||||||||||||||
| git, | ||||||||||||||||||||||||||||||||||||||||||||||||
| } as const, | ||||||||||||||||||||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||||||||||||||||||||
| branches: branchesSorted, | ||||||||||||||||||||||||||||||||||||||||||||||||
| hasFilters, | ||||||||||||||||||||||||||||||||||||||||||||||||
| limits, | ||||||||||||||||||||||||||||||||||||||||||||||||
| canPurchaseBranches, | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -218,6 +229,23 @@ export class BranchesPresenter { | |||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| export async function hydrateEnvsWithActivity<T extends { type: RuntimeEnvironmentType; id: string }> | ||||||||||||||||||||||||||||||||||||||||||||||||
| (userId: string, projectId: string, environments: T[]): Promise<Array<T & { lastActivity: Date | undefined; isConnected: boolean | undefined }>> { | ||||||||||||||||||||||||||||||||||||||||||||||||
| const recentDevBranchIds = await devPresence.getRecentBranchIds(userId, projectId); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| return Promise.all(environments.map(async (env) => { | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (env.type !== "DEVELOPMENT") { | ||||||||||||||||||||||||||||||||||||||||||||||||
| return { ...env, lastActivity: undefined, isConnected: undefined }; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const devHit = recentDevBranchIds.get(env.id); | ||||||||||||||||||||||||||||||||||||||||||||||||
| const lastActivity = devHit === undefined ? undefined : devHit; | ||||||||||||||||||||||||||||||||||||||||||||||||
| // TODO change dev-presence to a different data structure to avoid N calls? | ||||||||||||||||||||||||||||||||||||||||||||||||
| const isConnected = devHit === undefined ? undefined : await devPresence.isConnected(env.id); | ||||||||||||||||||||||||||||||||||||||||||||||||
| return { ...env, lastActivity, isConnected }; | ||||||||||||||||||||||||||||||||||||||||||||||||
| })); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| export function processGitMetadata(data: Prisma.JsonValue): GitMetaLinks | null { | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (!data) return null; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the duplicate
getRecentBranchIdsread.Line 107 performs a Redis read that is never used, and Line 112 immediately calls
hydrateEnvsWithActivity()which already performs the same read internally. This adds unnecessary network I/O on every request.💡 Suggested fix
Also applies to: 107-113