|
1 | | -import { execSync } from 'node:child_process' |
2 | 1 | import { promises as fsp } from 'node:fs' |
3 | 2 | import { $fetch } from 'ofetch' |
4 | 3 | import { resolve } from 'pathe' |
| 4 | +import { compare } from 'semver' |
5 | 5 | import { glob } from 'tinyglobby' |
6 | 6 | import { exec } from 'tinyexec' |
7 | 7 | import { determineSemverChange, getGitDiff, loadChangelogConfig, parseCommits } from 'changelogen' |
@@ -99,26 +99,70 @@ export async function loadWorkspace (dir: string) { |
99 | 99 | } |
100 | 100 | } |
101 | 101 |
|
102 | | -export async function determineBumpType () { |
| 102 | +export async function determineBumpType (since?: string) { |
103 | 103 | const config = await loadChangelogConfig(process.cwd()) |
104 | | - const commits = await getLatestCommits() |
| 104 | + const commits = await getLatestCommits(since) |
105 | 105 |
|
106 | 106 | return determineSemverChange(commits, config) |
107 | 107 | } |
108 | 108 |
|
109 | | -export async function getLatestCommits () { |
110 | | - const config = await loadChangelogConfig(process.cwd()) |
| 109 | +export async function getLatestTag () { |
111 | 110 | const { stdout: latestTag } = await exec('git', ['describe', '--tags', '--abbrev=0']) |
| 111 | + return latestTag.trim() |
| 112 | +} |
| 113 | + |
| 114 | +export async function getLatestReleasedTag () { |
| 115 | + const latestReleasedTag = await exec('git', ['tag', '-l']).then(r => r.stdout.trim().split('\n').filter(t => /v3\.\d+\.\d+/.test(t)).sort(compare)).then(r => r.pop()!.trim()) |
| 116 | + return latestReleasedTag |
| 117 | +} |
| 118 | + |
| 119 | +export async function getPreviousReleasedCommits () { |
| 120 | + const config = await loadChangelogConfig(process.cwd()) |
| 121 | + const latestTag = await getLatestTag() |
| 122 | + const latestReleasedTag = await getLatestReleasedTag() |
| 123 | + const commits = parseCommits(await getGitDiff(latestTag, latestReleasedTag), config) |
| 124 | + return commits |
| 125 | +} |
| 126 | + |
| 127 | +export async function getLatestCommits (since?: string) { |
| 128 | + const config = await loadChangelogConfig(process.cwd()) |
| 129 | + const latestTag = await getLatestTag() |
| 130 | + |
| 131 | + // If filtering by date, get commits with git log --since |
| 132 | + if (since) { |
| 133 | + const { stdout } = await exec('git', ['log', `${latestTag}..HEAD`, '--since', since, '--pretty=format:%H']) |
| 134 | + const commitHashes = new Set(stdout.trim().split('\n').filter(Boolean)) |
| 135 | + |
| 136 | + const allCommits = parseCommits(await getGitDiff(latestTag), config) |
| 137 | + return allCommits.filter((commit) => { |
| 138 | + // Match against full hash (shortHash is abbreviated) |
| 139 | + return Array.from(commitHashes).some(hash => hash.startsWith(commit.shortHash)) |
| 140 | + }) |
| 141 | + } |
112 | 142 |
|
113 | | - return parseCommits(await getGitDiff(latestTag.trim()), config) |
| 143 | + return parseCommits(await getGitDiff(latestTag), config) |
114 | 144 | } |
115 | 145 |
|
116 | | -export async function getContributors () { |
| 146 | +export async function getContributors (since?: string) { |
117 | 147 | const contributors = [] as Array<{ name: string, username: string }> |
118 | 148 | const emails = new Set<string>() |
119 | | - const latestTag = execSync('git describe --tags --abbrev=0').toString().trim() |
| 149 | + const latestTag = await getLatestTag() |
| 150 | + |
120 | 151 | const rawCommits = await getGitDiff(latestTag) |
| 152 | + |
| 153 | + // Get commit hashes filtered by date if specified |
| 154 | + let allowedHashes: Set<string> | null = null |
| 155 | + if (since) { |
| 156 | + const { stdout } = await exec('git', ['log', `${latestTag}..HEAD`, '--since', since, '--pretty=format:%H']) |
| 157 | + allowedHashes = new Set(stdout.trim().split('\n').filter(Boolean)) |
| 158 | + } |
| 159 | + |
121 | 160 | for (const commit of rawCommits) { |
| 161 | + // Filter by date if specified |
| 162 | + if (allowedHashes && !Array.from(allowedHashes).some(hash => hash.startsWith(commit.shortHash))) { |
| 163 | + continue |
| 164 | + } |
| 165 | + |
122 | 166 | if (emails.has(commit.author.email) || commit.author.name === 'renovate[bot]') { continue } |
123 | 167 | const { author } = await $fetch<{ author: { login: string, email: string } }>(`https://api.github.com/repos/nuxt/nuxt/commits/${commit.shortHash}`, { |
124 | 168 | headers: { |
|
0 commit comments