|
1 | | -import { exit } from 'node:process' |
2 | | -import fs from 'node:fs' |
3 | | -import { consola } from 'consola' |
4 | | -import { fetchReleases, fetchRepos } from './utils/github' |
5 | | -import type { GithubRelease } from './types' |
6 | | - |
7 | | -/** |
8 | | - * This script is used to fetch all releases from UnJS packages to create a draft for an article to publish on our blog. |
9 | | - */ |
10 | | -async function main() { |
11 | | - const repos = await fetchRepos() |
12 | | - |
13 | | - const releases = await fetchReleases(repos) |
14 | | - |
15 | | - const today = new Date() |
16 | | - const currentYear = today.getFullYear() |
17 | | - const currentMonth = today.getMonth() + 1 |
18 | | - // Filter releases to only keep the ones from the current year and month |
19 | | - const releasesFromCurrentMonth = releases.reduce((acc, releases) => { |
20 | | - const filtered = releases.releases.filter((release) => { |
21 | | - const releaseDate = new Date(release.publishedAt) |
22 | | - const releaseYear = releaseDate.getFullYear() |
23 | | - const releaseMonth = releaseDate.getMonth() + 1 |
24 | | - |
25 | | - return releaseYear === currentYear && releaseMonth === currentMonth && release.prerelease === false && release.draft === false |
26 | | - }) |
27 | | - |
28 | | - if (filtered.length > 0) { |
29 | | - acc.push({ |
30 | | - ...releases, |
31 | | - releases: filtered, |
32 | | - }) |
33 | | - } |
34 | | - |
35 | | - return acc |
36 | | - }, [] as { name: string, releases: GithubRelease[] }[]).sort((a, b) => a.name.localeCompare(b.name)) |
37 | | - |
38 | | - const numberOfReleases = releasesFromCurrentMonth.reduce((acc, releases) => acc + releases.releases.length, 0) |
39 | | - |
40 | | - // Create the article (draft) |
41 | | - const currentMonthName = today.toLocaleString('default', { month: 'long' }) |
42 | | - const currentDay = today.getDate() |
43 | | - const filename = `${currentYear}-${currentMonth}-${currentDay}-${currentMonthName.toLocaleLowerCase()}-monthly-updates.md` |
44 | | - const title = `Monthly updates (${currentMonthName} ${currentYear})` |
| 1 | +import { writeFileSync } from 'node:fs' |
| 2 | +import { defineCommand } from 'citty' |
| 3 | +import { fetchReleases, fetchRepos } from '../../utils/github' |
| 4 | +import { getCurrentMonth, getCurrentYear } from '../../utils/date' |
| 5 | +import { getBlogPath } from '../../utils/content' |
| 6 | +import type { GithubRelease } from '../../types' |
| 7 | + |
| 8 | +export const releasesArticle = defineCommand({ |
| 9 | + meta: { |
| 10 | + name: 'releases-article', |
| 11 | + description: 'Generate an article with all releases of the current month', |
| 12 | + }, |
| 13 | + async run() { |
| 14 | + const blogPath = getBlogPath() |
| 15 | + |
| 16 | + const currentMonth = getCurrentMonth() |
| 17 | + const currentYear = getCurrentYear() |
| 18 | + |
| 19 | + /** |
| 20 | + * Retrieve correct data |
| 21 | + */ |
| 22 | + |
| 23 | + const repos = await fetchRepos() |
| 24 | + const releases = await fetchReleases(repos) |
| 25 | + |
| 26 | + const currentReleases = releases.reduce((acc, _releases) => { |
| 27 | + const filtered = getMonthReleases(_releases.releases, currentYear, currentMonth) |
| 28 | + |
| 29 | + if (filtered.length) { |
| 30 | + acc.push({ |
| 31 | + ..._releases, |
| 32 | + releases: filtered, |
| 33 | + }) |
| 34 | + } |
45 | 35 |
|
46 | | - const article = /* md */`--- |
| 36 | + return acc |
| 37 | + }, [] as { name: string, releases: GithubRelease[] }[]).sort((a, b) => a.name.localeCompare(b.name)) |
| 38 | + |
| 39 | + const numberOfReleases = currentReleases.reduce((acc, releases) => acc + releases.releases.length, 0) |
| 40 | + |
| 41 | + /** |
| 42 | + * Create the article |
| 43 | + */ |
| 44 | + const today = new Date() |
| 45 | + const currentMonthName = today.toLocaleString('default', { month: 'long' }) |
| 46 | + const currentDay = today.getDate() |
| 47 | + const filename = `${currentYear}-${currentMonth.toLocaleString('en-US', { |
| 48 | + minimumIntegerDigits: 2, |
| 49 | + useGrouping: false, |
| 50 | + })}-${currentDay.toLocaleString('en-US', { |
| 51 | + minimumIntegerDigits: 2, |
| 52 | + useGrouping: false, |
| 53 | + })}-${currentMonthName.toLocaleLowerCase()}-monthly-updates.md` |
| 54 | + const title = `Monthly updates (${currentMonthName} ${currentYear})` |
| 55 | + const article = /* md */`--- |
47 | 56 | title: ${title} |
48 | 57 | description: ${numberOfReleases} releases this month! What's new in the UnJS ecosystem? |
49 | | -image: |
50 | | - src: |
51 | | - alt: |
52 | 58 | authors: |
53 | 59 | - name: |
54 | 60 | picture: |
55 | 61 | twitter: |
56 | 62 | category: |
57 | 63 | - releases |
58 | 64 | packages: |
59 | | - - ${releasesFromCurrentMonth.map(releases => releases.name).join('\n - ')} |
| 65 | + - ${currentReleases.map(releases => releases.name).join('\n - ')} |
60 | 66 | publishedAt: ${today.toISOString()} |
61 | 67 | modifiedAt: ${today.toISOString()} |
62 | | -layout: blog-post |
63 | 68 | --- |
64 | 69 |
|
65 | | -${releasesFromCurrentMonth.map(releases => `## ${releases.name}\n\nThis month, we release ${releases.releases.length} new ${releases.releases.length > 1 ? 'releases' : 'release'} (${logReleasesTypes(releases.releases)}):\n\n${releases.releases.map(release => `- [${release.tag}](https://github.com/unjs/${releases.name}/releases/tag/${release.tag})`).join('\n')}\n\n${formatReleasesMarkdown(releases.releases)}`).join('\n\n')}` |
| 70 | +${currentReleases.map(releases => `## ${releases.name}\n\nThis month, we release ${releases.releases.length} new ${releases.releases.length > 1 ? 'releases' : 'release'} (${logReleasesTypes(releases.releases)}):\n\n${releases.releases.map(release => `- [${release.tag}](https://github.com/unjs/${releases.name}/releases/tag/${release.tag})`).join('\n')}\n\n${formatReleasesMarkdown(releases.releases)}`).join('\n\n')}` |
66 | 71 |
|
67 | | - fs.writeFileSync(`./content/5.blog/${filename}`, article) |
68 | | -} |
| 72 | + // An article is a list of repo where each repo have a list releases and then, the changelog of each release. |
| 73 | + writeFileSync(`${blogPath}/${filename}`, article) |
| 74 | + }, |
| 75 | +}) |
69 | 76 |
|
70 | | -main().then(() => exit(0)).catch(consola.error) |
| 77 | +/** |
| 78 | + * Extract releases from a specific month and year |
| 79 | + */ |
| 80 | +function getMonthReleases(releases: GithubRelease[], year: number, month: number): GithubRelease[] { |
| 81 | + return releases.filter((release) => { |
| 82 | + const releaseDate = new Date(release.publishedAt) |
| 83 | + const releaseYear = releaseDate.getFullYear() |
| 84 | + const releaseMonth = releaseDate.getMonth() + 1 |
| 85 | + |
| 86 | + return releaseYear === year && releaseMonth === month && release.prerelease === false && release.draft === false |
| 87 | + }) |
| 88 | +} |
71 | 89 |
|
72 | 90 | function logReleasesTypes(releases: GithubRelease[]): string { |
73 | 91 | const majorReleases = releases.filter(release => release.tag.endsWith('.0.0')) |
@@ -154,7 +172,7 @@ function formatLine(line: string): string { |
154 | 172 | * Standardize title using h3, removing emoji like π and lowercase |
155 | 173 | */ |
156 | 174 | function formatTitle(line: string): string { |
157 | | - return `### ${line.replace(/#+\s*/, '').replace(/[ππ¨ππ©Ήπ]/u, '').toLowerCase().trim()}` |
| 175 | + return `### ${line.replace(/#+\s*/, '').replace(/[ππ¨ππ©Ήππ
π]/u, '').toLowerCase().trim()}` |
158 | 176 | } |
159 | 177 |
|
160 | 178 | /** |
|
0 commit comments