Skip to content
Draft
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
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,13 @@
"tinyexec": "catalog:runtime"
},
"devDependencies": {
"@effect/platform-node": "catalog:effect",
"@effect/vitest": "catalog:effect",
"@luxass/msw-utils": "catalog:dev",
"@types/node": "catalog:types",
"@types/prompts": "catalog:types",
"@types/semver": "catalog:types",
"effect": "catalog:effect",
"eta": "catalog:dev",
"msw": "catalog:dev",
"oxfmt": "catalog:dev",
Expand All @@ -58,7 +61,7 @@
"vitest": "catalog:dev",
"vitest-testdirs": "catalog:dev"
},
"packageManager": "pnpm@10.33.0",
"packageManager": "pnpm@11.0.9",
"inlinedDependencies": {
"eta": "4.5.1"
}
Expand Down
1,396 changes: 762 additions & 634 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ overrides:
undici-types: 6.24.0

catalogs:
effect:
effect: 4.0.0-beta.60
"@effect/platform-node": 4.0.0-beta.60
"@effect/vitest": 4.0.0-beta.60

dev:
"@luxass/msw-utils": 0.6.2
eta: 4.5.1
Expand Down
133 changes: 74 additions & 59 deletions src/versioning/commits.ts → src/commits.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { getGroupedFilesByCommitSha, getMostRecentPackageTag } from "#core/git";
import type { WorkspacePackage } from "#core/workspace";
import { logger } from "#shared/utils";
import { GitService } from "./services/git";
import type { WorkspacePackage } from "./services/workspace";
import { logger } from "./errors";
import type { GitCommit } from "commit-parser";
import { getCommits } from "commit-parser";
import { Effect } from "effect";
import farver from "farver";

/**
Expand All @@ -13,65 +14,76 @@ import farver from "farver";
* @param {WorkspacePackage[]} packages - Array of workspace packages to analyze
* @returns {Promise<Map<string, GitCommit[]>>} A map of package names to their commits since their last release
*/
export async function getWorkspacePackageGroupedCommits(
workspaceRoot: string,
packages: WorkspacePackage[],
): Promise<Map<string, GitCommit[]>> {
const changedPackages = new Map<string, GitCommit[]>();

const promises = packages.map(async (pkg) => {
// Get the latest tag that corresponds to the workspace package
// This will ensure that we only get commits, since the last release of this package.
const lastTagResult = await getMostRecentPackageTag(workspaceRoot, pkg.name);
const lastTag = lastTagResult.ok ? lastTagResult.value : undefined;

// Get all commits since the last tag, that affect this package
const allCommits = await getCommits({
from: lastTag,
to: "HEAD",
cwd: workspaceRoot,
folder: pkg.path,
export const getWorkspacePackageGroupedCommits = Effect.fn(
"getWorkspacePackageGroupedCommits",
)(function* (workspaceRoot: string, packages: WorkspacePackage[]) {
const git = yield* GitService;
const changedPackages = new Map<string, GitCommit[]>();

const loadPackageCommits = Effect.fn("loadPackageCommits")(function* (
pkg: WorkspacePackage,
fromTag?: string,
) {
const allCommits = yield* Effect.tryPromise(() =>
getCommits({
from: fromTag,
to: "HEAD",
cwd: workspaceRoot,
folder: pkg.path,
}),
);

logger.verbose(
`Found ${farver.cyan(allCommits.length)} commits for package ${farver.bold(pkg.name)} since ${farver.cyan(fromTag ?? "start")}`,
);

return allCommits;
});

logger.verbose(
`Found ${farver.cyan(allCommits.length)} commits for package ${farver.bold(
pkg.name,
)} since tag ${farver.cyan(lastTag ?? "N/A")}`,
const results = yield* Effect.all(
packages.map((pkg) =>
Effect.fn("getPackageCommitGroup")(function* () {
const lastTagExit = yield* Effect.exit(git.getMostRecentPackageTag(workspaceRoot, pkg.name));
const lastTag = lastTagExit._tag === "Success" ? lastTagExit.value : undefined;
const allCommits = yield* loadPackageCommits(pkg, lastTag);

return {
pkgName: pkg.name,
commits: allCommits,
};
})(),
),
);

return {
pkgName: pkg.name,
commits: allCommits,
};
});

const results = await Promise.all(promises);
for (const { pkgName, commits } of results) {
changedPackages.set(pkgName, commits);
}

for (const { pkgName, commits } of results) {
changedPackages.set(pkgName, commits);
}
return changedPackages;
});

return changedPackages;
}

export async function getPackageCommitsSinceTag(
export const getPackageCommitsSinceTag = Effect.fn("getPackageCommitsSinceTag")(function* (
workspaceRoot: string,
pkg: WorkspacePackage,
fromTag?: string,
): Promise<GitCommit[]> {
const allCommits = await getCommits({
from: fromTag,
to: "HEAD",
cwd: workspaceRoot,
folder: pkg.path,
});
) {
const allCommits = yield* Effect.tryPromise(() =>
getCommits({
from: fromTag,
to: "HEAD",
cwd: workspaceRoot,
folder: pkg.path,
}),
);

logger.verbose(
`Found ${farver.cyan(allCommits.length)} commits for package ${farver.bold(pkg.name)} since ${farver.cyan(fromTag ?? "start")}`,
);
logger.verbose(
`Found ${farver.cyan(allCommits.length)} commits for package ${farver.bold(pkg.name)} since ${farver.cyan(fromTag ?? "start")}`,
);

return allCommits;
});

return allCommits;
}

/**
* Check if a file path touches any package folder.
Expand Down Expand Up @@ -208,12 +220,12 @@ export function filterGlobalCommits(
* @param mode - Filter mode: false (disabled), "all" (all global commits), or "dependencies" (only dependency-related)
* @returns Map of package name to their global commits
*/
export async function getGlobalCommitsPerPackage(
export const getGlobalCommitsPerPackage = Effect.fn("getGlobalCommitsPerPackage")(function* (
workspaceRoot: string,
packageCommits: Map<string, GitCommit[]>,
allPackages: WorkspacePackage[],
mode?: false | "dependencies" | "all",
): Promise<Map<string, GitCommit[]>> {
) {
const result = new Map<string, GitCommit[]>();

if (!mode) {
Expand All @@ -234,19 +246,22 @@ export async function getGlobalCommitsPerPackage(
`${farver.cyan(commitRange.oldest)}..${farver.cyan(commitRange.newest)}`,
);

const commitFilesMap = await getGroupedFilesByCommitSha(
const git = yield* GitService;
const commitFilesMap = yield* git.getGroupedFilesByCommitSha(
workspaceRoot,
commitRange.oldest,
commitRange.newest,
);
if (!commitFilesMap.ok) {
logger.warn("Failed to get commit file list, returning empty global commits");
).pipe(Effect.catch(() => {
logger.warn("Failed to get commit file list, returning empty global commits");
return Effect.succeed(null);
}));
if (commitFilesMap === null) {
return result;
}

logger.verbose(
"Got file lists for commits",
`${farver.cyan(commitFilesMap.value.size)} commits in ONE git call`,
`${farver.cyan(commitFilesMap.size)} commits in ONE git call`,
);

const packagePaths = new Set(allPackages.map((p) => p.path));
Expand All @@ -259,7 +274,7 @@ export async function getGlobalCommitsPerPackage(

const filtered = filterGlobalCommits(
commits,
commitFilesMap.value,
commitFilesMap,
packagePaths,
workspaceRoot,
mode,
Expand All @@ -273,4 +288,4 @@ export async function getGlobalCommitsPerPackage(
}

return result;
}
});
Loading