Skip to content

Commit

Permalink
fix(core): attach github release to the current branch (#20046)
Browse files Browse the repository at this point in the history
  • Loading branch information
FrozenPandaz authored Nov 7, 2023
1 parent 7416b9c commit 79e4c3f
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 109 deletions.
222 changes: 117 additions & 105 deletions packages/nx/src/command-line/release/changelog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
getGitDiff,
getLatestGitTagForPattern,
parseCommits,
getCommitHash,
} from './utils/git';
import {
GithubRelease,
Expand All @@ -38,6 +39,7 @@ import {
import { launchEditor } from './utils/launch-editor';
import { parseChangelogMarkdown } from './utils/markdown';
import { printChanges, printDiff } from './utils/print-changes';
import { handleErrors } from '../../utils/params';

class ReleaseVersion {
rawVersion: string;
Expand All @@ -63,100 +65,130 @@ class ReleaseVersion {
}

export async function changelogHandler(args: ChangelogOptions): Promise<void> {
// Right now, the given version must be valid semver in order to proceed
if (!valid(args.version)) {
output.error({
title: `The given version "${args.version}" is not a valid semver version. Please provide your version in the format "1.0.0", "1.0.0-beta.1" etc`,
});
process.exit(1);
}

const projectGraph = await createProjectGraphAsync({ exitOnError: true });
const nxJson = readNxJson();
return handleErrors(args.verbose, async () => {
// Right now, the given version must be valid semver in order to proceed
if (!valid(args.version)) {
output.error({
title: `The given version "${args.version}" is not a valid semver version. Please provide your version in the format "1.0.0", "1.0.0-beta.1" etc`,
});
process.exit(1);
}

if (args.verbose) {
process.env.NX_VERBOSE_LOGGING = 'true';
}
const projectGraph = await createProjectGraphAsync({ exitOnError: true });
const nxJson = readNxJson();
const commitHash = await getCommitHash(args.to);

// Apply default configuration to any optional user configuration
const { error: configError, nxReleaseConfig } = await createNxReleaseConfig(
projectGraph,
nxJson.release
);
if (configError) {
return await handleNxReleaseConfigError(configError);
}
if (args.verbose) {
process.env.NX_VERBOSE_LOGGING = 'true';
}

const {
error: filterError,
releaseGroups,
releaseGroupToFilteredProjects,
} = filterReleaseGroups(
projectGraph,
nxReleaseConfig,
args.projects,
args.groups
);
if (filterError) {
output.error(filterError);
process.exit(1);
}
// Apply default configuration to any optional user configuration
const { error: configError, nxReleaseConfig } = await createNxReleaseConfig(
projectGraph,
nxJson.release
);
if (configError) {
return await handleNxReleaseConfigError(configError);
}

const releaseVersion = new ReleaseVersion({
version: args.version,
releaseTagPattern: nxReleaseConfig.releaseTagPattern,
});
const {
error: filterError,
releaseGroups,
releaseGroupToFilteredProjects,
} = filterReleaseGroups(
projectGraph,
nxReleaseConfig,
args.projects,
args.groups
);
if (filterError) {
output.error(filterError);
process.exit(1);
}

const from =
args.from ||
(await getLatestGitTagForPattern(nxReleaseConfig.releaseTagPattern))?.tag;
if (!from) {
output.error({
title: `Unable to determine the previous git tag, please provide an explicit git reference using --from`,
const releaseVersion = new ReleaseVersion({
version: args.version,
releaseTagPattern: nxReleaseConfig.releaseTagPattern,
});
process.exit(1);
}
const rawCommits = await getGitDiff(from, args.to);

// Parse as conventional commits
const commits = parseCommits(rawCommits).filter((c) => {
const type = c.type;
// Always ignore non user-facing commits for now
// TODO: allow this filter to be configurable via config in a future release
if (type === 'feat' || type === 'fix' || type === 'perf') {
return true;

const from =
args.from ||
(await getLatestGitTagForPattern(nxReleaseConfig.releaseTagPattern))?.tag;
if (!from) {
output.error({
title: `Unable to determine the previous git tag, please provide an explicit git reference using --from`,
});
process.exit(1);
}
return false;
});
const rawCommits = await getGitDiff(from, args.to);

// Parse as conventional commits
const commits = parseCommits(rawCommits).filter((c) => {
const type = c.type;
// Always ignore non user-facing commits for now
// TODO: allow this filter to be configurable via config in a future release
if (type === 'feat' || type === 'fix' || type === 'perf') {
return true;
}
return false;
});

const tree = new FsTree(workspaceRoot, args.verbose);
const tree = new FsTree(workspaceRoot, args.verbose);

await generateChangelogForWorkspace(
tree,
releaseVersion,
!!args.dryRun,
// Only trigger interactive mode for the workspace changelog if the user explicitly requested it via "all" or "workspace"
args.interactive === 'all' || args.interactive === 'workspace',
commits,
nxReleaseConfig.changelog.workspaceChangelog,
args.gitRemote
);
await generateChangelogForWorkspace(
tree,
releaseVersion,
!!args.dryRun,
// Only trigger interactive mode for the workspace changelog if the user explicitly requested it via "all" or "workspace"
args.interactive === 'all' || args.interactive === 'workspace',
commitHash,
commits,
nxReleaseConfig.changelog.workspaceChangelog,
args.gitRemote
);

if (args.projects?.length) {
/**
* Run changelog generation for all remaining release groups and filtered projects within them
*/
for (const releaseGroup of releaseGroups) {
const projectNodes = Array.from(
releaseGroupToFilteredProjects.get(releaseGroup)
).map((name) => projectGraph.nodes[name]);

await generateChangelogForProjects(
tree,
args.version,
!!args.dryRun,
// Only trigger interactive mode for the workspace changelog if the user explicitly requested it via "all" or "projects"
args.interactive === 'all' || args.interactive === 'projects',
commitHash,
commits,
releaseGroup.changelog,
releaseGroup.releaseTagPattern,
projectNodes,
args.gitRemote
);
}

return process.exit(0);
}

if (args.projects?.length) {
/**
* Run changelog generation for all remaining release groups and filtered projects within them
* Run changelog generation for all remaining release groups
*/
for (const releaseGroup of releaseGroups) {
const projectNodes = Array.from(
releaseGroupToFilteredProjects.get(releaseGroup)
).map((name) => projectGraph.nodes[name]);
const projectNodes = releaseGroup.projects.map(
(name) => projectGraph.nodes[name]
);

await generateChangelogForProjects(
tree,
args.version,
!!args.dryRun,
// Only trigger interactive mode for the workspace changelog if the user explicitly requested it via "all" or "projects"
args.interactive === 'all' || args.interactive === 'projects',
commitHash,
commits,
releaseGroup.changelog,
releaseGroup.releaseTagPattern,
Expand All @@ -165,38 +197,14 @@ export async function changelogHandler(args: ChangelogOptions): Promise<void> {
);
}

return process.exit(0);
}

/**
* Run changelog generation for all remaining release groups
*/
for (const releaseGroup of releaseGroups) {
const projectNodes = releaseGroup.projects.map(
(name) => projectGraph.nodes[name]
);

await generateChangelogForProjects(
tree,
args.version,
!!args.dryRun,
// Only trigger interactive mode for the workspace changelog if the user explicitly requested it via "all" or "projects"
args.interactive === 'all' || args.interactive === 'projects',
commits,
releaseGroup.changelog,
releaseGroup.releaseTagPattern,
projectNodes,
args.gitRemote
);
}

if (args.dryRun) {
logger.warn(
`\nNOTE: The "dryRun" flag means no changelogs were actually created.`
);
}
if (args.dryRun) {
logger.warn(
`\nNOTE: The "dryRun" flag means no changelogs were actually created.`
);
}

process.exit(0);
process.exit(0);
});
}

function isPrerelease(version: string): boolean {
Expand Down Expand Up @@ -229,6 +237,7 @@ async function generateChangelogForWorkspace(
releaseVersion: ReleaseVersion,
dryRun: boolean,
interactive: boolean,
commit: string,
commits: GitCommit[],
config: NxReleaseConfig['changelog']['workspaceChangelog'],
gitRemote?: string
Expand Down Expand Up @@ -421,6 +430,7 @@ async function generateChangelogForWorkspace(
version: releaseVersion.gitTag,
prerelease: releaseVersion.isPrerelease,
body: contents,
commit,
},
existingGithubReleaseForVersion
);
Expand All @@ -435,6 +445,7 @@ async function generateChangelogForProjects(
rawVersion: string,
dryRun: boolean,
interactive: boolean,
commit: string,
commits: GitCommit[],
config: NxReleaseConfig['changelog']['projectChangelogs'],
releaseTagPattern: string,
Expand Down Expand Up @@ -649,6 +660,7 @@ async function generateChangelogForProjects(
version: releaseVersion.gitTag,
prerelease: releaseVersion.isPrerelease,
body: contents,
commit,
},
existingGithubReleaseForVersion
);
Expand Down
8 changes: 8 additions & 0 deletions packages/nx/src/command-line/release/utils/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,11 @@ export function parseGitCommit(commit: RawGitCommit): GitCommit | null {
affectedFiles,
};
}

export function getCommitHash(ref: string) {
try {
return execCommand('git', ['rev-parse', ref]);
} catch (e) {
throw new Error(`Unknown revision: ${ref}`);
}
}
19 changes: 15 additions & 4 deletions packages/nx/src/command-line/release/utils/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as chalk from 'chalk';
import { execSync } from 'node:child_process';
import { existsSync, promises as fsp } from 'node:fs';
import { homedir } from 'node:os';
import { joinPathFragments, output } from '../../../devkit-exports';
import { joinPathFragments } from '../../../utils/path';
import { Reference } from './git';

// axios types and values don't seem to match
Expand All @@ -24,6 +24,7 @@ export interface GithubRequestConfig {
export interface GithubRelease {
id?: string;
tag_name: string;
target_commitish?: string;
name?: string;
body?: string;
draft?: boolean;
Expand Down Expand Up @@ -53,9 +54,16 @@ export function getGitHubRepoSlug(remoteName = 'origin'): RepoSlug {
}
}

interface GithubReleaseOptions {
version: string;
body: string;
prerelease: boolean;
commit: string;
}

export async function createOrUpdateGithubRelease(
githubRequestConfig: GithubRequestConfig,
release: { version: string; body: string; prerelease: boolean },
release: GithubReleaseOptions,
existingGithubReleaseForVersion?: GithubRelease
) {
const result = await syncGithubRelease(
Expand Down Expand Up @@ -91,7 +99,7 @@ export async function createOrUpdateGithubRelease(

async function syncGithubRelease(
githubRequestConfig: GithubRequestConfig,
release: { version: string; body: string; prerelease: boolean },
release: GithubReleaseOptions,
existingGithubReleaseForVersion?: GithubRelease
) {
const ghRelease: GithubRelease = {
Expand All @@ -108,7 +116,10 @@ async function syncGithubRelease(
existingGithubReleaseForVersion.id,
ghRelease
)
: createGithubRelease(githubRequestConfig, ghRelease));
: createGithubRelease(githubRequestConfig, {
...ghRelease,
target_commitish: release.commit,
}));
return {
status: existingGithubReleaseForVersion ? 'updated' : 'created',
id: newGhRelease.id,
Expand Down

1 comment on commit 79e4c3f

@vercel
Copy link

@vercel vercel bot commented on 79e4c3f Nov 7, 2023

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

nx-dev – ./

nx-dev-nrwl.vercel.app
nx-five.vercel.app
nx-dev-git-master-nrwl.vercel.app
nx.dev

Please sign in to comment.