@storm-software/git-tools 2.131.17 → 2.131.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/git.js CHANGED
@@ -49,15 +49,14 @@ import { defaultCreateReleaseProvider, GithubRemoteReleaseClient } from 'nx/src/
49
49
  import { parse } from 'yaml';
50
50
  import chalk from 'chalk';
51
51
  import { printAndFlushChanges as printAndFlushChanges$1 } from 'nx/src/command-line/release/utils/print-changes';
52
- import { createGitTagValues, handleDuplicateGitTags, createCommitMessageValues, isPrerelease, shouldPreferDockerVersionForReleaseGroup, ReleaseVersion, noDiffInChangelogMessage } from 'nx/src/command-line/release/utils/shared';
52
+ import { createGitTagValues, handleDuplicateGitTags, createCommitMessageValues, isPrerelease, shouldPreferDockerVersionForReleaseGroup, ReleaseVersion, noDiffInChangelogMessage, shouldSkipVersionActions } from 'nx/src/command-line/release/utils/shared';
53
53
  import { interpolate } from 'nx/src/tasks-runner/utils';
54
54
  import { execCommand } from 'nx/src/command-line/release/utils/exec-command.js';
55
- import { getCommitHash, getLatestGitTagForPattern, getFirstGitCommit, gitPush, gitAdd, getGitDiff, parseCommits } from 'nx/src/command-line/release/utils/git';
55
+ import { getCommitHash, getLatestGitTagForPattern, getFirstGitCommit, gitPush, gitAdd, getGitDiff, parseCommits, sanitizeProjectNameForGitTag } from 'nx/src/command-line/release/utils/git';
56
56
  import semver, { prerelease, major } from 'semver';
57
57
  import { ReleaseClient } from 'nx/release';
58
58
  import { readRawVersionPlans, setResolvedVersionPlansOnGroups } from 'nx/src/command-line/release/config/version-plans';
59
59
  import { printAndFlushChanges } from 'nx/src/command-line/release/utils/print-changes.js';
60
- import { createReleaseGraph } from 'nx/src/command-line/release/utils/release-graph';
61
60
  import { validateResolvedVersionPlansAgainstFilter } from 'nx/src/command-line/release/utils/version-plan-utils';
62
61
  import { FsTree } from 'nx/src/generators/tree';
63
62
  import { createFileMapUsingProjectGraph } from 'nx/src/project-graph/file-map-utils';
@@ -66,7 +65,16 @@ import DefaultChangelogRenderer from 'nx/release/changelog-renderer';
66
65
  import { DEFAULT_CONVENTIONAL_COMMITS_CONFIG } from 'nx/src/command-line/release/config/conventional-commits';
67
66
  import { readNxJson } from 'nx/src/config/nx-json';
68
67
  import { findMatchingProjects } from 'nx/src/utils/find-matching-projects';
69
- import { IMPLICIT_DEFAULT_RELEASE_GROUP } from 'nx/src/command-line/release/config/config.js';
68
+ import { IMPLICIT_DEFAULT_RELEASE_GROUP } from 'nx/src/command-line/release/config/config';
69
+ import { RepoGitTags } from 'nx/src/command-line/release/utils/repository-git-tags';
70
+ import { ProjectLogger } from 'nx/src/command-line/release/version/project-logger';
71
+ import { resolveCurrentVersion } from 'nx/src/command-line/release/version/resolve-current-version';
72
+ import { topologicalSort } from 'nx/src/command-line/release/version/topological-sort';
73
+ import { resolveVersionActionsForProject, NOOP_VERSION_ACTIONS as NOOP_VERSION_ACTIONS$1 } from 'nx/src/command-line/release/version/version-actions';
74
+ import { filterAffected } from 'nx/src/project-graph/affected/affected-project-graph';
75
+ import { calculateFileChanges } from 'nx/src/project-graph/file-utils';
76
+ import gte from 'semver/functions/gte';
77
+ import { IMPLICIT_DEFAULT_RELEASE_GROUP as IMPLICIT_DEFAULT_RELEASE_GROUP$1 } from 'nx/src/command-line/release/config/config.js';
70
78
  import { deriveSpecifierFromConventionalCommits } from 'nx/src/command-line/release/version/derive-specifier-from-conventional-commits';
71
79
  import { deriveSpecifierFromVersionPlan } from 'nx/src/command-line/release/version/deriver-specifier-from-version-plans';
72
80
  import { ReleaseGroupProcessor } from 'nx/src/command-line/release/version/release-group-processor';
@@ -3588,6 +3596,685 @@ function formatConfigLog(config5) {
3588
3596
  { sort: true, skip: ["workspaceConfig"] }
3589
3597
  );
3590
3598
  }
3599
+ var validReleaseVersionPrefixes = ["auto", "", "~", "^", "="];
3600
+ var ReleaseGraph = class _ReleaseGraph {
3601
+ constructor(releaseGroups, filters) {
3602
+ this.releaseGroups = releaseGroups;
3603
+ this.filters = filters;
3604
+ }
3605
+ projectToReleaseGroup = /* @__PURE__ */ new Map();
3606
+ projectToDependents = /* @__PURE__ */ new Map();
3607
+ projectToDependencies = /* @__PURE__ */ new Map();
3608
+ projectToUpdateDependentsSetting = /* @__PURE__ */ new Map();
3609
+ groupGraph = /* @__PURE__ */ new Map();
3610
+ sortedReleaseGroups = [];
3611
+ sortedProjects = /* @__PURE__ */ new Map();
3612
+ allProjectsConfiguredForNxRelease = /* @__PURE__ */ new Set();
3613
+ allProjectsToProcess = /* @__PURE__ */ new Set();
3614
+ finalConfigsByProject = /* @__PURE__ */ new Map();
3615
+ projectsToVersionActions = /* @__PURE__ */ new Map();
3616
+ uniqueAfterAllProjectsVersioned = /* @__PURE__ */ new Map();
3617
+ projectLoggers = /* @__PURE__ */ new Map();
3618
+ cachedCurrentVersions = /* @__PURE__ */ new Map();
3619
+ cachedLatestMatchingGitTag = /* @__PURE__ */ new Map();
3620
+ currentVersionsPerFixedReleaseGroup = /* @__PURE__ */ new Map();
3621
+ originalDependentProjectsPerProject = /* @__PURE__ */ new Map();
3622
+ releaseGroupToFilteredProjects = /* @__PURE__ */ new Map();
3623
+ originalFilteredProjects = /* @__PURE__ */ new Set();
3624
+ /**
3625
+ * Store the affected graph per commit per project
3626
+ * to avoid recomputation of the graph on workspace
3627
+ * with multiple projects
3628
+ */
3629
+ affectedGraphPerCommit = /* @__PURE__ */ new Map();
3630
+ repositoryGitTags = RepoGitTags.create();
3631
+ /**
3632
+ * User-friendly log describing what the filter matched.
3633
+ * Null if no filters were applied.
3634
+ */
3635
+ filterLog = null;
3636
+ /**
3637
+ * Initialize the graph by building all relationships and caches
3638
+ * @internal - Called by createReleaseGraph(), not meant for external use
3639
+ */
3640
+ async init(options) {
3641
+ this.setupProjectReleaseGroupMapping();
3642
+ this.applyInitialFiltering();
3643
+ await this.setupProjectsToProcess(options);
3644
+ await this.precomputeDependencyRelationships(
3645
+ options.tree,
3646
+ options.projectGraph
3647
+ );
3648
+ this.applyDependencyAwareFiltering();
3649
+ this.buildGroupGraphStructure();
3650
+ if (!options.skipVersionResolution) {
3651
+ await this.resolveCurrentVersionsForProjects(
3652
+ options.tree,
3653
+ options.projectGraph,
3654
+ options.preid ?? ""
3655
+ );
3656
+ }
3657
+ this.buildGroupDependencyGraph();
3658
+ this.sortedReleaseGroups = this.topologicallySortReleaseGroups();
3659
+ for (const group of this.releaseGroups) {
3660
+ this.sortedProjects.set(
3661
+ group.name,
3662
+ this.topologicallySortProjects(group)
3663
+ );
3664
+ }
3665
+ await this.populateDependentProjectsData(
3666
+ options.tree,
3667
+ options.projectGraph
3668
+ );
3669
+ }
3670
+ /**
3671
+ * Setup mapping from project to release group and cache updateDependents settings
3672
+ */
3673
+ setupProjectReleaseGroupMapping() {
3674
+ for (const group of this.releaseGroups) {
3675
+ for (const project of group.projects) {
3676
+ this.projectToReleaseGroup.set(project, group);
3677
+ const updateDependents = group.version?.updateDependents || "always";
3678
+ this.projectToUpdateDependentsSetting.set(project, updateDependents);
3679
+ }
3680
+ }
3681
+ }
3682
+ /**
3683
+ * Apply initial filtering to construct releaseGroupToFilteredProjects based on filters.
3684
+ * This determines the base set of projects and groups before considering dependencies.
3685
+ */
3686
+ applyInitialFiltering() {
3687
+ const matchedReleaseGroups = [];
3688
+ for (const releaseGroup of this.releaseGroups) {
3689
+ if (this.filters.groups?.length && !this.filters.groups.includes(releaseGroup.name)) {
3690
+ continue;
3691
+ }
3692
+ if (this.filters.groups?.length && !this.filters.projects?.length) {
3693
+ this.releaseGroupToFilteredProjects.set(
3694
+ releaseGroup,
3695
+ new Set(releaseGroup.projects)
3696
+ );
3697
+ matchedReleaseGroups.push(releaseGroup);
3698
+ continue;
3699
+ }
3700
+ const filteredProjects = /* @__PURE__ */ new Set();
3701
+ for (const project of releaseGroup.projects) {
3702
+ if (this.filters.projects?.length && !this.filters.projects.includes(project)) {
3703
+ continue;
3704
+ }
3705
+ filteredProjects.add(project);
3706
+ }
3707
+ if (filteredProjects.size > 0 || !this.hasAnyFilters()) {
3708
+ const projectsToInclude = filteredProjects.size > 0 ? filteredProjects : new Set(releaseGroup.projects);
3709
+ this.releaseGroupToFilteredProjects.set(
3710
+ releaseGroup,
3711
+ projectsToInclude
3712
+ );
3713
+ matchedReleaseGroups.push(releaseGroup);
3714
+ }
3715
+ }
3716
+ if (this.hasAnyFilters()) {
3717
+ this.releaseGroups = matchedReleaseGroups;
3718
+ }
3719
+ }
3720
+ /**
3721
+ * Check if any filters are applied
3722
+ */
3723
+ hasAnyFilters() {
3724
+ return !!(this.filters.projects?.length || this.filters.groups?.length);
3725
+ }
3726
+ /**
3727
+ * Setup projects to process and resolve version actions
3728
+ */
3729
+ async setupProjectsToProcess(options) {
3730
+ const {
3731
+ tree,
3732
+ projectGraph,
3733
+ nxReleaseConfig,
3734
+ filters,
3735
+ firstRelease,
3736
+ versionActionsOptionsOverrides
3737
+ } = options;
3738
+ let projectsToProcess = /* @__PURE__ */ new Set();
3739
+ const resolveVersionActionsForProjectCallbacks = [];
3740
+ for (const [groupName, group] of Object.entries(nxReleaseConfig.groups)) {
3741
+ for (const project of group.projects) {
3742
+ this.allProjectsConfiguredForNxRelease.add(project);
3743
+ this.projectLoggers.set(project, new ProjectLogger(project));
3744
+ if (filters.groups?.includes(groupName)) {
3745
+ projectsToProcess.add(project);
3746
+ } else if (filters.projects?.includes(project)) {
3747
+ projectsToProcess.add(project);
3748
+ }
3749
+ const projectGraphNode = projectGraph.nodes[project];
3750
+ const releaseGroup = this.projectToReleaseGroup.get(project);
3751
+ const finalConfigForProject = _ReleaseGraph.resolveFinalConfigForProject(
3752
+ releaseGroup,
3753
+ projectGraphNode,
3754
+ firstRelease,
3755
+ versionActionsOptionsOverrides
3756
+ );
3757
+ this.finalConfigsByProject.set(project, finalConfigForProject);
3758
+ resolveVersionActionsForProjectCallbacks.push(async () => {
3759
+ const {
3760
+ versionActionsPath,
3761
+ versionActions,
3762
+ afterAllProjectsVersioned
3763
+ } = await resolveVersionActionsForProject(
3764
+ tree,
3765
+ releaseGroup,
3766
+ projectGraphNode,
3767
+ finalConfigForProject
3768
+ );
3769
+ if (!this.uniqueAfterAllProjectsVersioned.has(versionActionsPath)) {
3770
+ this.uniqueAfterAllProjectsVersioned.set(
3771
+ versionActionsPath,
3772
+ afterAllProjectsVersioned
3773
+ );
3774
+ }
3775
+ let versionActionsToUse = versionActions;
3776
+ const shouldSkip = shouldSkipVersionActions(
3777
+ finalConfigForProject.dockerOptions,
3778
+ project
3779
+ );
3780
+ if (shouldSkip) {
3781
+ versionActionsToUse = new NOOP_VERSION_ACTIONS$1(
3782
+ releaseGroup,
3783
+ projectGraphNode,
3784
+ finalConfigForProject
3785
+ );
3786
+ }
3787
+ this.projectsToVersionActions.set(project, versionActionsToUse);
3788
+ });
3789
+ }
3790
+ }
3791
+ if (!filters.groups?.length && !filters.projects?.length) {
3792
+ projectsToProcess = this.allProjectsConfiguredForNxRelease;
3793
+ }
3794
+ if (projectsToProcess.size === 0) {
3795
+ throw new Error(
3796
+ "No projects are set to be processed, please report this as a bug on https://github.com/nrwl/nx/issues"
3797
+ );
3798
+ }
3799
+ this.allProjectsToProcess = new Set(projectsToProcess);
3800
+ for (const cb of resolveVersionActionsForProjectCallbacks) {
3801
+ await cb();
3802
+ }
3803
+ }
3804
+ /**
3805
+ * Precompute dependency relationships between all projects
3806
+ */
3807
+ async precomputeDependencyRelationships(tree, projectGraph) {
3808
+ for (const projectName of this.allProjectsConfiguredForNxRelease) {
3809
+ const versionActions = this.projectsToVersionActions.get(projectName);
3810
+ if (!this.projectToDependencies.has(projectName)) {
3811
+ this.projectToDependencies.set(projectName, /* @__PURE__ */ new Set());
3812
+ }
3813
+ const deps = await versionActions.readDependencies(tree, projectGraph);
3814
+ for (const dep of deps) {
3815
+ if (!this.allProjectsConfiguredForNxRelease.has(dep.target)) {
3816
+ continue;
3817
+ }
3818
+ this.projectToDependencies.get(projectName).add(dep.target);
3819
+ if (!this.projectToDependents.has(dep.target)) {
3820
+ this.projectToDependents.set(dep.target, /* @__PURE__ */ new Set());
3821
+ }
3822
+ this.projectToDependents.get(dep.target).add(projectName);
3823
+ }
3824
+ }
3825
+ }
3826
+ /**
3827
+ * Apply dependency-aware filtering that considers updateDependents configuration.
3828
+ * This includes transitive dependents based on updateDependents setting ('always' by default, or 'auto').
3829
+ */
3830
+ applyDependencyAwareFiltering() {
3831
+ this.originalFilteredProjects = new Set(this.allProjectsToProcess);
3832
+ if (!this.hasAnyFilters()) {
3833
+ return;
3834
+ }
3835
+ this.validateFilterAgainstFixedGroups();
3836
+ this.findDependentsToProcess();
3837
+ this.generateFilterLog();
3838
+ }
3839
+ /**
3840
+ * Validate that the filter doesn't try to isolate projects in fixed release groups
3841
+ */
3842
+ validateFilterAgainstFixedGroups() {
3843
+ if (!this.filters.projects?.length) {
3844
+ return;
3845
+ }
3846
+ for (const releaseGroup of this.releaseGroups) {
3847
+ if (releaseGroup.projectsRelationship !== "fixed") {
3848
+ continue;
3849
+ }
3850
+ const filteredProjectsInGroup = releaseGroup.projects.filter(
3851
+ (p) => this.releaseGroupToFilteredProjects.get(releaseGroup)?.has(p)
3852
+ );
3853
+ if (filteredProjectsInGroup.length > 0 && filteredProjectsInGroup.length < releaseGroup.projects.length) {
3854
+ throw new Error(
3855
+ `Cannot filter to a subset of projects within fixed release group "${releaseGroup.name}". Filtered projects: [${filteredProjectsInGroup.join(", ")}], All projects in group: [${releaseGroup.projects.join(", ")}]. Either filter to all projects in the group, use --groups to filter by group, or change the group to "independent".`
3856
+ );
3857
+ }
3858
+ }
3859
+ }
3860
+ /**
3861
+ * Find dependents that should be included in processing based on updateDependents configuration
3862
+ */
3863
+ findDependentsToProcess() {
3864
+ const projectsToProcess = Array.from(this.allProjectsToProcess);
3865
+ const allTrackedDependents = /* @__PURE__ */ new Set();
3866
+ const dependentsToProcess = /* @__PURE__ */ new Set();
3867
+ const additionalGroups = /* @__PURE__ */ new Map();
3868
+ let currentLevel = [...projectsToProcess];
3869
+ while (currentLevel.length > 0) {
3870
+ const nextLevel = [];
3871
+ const dependents = this.getAllNonImplicitDependents(currentLevel);
3872
+ for (const dep of dependents) {
3873
+ if (allTrackedDependents.has(dep) || this.allProjectsToProcess.has(dep)) {
3874
+ continue;
3875
+ }
3876
+ allTrackedDependents.add(dep);
3877
+ const depUpdateDependentsSetting = this.projectToUpdateDependentsSetting.get(dep);
3878
+ if (depUpdateDependentsSetting !== "never") {
3879
+ const shouldIncludeDependent = currentLevel.some((proj) => {
3880
+ const projUpdateSetting = this.projectToUpdateDependentsSetting.get(proj);
3881
+ const projDependents = this.getProjectDependents(proj);
3882
+ if (!projDependents.has(dep)) {
3883
+ return false;
3884
+ }
3885
+ if (projUpdateSetting === "always") {
3886
+ return true;
3887
+ }
3888
+ if (projUpdateSetting === "auto") {
3889
+ const projGroup = this.getReleaseGroupForProject(proj);
3890
+ const depGroup = this.getReleaseGroupForProject(dep);
3891
+ return projGroup && depGroup && projGroup.name === depGroup.name;
3892
+ }
3893
+ return false;
3894
+ });
3895
+ if (shouldIncludeDependent) {
3896
+ dependentsToProcess.add(dep);
3897
+ const depGroup = this.getReleaseGroupForProject(dep);
3898
+ if (depGroup) {
3899
+ const groupAlreadyExists = this.releaseGroups.some(
3900
+ (g) => g.name === depGroup.name
3901
+ );
3902
+ if (!groupAlreadyExists) {
3903
+ additionalGroups.set(depGroup.name, depGroup);
3904
+ }
3905
+ }
3906
+ }
3907
+ }
3908
+ nextLevel.push(dep);
3909
+ }
3910
+ currentLevel = nextLevel;
3911
+ }
3912
+ dependentsToProcess.forEach((dep) => this.allProjectsToProcess.add(dep));
3913
+ additionalGroups.forEach((group) => {
3914
+ const groupForDependents = {
3915
+ ...group,
3916
+ versionPlans: false,
3917
+ resolvedVersionPlans: false
3918
+ };
3919
+ this.releaseGroups.push(groupForDependents);
3920
+ const projectsInGroup = new Set(
3921
+ group.projects.filter((p) => dependentsToProcess.has(p))
3922
+ );
3923
+ this.releaseGroupToFilteredProjects.set(
3924
+ groupForDependents,
3925
+ projectsInGroup
3926
+ );
3927
+ });
3928
+ }
3929
+ /**
3930
+ * Generate user-friendly log describing what the filter matched
3931
+ */
3932
+ generateFilterLog() {
3933
+ if (this.filters.projects?.length) {
3934
+ const matchedProjects = Array.from(this.originalFilteredProjects);
3935
+ this.filterLog = {
3936
+ title: `Your filter "${this.filters.projects.join(
3937
+ ","
3938
+ )}" matched the following projects:`,
3939
+ bodyLines: matchedProjects.map((p) => {
3940
+ const releaseGroupForProject = this.projectToReleaseGroup.get(p);
3941
+ if (!releaseGroupForProject || releaseGroupForProject.name === IMPLICIT_DEFAULT_RELEASE_GROUP) {
3942
+ return `- ${p}`;
3943
+ }
3944
+ return `- ${p} (release group "${releaseGroupForProject.name}")`;
3945
+ })
3946
+ };
3947
+ }
3948
+ }
3949
+ /**
3950
+ * Build the group graph structure
3951
+ */
3952
+ buildGroupGraphStructure() {
3953
+ for (const group of this.releaseGroups) {
3954
+ if (!this.groupGraph.has(group.name)) {
3955
+ this.groupGraph.set(group.name, {
3956
+ group,
3957
+ dependencies: /* @__PURE__ */ new Set(),
3958
+ dependents: /* @__PURE__ */ new Set()
3959
+ });
3960
+ }
3961
+ }
3962
+ }
3963
+ /**
3964
+ * Resolve current versions for all projects that will be processed
3965
+ */
3966
+ async resolveCurrentVersionsForProjects(tree, projectGraph, preid) {
3967
+ for (const [, releaseGroupNode] of this.groupGraph) {
3968
+ for (const projectName of releaseGroupNode.group.projects) {
3969
+ const projectGraphNode = projectGraph.nodes[projectName];
3970
+ if (!this.allProjectsToProcess.has(projectName)) {
3971
+ continue;
3972
+ }
3973
+ const versionActions = this.projectsToVersionActions.get(projectName);
3974
+ const finalConfigForProject = this.finalConfigsByProject.get(projectName);
3975
+ let latestMatchingGitTag;
3976
+ const releaseTagPattern = releaseGroupNode.group.releaseTag.pattern;
3977
+ if (finalConfigForProject.currentVersionResolver === "git-tag") {
3978
+ const additionalInterpolationData = {
3979
+ projectName: sanitizeProjectNameForGitTag(projectGraphNode.name),
3980
+ releaseGroupName: releaseGroupNode.group.name
3981
+ };
3982
+ const options = {
3983
+ checkAllBranchesWhen: releaseGroupNode.group.releaseTag.checkAllBranchesWhen,
3984
+ preid,
3985
+ requireSemver: releaseGroupNode.group.releaseTag.requireSemver,
3986
+ strictPreid: releaseGroupNode.group.releaseTag.strictPreid
3987
+ };
3988
+ if (releaseGroupNode.group.projectsRelationship === "fixed" && !releaseTagPattern.includes("{projectName}")) {
3989
+ const groupReleaseTag = await getLatestGitTagForPattern(
3990
+ releaseTagPattern,
3991
+ additionalInterpolationData,
3992
+ this.resolveRepositoryTags.bind(this),
3993
+ options
3994
+ );
3995
+ const projectReleaseTag = await getLatestGitTagForPattern(
3996
+ releaseTagPattern.includes("{releaseGroupName}") ? releaseTagPattern.replace(
3997
+ /\{releaseGroupName\}/g,
3998
+ "{projectName}"
3999
+ ) : `{projectName}@${releaseTagPattern}`,
4000
+ additionalInterpolationData,
4001
+ this.resolveRepositoryTags.bind(this),
4002
+ options
4003
+ );
4004
+ if (projectReleaseTag?.extractedVersion && groupReleaseTag?.extractedVersion && gte(
4005
+ projectReleaseTag.extractedVersion,
4006
+ groupReleaseTag.extractedVersion
4007
+ )) {
4008
+ latestMatchingGitTag = projectReleaseTag;
4009
+ } else {
4010
+ latestMatchingGitTag = groupReleaseTag;
4011
+ }
4012
+ } else {
4013
+ latestMatchingGitTag = await getLatestGitTagForPattern(
4014
+ releaseTagPattern,
4015
+ additionalInterpolationData,
4016
+ this.resolveRepositoryTags.bind(this),
4017
+ options
4018
+ );
4019
+ }
4020
+ this.cachedLatestMatchingGitTag.set(
4021
+ projectName,
4022
+ latestMatchingGitTag
4023
+ );
4024
+ const currentVersion = await resolveCurrentVersion(
4025
+ tree,
4026
+ projectGraphNode,
4027
+ releaseGroupNode.group,
4028
+ versionActions,
4029
+ this.projectLoggers.get(projectName),
4030
+ this.currentVersionsPerFixedReleaseGroup,
4031
+ finalConfigForProject,
4032
+ releaseTagPattern,
4033
+ latestMatchingGitTag
4034
+ );
4035
+ this.cachedCurrentVersions.set(projectName, currentVersion);
4036
+ }
4037
+ }
4038
+ }
4039
+ }
4040
+ /**
4041
+ * Build dependency relationships between release groups
4042
+ */
4043
+ buildGroupDependencyGraph() {
4044
+ for (const [releaseGroupName, releaseGroupNode] of this.groupGraph) {
4045
+ for (const projectName of releaseGroupNode.group.projects) {
4046
+ const projectDeps = this.getProjectDependencies(projectName);
4047
+ for (const dep of projectDeps) {
4048
+ const dependencyGroup = this.getReleaseGroupNameForProject(dep);
4049
+ if (dependencyGroup && dependencyGroup !== releaseGroupName) {
4050
+ releaseGroupNode.dependencies.add(dependencyGroup);
4051
+ const dependencyGroupNode = this.groupGraph.get(dependencyGroup);
4052
+ if (dependencyGroupNode) {
4053
+ dependencyGroupNode.dependents.add(releaseGroupName);
4054
+ }
4055
+ }
4056
+ }
4057
+ }
4058
+ }
4059
+ }
4060
+ /**
4061
+ * Topologically sort release groups
4062
+ */
4063
+ topologicallySortReleaseGroups() {
4064
+ const groupNames = Array.from(this.groupGraph.keys());
4065
+ const getGroupDependencies = (groupName) => {
4066
+ const groupNode = this.groupGraph.get(groupName);
4067
+ if (!groupNode) {
4068
+ return [];
4069
+ }
4070
+ return Array.from(groupNode.dependencies);
4071
+ };
4072
+ return topologicalSort(groupNames, getGroupDependencies);
4073
+ }
4074
+ /**
4075
+ * Topologically sort projects within a release group
4076
+ */
4077
+ topologicallySortProjects(releaseGroup) {
4078
+ const projects = releaseGroup.projects.filter(
4079
+ (p) => this.allProjectsToProcess.has(p)
4080
+ );
4081
+ const getProjectDependenciesInSameGroup = (project) => {
4082
+ const deps = this.getProjectDependencies(project);
4083
+ return Array.from(deps).filter(
4084
+ (dep) => this.getReleaseGroupNameForProject(dep) === releaseGroup.name && this.allProjectsToProcess.has(dep)
4085
+ );
4086
+ };
4087
+ return topologicalSort(projects, getProjectDependenciesInSameGroup);
4088
+ }
4089
+ async populateDependentProjectsData(tree, projectGraph) {
4090
+ for (const projectName of this.allProjectsToProcess) {
4091
+ const dependentProjectNames = Array.from(
4092
+ this.getProjectDependents(projectName)
4093
+ ).filter((dep) => this.allProjectsConfiguredForNxRelease.has(dep));
4094
+ const dependentProjectsData = [];
4095
+ for (const dependentProjectName of dependentProjectNames) {
4096
+ const versionActions = this.projectsToVersionActions.get(dependentProjectName);
4097
+ const { currentVersion, dependencyCollection } = await versionActions.readCurrentVersionOfDependency(
4098
+ tree,
4099
+ projectGraph,
4100
+ projectName
4101
+ );
4102
+ dependentProjectsData.push({
4103
+ source: dependentProjectName,
4104
+ target: projectName,
4105
+ type: "static",
4106
+ dependencyCollection,
4107
+ rawVersionSpec: currentVersion
4108
+ });
4109
+ }
4110
+ this.originalDependentProjectsPerProject.set(
4111
+ projectName,
4112
+ dependentProjectsData
4113
+ );
4114
+ }
4115
+ }
4116
+ /**
4117
+ * Get all non-implicit dependents for a set of projects
4118
+ */
4119
+ getAllNonImplicitDependents(projects) {
4120
+ return projects.flatMap((project) => Array.from(this.getProjectDependents(project))).filter((dep) => !this.allProjectsToProcess.has(dep));
4121
+ }
4122
+ /**
4123
+ * Resolve final configuration for a project
4124
+ *
4125
+ * NOTE: We are providing ultimate fallback values via ?? here mainly just to keep TypeScript happy.
4126
+ * All default values should have been applied by this point by config.ts but the types can't know
4127
+ * that for sure at this point.
4128
+ */
4129
+ static resolveFinalConfigForProject(releaseGroup, projectGraphNode, firstRelease, versionActionsOptionsOverrides) {
4130
+ const releaseGroupVersionConfig = releaseGroup.version;
4131
+ const projectVersionConfig = projectGraphNode.data.release?.version;
4132
+ const projectDockerConfig = projectGraphNode.data.release?.docker;
4133
+ const specifierSource = projectVersionConfig?.specifierSource ?? releaseGroupVersionConfig?.specifierSource ?? "prompt";
4134
+ const versionPrefix = projectVersionConfig?.versionPrefix ?? releaseGroupVersionConfig?.versionPrefix ?? "auto";
4135
+ if (versionPrefix && !validReleaseVersionPrefixes.includes(versionPrefix)) {
4136
+ throw new Error(
4137
+ `Invalid value for versionPrefix: "${versionPrefix}"
4138
+
4139
+ Valid values are: ${validReleaseVersionPrefixes.map((s) => `"${s}"`).join(", ")}`
4140
+ );
4141
+ }
4142
+ const dockerOptions = Object.assign(
4143
+ {},
4144
+ releaseGroup.docker || {},
4145
+ projectDockerConfig || {}
4146
+ );
4147
+ let currentVersionResolver = projectVersionConfig?.currentVersionResolver ?? releaseGroupVersionConfig?.currentVersionResolver ?? "disk";
4148
+ const shouldSkip = shouldSkipVersionActions(
4149
+ dockerOptions,
4150
+ projectGraphNode.name
4151
+ );
4152
+ if (shouldSkip) {
4153
+ currentVersionResolver = "none";
4154
+ } else if (specifierSource === "conventional-commits" && currentVersionResolver !== "git-tag") {
4155
+ throw new Error(
4156
+ `Invalid currentVersionResolver "${currentVersionResolver}" provided for project "${projectGraphNode.name}". Must be "git-tag" when "specifierSource" is "conventional-commits"`
4157
+ );
4158
+ }
4159
+ const currentVersionResolverMetadata = projectVersionConfig?.currentVersionResolverMetadata ?? releaseGroupVersionConfig?.currentVersionResolverMetadata ?? {};
4160
+ const preserveLocalDependencyProtocols = projectVersionConfig?.preserveLocalDependencyProtocols ?? releaseGroupVersionConfig?.preserveLocalDependencyProtocols ?? true;
4161
+ const preserveMatchingDependencyRanges = projectVersionConfig?.preserveMatchingDependencyRanges ?? releaseGroupVersionConfig?.preserveMatchingDependencyRanges ?? true;
4162
+ const adjustSemverBumpsForZeroMajorVersion = projectVersionConfig?.adjustSemverBumpsForZeroMajorVersion ?? releaseGroupVersionConfig?.adjustSemverBumpsForZeroMajorVersion ?? true;
4163
+ const applyPreidToDependents = projectVersionConfig?.applyPreidToDependents ?? releaseGroupVersionConfig?.applyPreidToDependents ?? false;
4164
+ const fallbackCurrentVersionResolver = projectVersionConfig?.fallbackCurrentVersionResolver ?? releaseGroupVersionConfig?.fallbackCurrentVersionResolver ?? (firstRelease ? "disk" : void 0);
4165
+ let versionActionsOptions = projectVersionConfig?.versionActionsOptions ?? releaseGroupVersionConfig?.versionActionsOptions ?? {};
4166
+ versionActionsOptions = {
4167
+ ...versionActionsOptions,
4168
+ ...versionActionsOptionsOverrides ?? {}
4169
+ };
4170
+ const manifestRootsToUpdate = (projectVersionConfig?.manifestRootsToUpdate ?? releaseGroupVersionConfig?.manifestRootsToUpdate ?? []).map((manifestRoot) => {
4171
+ if (typeof manifestRoot === "string") {
4172
+ return {
4173
+ path: manifestRoot,
4174
+ // Apply the project level preserveLocalDependencyProtocols setting that was already resolved
4175
+ preserveLocalDependencyProtocols
4176
+ };
4177
+ }
4178
+ return manifestRoot;
4179
+ });
4180
+ return {
4181
+ specifierSource,
4182
+ currentVersionResolver,
4183
+ currentVersionResolverMetadata,
4184
+ fallbackCurrentVersionResolver,
4185
+ versionPrefix,
4186
+ preserveLocalDependencyProtocols,
4187
+ preserveMatchingDependencyRanges,
4188
+ adjustSemverBumpsForZeroMajorVersion,
4189
+ applyPreidToDependents,
4190
+ versionActionsOptions,
4191
+ manifestRootsToUpdate,
4192
+ dockerOptions
4193
+ };
4194
+ }
4195
+ /**
4196
+ * Get the release group for a given project
4197
+ */
4198
+ getReleaseGroupForProject(projectName) {
4199
+ return this.projectToReleaseGroup.get(projectName);
4200
+ }
4201
+ /**
4202
+ * Get the release group name for a given project
4203
+ */
4204
+ getReleaseGroupNameForProject(projectName) {
4205
+ const group = this.projectToReleaseGroup.get(projectName);
4206
+ return group ? group.name : null;
4207
+ }
4208
+ /**
4209
+ * Get the dependencies of a project
4210
+ */
4211
+ getProjectDependencies(projectName) {
4212
+ return this.projectToDependencies.get(projectName) || /* @__PURE__ */ new Set();
4213
+ }
4214
+ /**
4215
+ * Get the dependents of a project (projects that depend on it)
4216
+ */
4217
+ getProjectDependents(projectName) {
4218
+ return this.projectToDependents.get(projectName) || /* @__PURE__ */ new Set();
4219
+ }
4220
+ /**
4221
+ * Get the version actions for a project
4222
+ */
4223
+ getVersionActionsForProject(projectName) {
4224
+ return this.projectsToVersionActions.get(projectName);
4225
+ }
4226
+ /**
4227
+ * Check if a project will be processed
4228
+ */
4229
+ isProjectToProcess(projectName) {
4230
+ return this.allProjectsToProcess.has(projectName);
4231
+ }
4232
+ async resolveAffectedFilesPerCommitInProjectGraph(commit, projectGraph) {
4233
+ const { shortHash } = commit;
4234
+ let affectedGraph = this.affectedGraphPerCommit.get(shortHash);
4235
+ if (affectedGraph) {
4236
+ return affectedGraph;
4237
+ }
4238
+ const touchedFiles = calculateFileChanges(commit.affectedFiles, {
4239
+ base: `${commit.shortHash}^`,
4240
+ head: commit.shortHash
4241
+ });
4242
+ affectedGraph = await filterAffected(projectGraph, touchedFiles);
4243
+ this.affectedGraphPerCommit.set(shortHash, affectedGraph);
4244
+ return affectedGraph;
4245
+ }
4246
+ async resolveRepositoryTags(resolveTagsWhen) {
4247
+ return this.repositoryGitTags.resolveTags(resolveTagsWhen);
4248
+ }
4249
+ /**
4250
+ * Runs validation on resolved VersionActions instances. E.g. check that manifest files exist for all projects that will be processed.
4251
+ * This should be called after preVersionCommand has run, as those commands may create manifest files that are needed for versioning.
4252
+ */
4253
+ async validate(tree) {
4254
+ const validationPromises = [];
4255
+ for (const projectName of this.allProjectsToProcess) {
4256
+ const versionActions = this.projectsToVersionActions.get(projectName);
4257
+ if (versionActions) {
4258
+ validationPromises.push(versionActions.validate(tree));
4259
+ }
4260
+ }
4261
+ await Promise.all(validationPromises);
4262
+ }
4263
+ };
4264
+ async function createReleaseGraph(options) {
4265
+ const releaseGroups = Object.entries(
4266
+ options.nxReleaseConfig.groups ?? {}
4267
+ ).map(([name, group]) => {
4268
+ return {
4269
+ ...group,
4270
+ name,
4271
+ resolvedVersionPlans: group.versionPlans ? [] : false
4272
+ };
4273
+ });
4274
+ const graph = new ReleaseGraph(releaseGroups, options.filters);
4275
+ await graph.init(options);
4276
+ return graph;
4277
+ }
3591
4278
  var StormReleaseGroupProcessor = class extends ReleaseGroupProcessor {
3592
4279
  constructor(tree, workspaceConfig, projectGraph, nxReleaseConfig, releaseGraph, versionOptions) {
3593
4280
  super(tree, projectGraph, nxReleaseConfig, releaseGraph, {
@@ -3793,45 +4480,48 @@ var StormReleaseGroupProcessor = class extends ReleaseGroupProcessor {
3793
4480
  return false;
3794
4481
  }
3795
4482
  let bumped = false;
3796
- const firstProject = releaseGroup.projects.reduce((ret, project) => {
4483
+ const fixedGroup = {
4484
+ firstProject: null,
4485
+ newVersion: null,
4486
+ currentVersion: null
4487
+ };
4488
+ for (const project of releaseGroup.projects) {
3797
4489
  const currentVersion = this.#getCurrentCachedVersionForProject(project);
3798
4490
  if (!currentVersion) {
3799
4491
  writeTrace(
3800
4492
  `No current version found for project ${project} in release group ${releaseGroup.name}, skipping version comparison.`,
3801
4493
  this.workspaceConfig
3802
4494
  );
3803
- return "";
3804
- }
3805
- if (!ret) {
3806
- writeTrace(
3807
- `Defaulting to first version ${currentVersion} (project: ${project})`,
3808
- this.workspaceConfig
3809
- );
3810
- return project;
3811
- }
3812
- const largestVersion = this.#getCurrentCachedVersionForProject(ret);
3813
- if (!largestVersion) {
3814
- writeTrace(
3815
- `No current version found for project ${ret} in release group ${releaseGroup.name}, skipping version comparison.`,
4495
+ } else {
4496
+ writeDebug(
4497
+ `Comparing versions for fixed group ${releaseGroup.name}: Current Greatest Version: ${fixedGroup.currentVersion || "none"}, Current Project Version: ${currentVersion} (project: ${project})`,
3816
4498
  this.workspaceConfig
3817
4499
  );
3818
- return project;
3819
- }
3820
- writeDebug(
3821
- `Comparing versions for fixed group ${releaseGroup.name}: Current Greatest Version: ${largestVersion}, Current Project Version: ${currentVersion} (project: ${project})`,
3822
- this.workspaceConfig
3823
- );
3824
- if (currentVersion && semver.gt(currentVersion, largestVersion)) {
3825
- return project;
4500
+ const {
4501
+ newVersionInput,
4502
+ newVersionInputReason,
4503
+ newVersionInputReasonData
4504
+ } = await this.#determineVersionBumpForProject(releaseGroup, project);
4505
+ if (!fixedGroup.currentVersion || currentVersion && semver.gt(currentVersion, fixedGroup.currentVersion) || !fixedGroup.newVersion || fixedGroup.newVersion.input === "none" || newVersionInput && semver.gt(newVersionInput, fixedGroup.newVersion.input)) {
4506
+ if (!fixedGroup.currentVersion || currentVersion && semver.gt(currentVersion, fixedGroup.currentVersion)) {
4507
+ fixedGroup.currentVersion = currentVersion;
4508
+ }
4509
+ if (!fixedGroup.newVersion || fixedGroup.newVersion.input === "none" || newVersionInput && semver.gt(newVersionInput, fixedGroup.newVersion.input)) {
4510
+ fixedGroup.newVersion = {
4511
+ input: newVersionInput,
4512
+ reason: newVersionInputReason,
4513
+ reasonData: newVersionInputReasonData
4514
+ };
4515
+ }
4516
+ writeDebug(
4517
+ `Fixed release group ${releaseGroup.name} updated: Current Version: ${fixedGroup.currentVersion || "none"}, New Version: ${fixedGroup.newVersion?.input || "none"} (first project: ${project})`,
4518
+ this.workspaceConfig
4519
+ );
4520
+ fixedGroup.firstProject = project;
4521
+ }
3826
4522
  }
3827
- return ret;
3828
- }, "");
3829
- const {
3830
- newVersionInput,
3831
- newVersionInputReason,
3832
- newVersionInputReasonData
3833
- } = await this.#determineVersionBumpForProject(releaseGroup, firstProject);
3834
- if (newVersionInput === "none") {
4523
+ }
4524
+ if (fixedGroup.newVersion?.input === "none") {
3835
4525
  let bumpedByDependency = false;
3836
4526
  const sortedProjects2 = this.#releaseGraph.sortedProjects.get(releaseGroup.name) || [];
3837
4527
  for (const project of sortedProjects2) {
@@ -3881,22 +4571,22 @@ var StormReleaseGroupProcessor = class extends ReleaseGroupProcessor {
3881
4571
  dockerVersion: null,
3882
4572
  dependentProjects: this.#getOriginalDependentProjects(project)
3883
4573
  });
3884
- if (project === firstProject) {
4574
+ if (project === fixedGroup.firstProject) {
3885
4575
  continue;
3886
4576
  }
3887
4577
  const projectLogger = this.#getProjectLoggerForProject(project);
3888
4578
  projectLogger.buffer(
3889
- `\u{1F6AB} Skipping versioning for ${project} as it is a part of a fixed release group with ${firstProject} and no dependency bumps were detected`
4579
+ `\u{1F6AB} Skipping versioning for ${project} as it is a part of a fixed release group with ${fixedGroup.firstProject} and no dependency bumps were detected`
3890
4580
  );
3891
4581
  }
3892
4582
  }
3893
4583
  return bumpedByDependency;
3894
4584
  }
3895
4585
  const { newVersion } = await this.#calculateNewVersion(
3896
- firstProject,
3897
- newVersionInput,
3898
- newVersionInputReason,
3899
- newVersionInputReasonData
4586
+ fixedGroup.firstProject,
4587
+ fixedGroup.newVersion?.input ?? "none",
4588
+ fixedGroup.newVersion.reason,
4589
+ fixedGroup.newVersion?.reasonData ?? {}
3900
4590
  );
3901
4591
  const sortedProjects = this.#releaseGraph.sortedProjects.get(releaseGroup.name) || releaseGroup.projects;
3902
4592
  for (const project of sortedProjects) {
@@ -3905,9 +4595,9 @@ var StormReleaseGroupProcessor = class extends ReleaseGroupProcessor {
3905
4595
  const currentVersion = this.#getCurrentCachedVersionForProject(
3906
4596
  project
3907
4597
  );
3908
- if (project !== firstProject) {
4598
+ if (project !== fixedGroup.firstProject) {
3909
4599
  projectLogger.buffer(
3910
- `\u2753 Applied version ${newVersion} directly, because the project is a member of a fixed release group containing ${firstProject}`
4600
+ `\u2753 Applied version ${newVersion} directly, because the project is a member of a fixed release group containing ${fixedGroup.firstProject}`
3911
4601
  );
3912
4602
  }
3913
4603
  const logMessages = await versionActions.updateProjectVersion(
@@ -4163,7 +4853,7 @@ var StormReleaseGroupProcessor = class extends ReleaseGroupProcessor {
4163
4853
  }
4164
4854
  }
4165
4855
  } else {
4166
- const releaseGroupText = releaseGroupName !== IMPLICIT_DEFAULT_RELEASE_GROUP ? ` in release group "${releaseGroupName}" ` : " ";
4856
+ const releaseGroupText = releaseGroupName !== IMPLICIT_DEFAULT_RELEASE_GROUP$1 ? ` in release group "${releaseGroupName}" ` : " ";
4167
4857
  projectLogger.buffer(
4168
4858
  `\u23E9 Skipping dependent updates as "updateDependents"${releaseGroupText}is not "auto"`
4169
4859
  );
@@ -4346,7 +5036,7 @@ ${formatConfigLog(config5)}`,
4346
5036
  v.newVersion ? extractPreid(v.newVersion) : void 0
4347
5037
  ])
4348
5038
  );
4349
- const releaseGraph = options.releaseGraph ?? await createReleaseGraph({
5039
+ const releaseGraph = await createReleaseGraph({
4350
5040
  tree: this.tree,
4351
5041
  projectGraph: this.projectGraph,
4352
5042
  nxReleaseConfig: this.releaseConfig,
@@ -4675,7 +5365,7 @@ ${Object.keys(allProjectChangelogs).map((p) => ` - ${p}`).join("\n")}
4675
5365
  "Failed to load the project graph. Please run `nx reset`, then run the `storm-git commit` command again."
4676
5366
  );
4677
5367
  }
4678
- const releaseGraph = options.releaseGraph ?? await createReleaseGraph({
5368
+ const releaseGraph = await createReleaseGraph({
4679
5369
  tree: this.tree,
4680
5370
  projectGraph: this.projectGraph,
4681
5371
  nxReleaseConfig: this.releaseConfig,