-
Notifications
You must be signed in to change notification settings - Fork 222
ci: global changelog generator script #5328
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Rajdeepc
wants to merge
16
commits into
main
Choose a base branch
from
rajdeep/changelog-global
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 13 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
a0f6e3e
ci: updated global changelog
a2f863c
Merge branch 'main' into rajdeep/changelog-global
blunteshwar 9ccb88d
chore: improve global changelog script
blunteshwar 2bf08d8
chore: update changelog
blunteshwar a849b21
Merge branch 'main' into rajdeep/changelog-global
Rajdeepc 73df35a
Merge branch 'main' into rajdeep/changelog-global
Rajdeepc 24edcd7
chore: updated method call
ef8f7bb
Merge branch 'main' into rajdeep/changelog-global
blunteshwar cab24b0
ci: added new global script to handle changelog
03ba768
chore: updated script file name
a9d421c
ci: added failsafe check for new version
9cf280c
Merge branch 'main' into rajdeep/changelog-global
5050e77
chore: reset changelog
bf0afbd
chore: updated jsdoc for createGLobalChange function
7de437d
chore: updated jsdoc for createGLobalChange function
eb64182
Merge branch 'main' into rajdeep/changelog-global
Rajdeepc File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
/* | ||
Copyright 2025 Adobe. All rights reserved. | ||
This file is licensed to you under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. You may obtain a copy | ||
of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software distributed under | ||
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS | ||
OF ANY KIND, either express or implied. See the License for the specific language | ||
governing permissions and limitations under the License. | ||
|
||
*/ | ||
|
||
import fs from 'fs'; | ||
import { execSync } from 'child_process'; | ||
import { fileURLToPath } from 'url'; | ||
import path from 'path'; | ||
import { version as newVersion } from '@spectrum-web-components/base/src/version.js'; | ||
|
||
const __dirname = path.dirname(fileURLToPath(import.meta.url)); | ||
castastrophe marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const repoUrl = 'https://github.com/adobe/spectrum-web-components'; | ||
|
||
async function createGlobalChangelog() { | ||
Rajdeepc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (!newVersion) { | ||
console.error('Error: newVersion is undefined or empty'); | ||
process.exit(1); | ||
} | ||
const newTag = `v${newVersion}`; | ||
castastrophe marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let prevTag; | ||
try { | ||
const gitTagOutput = execSync('git tag --sort=-creatordate'); | ||
if (!gitTagOutput) { | ||
throw new Error('Git tag command returned empty output'); | ||
} | ||
|
||
const tagList = gitTagOutput.toString().split('\n').filter(Boolean); | ||
if (tagList.length === 0) { | ||
throw new Error('No git tags found in repository'); | ||
} | ||
|
||
prevTag = tagList.find((tag) => tag !== newTag); | ||
if (!prevTag) { | ||
throw new Error( | ||
'Could not find a previous tag different from the new tag' | ||
); | ||
} | ||
} catch (error) { | ||
console.error(`Failed to get previous git tag: ${error.message}`); | ||
process.exit(1); | ||
} | ||
|
||
if (!prevTag) { | ||
console.error('No previous tag found.'); | ||
process.exit(1); | ||
} | ||
|
||
// Read the existing CHANGELOG.md early to check for existing entries | ||
const changelogPath = path.resolve(__dirname, '../CHANGELOG.md'); | ||
let existingChangelog = fs.existsSync(changelogPath) | ||
? fs.readFileSync(changelogPath, 'utf-8') | ||
: ''; | ||
|
||
// Check if this version already has an entry in the changelog | ||
const versionEntryPattern = new RegExp( | ||
`# \\[${newVersion.replace(/\./g, '\\.')}\\]` | ||
); | ||
if (versionEntryPattern.test(existingChangelog)) { | ||
console.log( | ||
`⚠️ Version ${newVersion} already has an entry in the CHANGELOG. Skipping update.` | ||
); | ||
process.exit(0); | ||
} | ||
|
||
const date = new Date().toLocaleDateString('en-CA', { | ||
year: 'numeric', | ||
month: '2-digit', | ||
day: '2-digit', | ||
}); | ||
// We need to use a stable release tag (not a pre-release/beta) for the comparison URL | ||
// to ensure the changelog shows changes between proper semver releases | ||
const compareUrl = `${repoUrl}/compare/${prevTag}...${newTag}`; | ||
// Read all changesets from the .changeset directory | ||
const changesetDir = path.resolve(__dirname, '../.changeset'); | ||
const changesetFiles = fs | ||
.readdirSync(changesetDir) | ||
.filter((file) => file.endsWith('.md') && file !== 'README.md'); | ||
|
||
const majorChanges = []; | ||
const minorChanges = []; | ||
const patchChanges = []; | ||
|
||
// Process each changeset file | ||
for (const file of changesetFiles) { | ||
const filePath = path.join(changesetDir, file); | ||
const content = fs.readFileSync(filePath, 'utf-8'); | ||
|
||
// Extract the frontmatter from the changeset | ||
const frontmatterMatch = content.match( | ||
/---\n([\s\S]*?)\n---\n([\s\S]*)/ | ||
); | ||
|
||
if (frontmatterMatch) { | ||
const [, frontmatter, description] = frontmatterMatch; | ||
|
||
// Parse the frontmatter to determine the change type | ||
console.log(frontmatter); | ||
const isMajor = frontmatter.includes('major'); | ||
const isMinor = frontmatter.includes('minor'); | ||
// If not major or minor, it's a patch | ||
|
||
// Extract the package scope from the frontmatter | ||
const packageMatch = frontmatter.match( | ||
/'@spectrum-web-components\/([^']+)':|"@spectrum-web-components\/([^"]+)":/ | ||
); | ||
// Extract component name from package name and prefix with "sp-" | ||
const scope = packageMatch ? `sp-${packageMatch[1]}` : 'core'; | ||
// Clean up the description text | ||
const cleanDescription = description.trim(); | ||
|
||
// Create the entry (without commit hash since we're using changesets) | ||
const entry = `**${scope}**: ${cleanDescription}\n\n`; | ||
|
||
// Categorize based on semver bump type | ||
if (isMajor) { | ||
majorChanges.push(entry); | ||
} else if (isMinor) { | ||
minorChanges.push(entry); | ||
} else { | ||
patchChanges.push(entry); | ||
} | ||
} | ||
} | ||
|
||
// Skip if nothing relevant | ||
if (!majorChanges.length && !minorChanges.length && !patchChanges.length) { | ||
console.log('🚫 No changes to add to the changelog.'); | ||
process.exit(0); | ||
} | ||
|
||
// Format new changelog entry | ||
let newEntry = `# [${newVersion}](${compareUrl}) (${date})\n\n`; | ||
|
||
if (majorChanges.length) { | ||
newEntry += `## Major Changes\n\n${majorChanges.join('\n')}\n\n`; | ||
} | ||
|
||
if (minorChanges.length) { | ||
newEntry += `## Minor Changes\n\n${minorChanges.join('\n')}\n\n`; | ||
} | ||
|
||
if (patchChanges.length) { | ||
newEntry += `## Patch Changes\n\n${patchChanges.join('\n')}\n\n`; | ||
} | ||
|
||
// Preserve the header if it exists | ||
let headerText = ''; | ||
const headerMatch = existingChangelog.match( | ||
/^(# Change Log\n\n[\s\S]+?(?=\n\n# \[))/ | ||
); | ||
if (headerMatch) { | ||
headerText = headerMatch[1]; | ||
existingChangelog = existingChangelog.substring(headerMatch[0].length); | ||
} else if (existingChangelog.startsWith('# Change Log')) { | ||
// Handle case where there might not be any versions yet | ||
const simpleHeaderMatch = existingChangelog.match( | ||
/^(# Change Log\n\n[\s\S]+?)(?=\n\n|$)/ | ||
); | ||
if (simpleHeaderMatch) { | ||
headerText = simpleHeaderMatch[1]; | ||
existingChangelog = existingChangelog.substring(headerText.length); | ||
} | ||
} | ||
|
||
fs.writeFileSync( | ||
changelogPath, | ||
`${headerText}\n\n${newEntry.trim()}\n\n${existingChangelog.trim()}`, | ||
'utf-8' | ||
); | ||
console.log(`✅ CHANGELOG updated for ${newVersion}`); | ||
} | ||
|
||
createGlobalChangelog().catch((error) => { | ||
console.error('Error updating changelog:', error); | ||
process.exit(1); | ||
}); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn’t
yarn changelog:global
be executed beforeyarn changeset version
? This is becauseyarn changelog:global
reads from changeset files located in the.changeset
directory. However, after runningyarn changeset version
, all the changesets are removed/deleted, and the changelogs are populated. Consequently,yarn changelog:global
will no longer be able to read the changeset files in the.changeset
directory.