Repository: igorkamyshev/farfetched
Pull request #258 (2023-02-08 08:15:01)

Improve changelogs
fixes #256 

cloudflare-pages[bot]: ## Deploying with &nbsp;<a href="https://pages.dev"><img alt="Cloudflare Pages" src="https://user-images.githubusercontent.com/23264/106598434-9e719e00-654f-11eb-9e59-6167043cfa01.png" width="16"></a> &nbsp;Cloudflare Pages

<table><tr><td><strong>Latest commit:</strong> </td><td>
<code>b6eda50</code>
</td></tr>
<tr><td><strong>Status:</strong></td><td>&nbsp;✅&nbsp; Deploy successful!</td></tr>
<tr><td><strong>Preview URL:</strong></td><td>
<a href='https://72f97cfd.farfetched.pages.dev'>https://72f97cfd.farfetched.pages.dev</a>
</td></tr>
<tr><td><strong>Branch Preview URL:</strong></td><td>
<a href='https://improve-changelog.farfetched.pages.dev'>https://improve-changelog.farfetched.pages.dev</a>
</td></tr>
</table>

[View logs](https://dash.cloudflare.com/?to=/:account/pages/view/farfetched/72f97cfd-bb85-4ddb-ad69-d910c9d81616)


Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ffdacf4..18dc043 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -26,6 +26,7 @@ jobs:
       - run: pnpm lint:workspace
       - run: pnpm test
       - run: pnpm test:types
+      - run: pnpm test:tools
       - run: pnpm lint
       - run: pnpm build
       - run: pnpm size
diff --git a/apps/website/project.json b/apps/website/project.json
index a2fbc08..7138259 100644
--- a/apps/website/project.json
+++ b/apps/website/project.json
@@ -31,7 +31,7 @@
     "prepare_changelog": {
       "executor": "nx:run-commands",
       "options": {
-        "command": "node tools/scripts/changelog.mjs"
+        "command": "node tools/scripts/changelog/cli.mjs"
       }
     }
   },
diff --git a/package.json b/package.json
index 18529eb..ae37f98 100644
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
     "test": "nx run-many --target=test --all",
     "test:watch": "nx run-many --target=test_watch --all --args=\"--\"",
     "test:types": "nx run-many --target=typetest --all",
+    "test:tools": "vitest run tools",
     "lint": "nx run-many --target=lint --all",
     "lint:format": "nx format:check",
     "lint:workspace": "nx workspace-lint",
diff --git a/tools/scripts/changelog.mjs b/tools/scripts/changelog/cli.mjs
similarity index 84%
rename from tools/scripts/changelog.mjs
rename to tools/scripts/changelog/cli.mjs
index e734375..e93f168 100644
--- a/tools/scripts/changelog.mjs
+++ b/tools/scripts/changelog/cli.mjs
@@ -7,6 +7,8 @@ import { NodeHtmlMarkdown } from 'node-html-markdown';
 import { parseSemVer, compareSemVer } from 'semver-parser';
 import { resolve } from 'node:path';
 
+import { groupByVersions } from './lib.mjs';
+
 const files = await promisify(glob)(
   '{packages,deleted_packages}/*/CHANGELOG.md',
   {
@@ -73,27 +75,30 @@ function mergeChangelogs(packages) {
       .filter(({ changes }) => Object.keys(changes).length > 0);
 
     currentLog.push(['header', { level: 2 }, 'Full changelog']);
-    for (const { name, changes } of relatedChanges) {
+    for (const { version, packages } of groupByVersions(relatedChanges).sort(
+      ({ version: v1 }, { version: v2 }) => -compareSemVer(v1, v2)
+    )) {
       const logForVersion = [];
-      for (const [version, versionChanges] of Object.entries(changes).sort(
-        ([v1], [v2]) => -compareSemVer(v1, v2)
-      )) {
-        const versionChangesEntries = Object.entries(versionChanges);
+      for (const { name: packageName, changes: packageChanges } of packages) {
+        const pacakgeChangesEntries = Object.entries(packageChanges);
 
-        let hasChanges = versionChangesEntries.length > 0;
+        let hasChanges = pacakgeChangesEntries.length > 0;
 
         if (!hasChanges) {
           continue;
         }
-        logForVersion.push(['header', { level: 4 }, version]);
 
-        for (const [type, items] of versionChangesEntries) {
+        logForVersion.push(['para', `::: details ${packageName}`]);
+
+        for (const [type, items] of pacakgeChangesEntries) {
           logForVersion.push(['para', ['strong', type]], ...items);
         }
+
+        logForVersion.push(['para', ':::']);
       }
 
       if (logForVersion.length > 0) {
-        currentLog.push(['header', { level: 3 }, name]);
+        currentLog.push(['header', { level: 3 }, version]);
         currentLog.push(...logForVersion);
       }
     }
diff --git a/tools/scripts/changelog/lib.mjs b/tools/scripts/changelog/lib.mjs
new file mode 100644
index 0000000..ee49cc2
--- /dev/null
+++ b/tools/scripts/changelog/lib.mjs
@@ -0,0 +1,22 @@
+export function groupByVersions(packages) {
+  const groupedByVersions = [];
+
+  for (const { name, changes } of packages) {
+    for (const [version, versionChanges] of Object.entries(changes)) {
+      const versionGroup = groupedByVersions.find(
+        (group) => group.version === version
+      );
+
+      if (versionGroup) {
+        versionGroup.packages.push({ name, changes: versionChanges });
+      } else {
+        groupedByVersions.push({
+          version,
+          packages: [{ name, changes: versionChanges }],
+        });
+      }
+    }
+  }
+
+  return groupedByVersions;
+}


Test patch:
diff --git a/tools/scripts/changelog/lib.test.js b/tools/scripts/changelog/lib.test.js
new file mode 100644
index 0000000..b286494
--- /dev/null
+++ b/tools/scripts/changelog/lib.test.js
@@ -0,0 +1,195 @@
+import { describe, test, expect } from 'vitest';
+
+import { groupByVersions } from './lib.mjs';
+
+describe('groupByVersion', () => {
+  test('correct grouping', () => {
+    const changes = [
+      {
+        name: '@farfetched/core',
+        changes: {
+          '0.6.4': {
+            'Patch Changes': [
+              [
+                'bulletlist',
+                [
+                  'listitem',
+                  '5da04bf: Fix type inference in ',
+                  ['inlinecode', 'createQuery'],
+                  ' in ',
+                  ['inlinecode', 'effect'],
+                  ' and ',
+                  ['inlinecode', 'mapData'],
+                  ' overload',
+                ],
+              ],
+            ],
+          },
+          '0.6.3': {},
+          '0.6.2': {
+            'Patch Changes': [
+              [
+                'bulletlist',
+                [
+                  'listitem',
+                  '05b4860: Fix ',
+                  ['inlinecode', 'cache'],
+                  ' invalidation after ',
+                  ['inlinecode', 'update'],
+                ],
+              ],
+            ],
+          },
+          '0.6.1': {
+            'Patch Changes': [
+              [
+                'bulletlist',
+                [
+                  'listitem',
+                  'c2b67a6: Fix ',
+                  ['inlinecode', 'cache'],
+                  ' overlapping in ',
+                  ['inlinecode', 'createJsonQuery'],
+                ],
+              ],
+            ],
+          },
+        },
+      },
+      {
+        name: '@farfetched/solid',
+        changes: {
+          '0.6.4': {},
+          '0.6.3': {
+            'Patch Changes': [
+              [
+                'bulletlist',
+                [
+                  'listitem',
+                  '0a45391: Re-trigger resource after ',
+                  ['inlinecode', 'update'],
+                  ' a ',
+                  ['em', 'Query'],
+                ],
+              ],
+            ],
+          },
+          '0.6.2': {},
+          '0.6.1': {},
+        },
+      },
+    ];
+
+    const result = groupByVersions(changes);
+
+    expect(result).toEqual([
+      {
+        version: '0.6.4',
+        packages: [
+          {
+            name: '@farfetched/core',
+            changes: {
+              'Patch Changes': [
+                [
+                  'bulletlist',
+                  [
+                    'listitem',
+                    '5da04bf: Fix type inference in ',
+                    ['inlinecode', 'createQuery'],
+                    ' in ',
+                    ['inlinecode', 'effect'],
+                    ' and ',
+                    ['inlinecode', 'mapData'],
+                    ' overload',
+                  ],
+                ],
+              ],
+            },
+          },
+          {
+            name: '@farfetched/solid',
+            changes: {},
+          },
+        ],
+      },
+      {
+        version: '0.6.3',
+        packages: [
+          {
+            name: '@farfetched/core',
+            changes: {},
+          },
+          {
+            name: '@farfetched/solid',
+            changes: {
+              'Patch Changes': [
+                [
+                  'bulletlist',
+                  [
+                    'listitem',
+                    '0a45391: Re-trigger resource after ',
+                    ['inlinecode', 'update'],
+                    ' a ',
+                    ['em', 'Query'],
+                  ],
+                ],
+              ],
+            },
+          },
+        ],
+      },
+      {
+        version: '0.6.2',
+        packages: [
+          {
+            name: '@farfetched/core',
+            changes: {
+              'Patch Changes': [
+                [
+                  'bulletlist',
+                  [
+                    'listitem',
+                    '05b4860: Fix ',
+                    ['inlinecode', 'cache'],
+                    ' invalidation after ',
+                    ['inlinecode', 'update'],
+                  ],
+                ],
+              ],
+            },
+          },
+          {
+            name: '@farfetched/solid',
+            changes: {},
+          },
+        ],
+      },
+      {
+        version: '0.6.1',
+        packages: [
+          {
+            name: '@farfetched/core',
+            changes: {
+              'Patch Changes': [
+                [
+                  'bulletlist',
+                  [
+                    'listitem',
+                    'c2b67a6: Fix ',
+                    ['inlinecode', 'cache'],
+                    ' overlapping in ',
+                    ['inlinecode', 'createJsonQuery'],
+                  ],
+                ],
+              ],
+            },
+          },
+          {
+            name: '@farfetched/solid',
+            changes: {},
+          },
+        ],
+      },
+    ]);
+  });
+});