Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/actions/cron/drip-emails/build-owner-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ export const buildOwnerContext = (data: BatchQueryResults): OwnerLookups => {
const coverageRepoCountByOwner: Record<number, number> = {};
const repoMostNeedingCoverageByOwner: Record<number, string | null> = {};
const repoMostNeedingCoveragePctByOwner: Record<number, number | null> = {};
const repoMostNeedingCoverageLinesByOwner: Record<number, number | null> = {};
for (const [ownerIdStr, repos] of Object.entries(latestRepoCov)) {
const ownerId = Number(ownerIdStr);
coverageRepoCountByOwner[ownerId] = Object.keys(repos).length;
Expand All @@ -135,6 +136,7 @@ export const buildOwnerContext = (data: BatchQueryResults): OwnerLookups => {
repoMostNeedingCoveragePctByOwner[ownerId] = Math.round(
(r.lines_covered / r.lines_total) * 100,
);
repoMostNeedingCoverageLinesByOwner[ownerId] = r.lines_total;
}
}

Expand Down Expand Up @@ -188,6 +190,7 @@ export const buildOwnerContext = (data: BatchQueryResults): OwnerLookups => {
unscheduledRepoNames: ownerUnscheduledRepoNames[ownerId] || [],
repoMostNeedingCoverage: repoMostNeedingCoverageByOwner[ownerId] ?? null,
repoMostNeedingCoveragePct: repoMostNeedingCoveragePctByOwner[ownerId] ?? null,
repoMostNeedingCoverageLines: repoMostNeedingCoverageLinesByOwner[ownerId] ?? null,
coverageBenchmark: (() => {
const repo = repoMostNeedingCoverageByOwner[ownerId];
const ownerRepos = latestRepoCov[ownerId];
Expand Down
10 changes: 7 additions & 3 deletions app/actions/resend/templates/drip/drip-templates.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const makeCtx = (overrides: Partial<OwnerContext> = {}): OwnerContext => ({
unscheduledRepoNames: ["api", "web"],
repoMostNeedingCoverage: null,
repoMostNeedingCoveragePct: null,
repoMostNeedingCoverageLines: null,
coverageBenchmark: null,
hasSetupPr: false,
hasSetupPrMerged: false,
Expand Down Expand Up @@ -67,14 +68,15 @@ describe("drip email templates", () => {
ownerCoveragePct: 42.7,
coverageRepoCount: 1,
repoMostNeedingCoverage: "backend",
repoMostNeedingCoverageLines: 8200,
coverageBenchmark: { linesTotal: 5303, coveragePct: 89 },
});
const text = generateCoverageChartsEmail("acme", "Alice", ctx);
expect(text).toContain("Hi Alice");
expect(text).toContain("43%");
expect(text).toContain("acme/backend");
expect(text).toContain("acme/backend (~8K lines)");
expect(text).not.toContain("across");
expect(text).toContain("5K-line project on GitAuto has 89% coverage");
expect(text).toContain("5K-line project on GitAuto reached 89% coverage");
expect(text).toContain("/dashboard/charts");
expect(text).toContain("Wes");
});
Expand All @@ -85,12 +87,13 @@ describe("drip email templates", () => {
ownerCoveragePct: 72,
coverageRepoCount: 5,
repoMostNeedingCoverage: "backend",
repoMostNeedingCoverageLines: 12000,
});
const text = generateCoverageChartsEmail("acme", "Alice", ctx);
expect(text).toContain("Hi Alice");
expect(text).toContain("72%");
expect(text).toContain("across 5 repos");
expect(text).toContain("acme/backend");
expect(text).toContain("acme/backend (~12K lines)");
expect(text).toContain("/dashboard/charts");
expect(text).toContain("Wes");
});
Expand Down Expand Up @@ -220,6 +223,7 @@ describe("drip email templates", () => {
ownerCoveragePct: 99.9,
coverageRepoCount: 99,
repoMostNeedingCoverage: "long-repo-name",
repoMostNeedingCoverageLines: 999000,
});
const text = generateCoverageChartsEmail("long-org-name", "Maximilian", ctx);
expect(text.length).toBeLessThanOrEqual(CHAR_LIMIT);
Expand Down
20 changes: 12 additions & 8 deletions app/actions/resend/templates/drip/onboarding/02-coverage-charts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { formatLines } from "@/utils/format-lines";
* Single repo (with benchmark):
* Subject: Your test coverage is 15%
* Body:
* Hi Alice - your test coverage is 15% for acme/backend. A 5K-line project on GitAuto has 89% coverage. See the chart:
* Hi Alice - I just measured your test coverage at 15% for acme/backend (~8K lines). For reference, a 5K-line project on GitAuto reached 89% coverage. See the chart:
*
* https://gitauto.ai/dashboard/charts
*
Expand All @@ -17,7 +17,7 @@ import { formatLines } from "@/utils/format-lines";
* Multi-repo (no benchmark):
* Subject: Your test coverage across 3 repos is 72%
* Body:
* Hi Alice - your weighted test coverage is 72% across 3 repos like acme/backend. See the chart:
* Hi Alice - I just measured your weighted test coverage at 72% across 3 repos like acme/backend (~8K lines). See the chart:
*
* https://gitauto.ai/dashboard/charts
*
Expand All @@ -37,17 +37,21 @@ export const generateCoverageChartsEmail = (
) => {
const pct = Math.round(ctx.ownerCoveragePct!);
const multi = ctx.coverageRepoCount > 1;
const repo = ctx.repoMostNeedingCoverage ? `${ownerName}/${ctx.repoMostNeedingCoverage}` : "";
const repoName = ctx.repoMostNeedingCoverage ? `${ownerName}/${ctx.repoMostNeedingCoverage}` : "";
const repoWithLines =
repoName && ctx.repoMostNeedingCoverageLines
? `${repoName} (~${formatLines(ctx.repoMostNeedingCoverageLines)} lines)`
: repoName;
const repoDetail = multi
? ` across ${ctx.coverageRepoCount} repos${repo ? ` like ${repo}` : ""}`
: repo
? ` for ${repo}`
? ` across ${ctx.coverageRepoCount} repos${repoWithLines ? ` like ${repoWithLines}` : ""}`
: repoWithLines
? ` for ${repoWithLines}`
: "";
const benchmarkLine = ctx.coverageBenchmark
? ` A ${formatLines(ctx.coverageBenchmark.linesTotal)}-line project on GitAuto has ${ctx.coverageBenchmark.coveragePct}% coverage.`
? ` For reference, a ${formatLines(ctx.coverageBenchmark.linesTotal)}-line project on GitAuto reached ${ctx.coverageBenchmark.coveragePct}% coverage.`
: "";

return `Hi ${firstName} - your ${multi ? "weighted " : ""}test coverage is ${pct}%${repoDetail}.${benchmarkLine} See the chart:
return `Hi ${firstName} - your ${multi ? "weighted " : ""}test coverage just came in at ${pct}%${repoDetail}.${benchmarkLine} See the chart:

${ABSOLUTE_URLS.GITAUTO.DASHBOARD.CHARTS}

Expand Down
2 changes: 1 addition & 1 deletion app/blog/posts/2024-11-24-what-are-dora-metrics.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const metadata = {

# What are DORA Metrics?

[DORA (DevOps Research and Assessment) metrics](https://dora.dev/guides/dora-metrics-four-keys/) are a key benchmark for measuring software delivery performance. These metrics help teams assess their capabilities and drive improvements.
[DORA (DevOps Research and Assessment) metrics](https://dora.dev/guides/dora-metrics/) are a key benchmark for measuring software delivery performance. These metrics help teams assess their capabilities and drive improvements.

## The Four Key Metrics

Expand Down
1 change: 1 addition & 0 deletions types/drip-emails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface OwnerContext {
unscheduledRepoNames: string[];
repoMostNeedingCoverage: string | null;
repoMostNeedingCoveragePct: number | null;
repoMostNeedingCoverageLines: number | null;
/** Anonymized similar-sized repo from another owner with higher coverage (>= 80%) */
coverageBenchmark: { linesTotal: number; coveragePct: number } | null;
hasSetupPr: boolean;
Expand Down
Loading