-
-
Notifications
You must be signed in to change notification settings - Fork 4
Fix bug introduced to updateChangelog in #158
#181
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
Conversation
d973245 to
4e8abf3
Compare
- `updateChangelog` returns results even if `isReleaseCandidate` is false
2103825 to
4cedf60
Compare
updateChangelog in #158 and write testsupdateChangelog in #158
4cedf60 to
aeabb00
Compare
| const newChangelogContent = changelog.toString(); | ||
| const isChangelogUpdated = changelogContent !== newChangelogContent; | ||
| return isChangelogUpdated ? newChangelogContent : undefined; |
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.
update() in cli.ts expects that updateChangelog return undefined if there are no updates to be added to the changelog.
| if ( | ||
| newCommits.length === 0 && | ||
| (!isReleaseCandidate || hasUnreleasedChanges) | ||
| ) { | ||
| return undefined; | ||
| } |
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.
Previously, the undefined return branch was located here.
| const commitRange = | ||
| mostRecentTag === null ? 'HEAD' : `${mostRecentTag}..HEAD`; | ||
| const commitsHashesSinceLastRelease = await getCommitHashesInRange( | ||
| commitRange, | ||
| projectRootDirectory, | ||
| ); | ||
| const commits = await getCommits(commitsHashesSinceLastRelease); | ||
|
|
||
| const loggedPrNumbers = getAllLoggedPrNumbers(changelog); | ||
| const newCommits = commits.filter( | ||
| ({ prNumber }) => | ||
| prNumber === undefined || !loggedPrNumbers.includes(prNumber), | ||
| ); |
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.
This section is moved to getNewChangeEntries().
| const newChangeEntries = newCommits.map(({ prNumber, description }) => { | ||
| if (prNumber) { | ||
| const suffix = `([#${prNumber}](${repoUrl}/pull/${prNumber}))`; | ||
| return `${description} ${suffix}`; | ||
| } | ||
| return description; | ||
| }); |
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.
This section is moved to getNewChangeEntries().
| }); | ||
|
|
||
| // Ensure we have all tags on remote | ||
| await runCommand('git', ['fetch', '--tags']); |
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.
This line is moved to getMostRecentTag().
| } | ||
|
|
||
| if (mostRecentTag === `${tagPrefixes[0]}${currentVersion ?? ''}`) { | ||
| if (mostRecentTag === `${tagPrefixes[0]}${currentVersion}`) { |
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.
currentVersion is narrowed to string thanks to the if (!currentVersion) block being moved directly above. Previously as string or ?? '' was required.
| .getReleases() | ||
| .find((release) => release.version === currentVersion) | ||
| ) { | ||
| changelog.addRelease({ version: currentVersion }); |
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.
currentVersion is correctly narrowed due to all related branches being refactored to fall under the if (isReleaseCandidate) block instead of there being multiple if (isReleaseCandidate &&) blocks. currentVersion as Version casting is now unnecessary.
| category: ChangeCategory.Uncategorized, | ||
| description, | ||
| }); | ||
| } |
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.
This is the bracket that caused the bug. Moving it to above the getNewChangeEntries call resolves the error.
kanthesha
left a comment
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.
Overall looks good. Few minor suggestions.
| projectRootDirectory, | ||
| }: AddNewCommitsOptions) { | ||
| const commitRange = | ||
| mostRecentTag === null ? 'HEAD' : `${mostRecentTag}..HEAD`; |
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.
is there a possibility to be little more flexible here!
| mostRecentTag === null ? 'HEAD' : `${mostRecentTag}..HEAD`; | |
| !mostRecentTag ? 'HEAD' : `${mostRecentTag}..HEAD`; |
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.
Thanks for pointing these out! Unfortunately, this one results in a linter error:
Unexpected negated condition. eslint(no-negated-condition)
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.
How about this?
| mostRecentTag === null ? 'HEAD' : `${mostRecentTag}..HEAD`; | |
| mostRecentTag ? `${mostRecentTag}..HEAD` : 'HEAD'; |
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.
That would work, but I would prefer to prioritize type safety over brevity here, since mostRecentTag is derived from the output of running an actual git command in shell. There are no strong guarantees on what the runtime output will be, so we can't completely rule out edge cases where e.g. an empty string or undefined is returned.
This probably aligns with the original motivation for getMostRecentTag returning null in its early exit branch. It represents the exception case where we know for sure that no tag exists, which is distinct from the error case where some tags exist, but the most recent tag could not be found due to a failure or edge case. This second case would be better represented by an undefined.
What are your thoughts? In general, I feel less comfortable replacing === null with !, because our codebase mostly uses undefined, which makes me assume that any null usage is intentional.
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.
Hmm, we did use null intentionally to represent lack of a most recent tag, so the use of null matches the type that getMostRecentTag returns. However, I suppose that the tag name could be an empty string in theory if for some reason git describe returns an empty string, and that case we would want to fall back to HEAD. So, we could update getMostRecentTag to just return string instead of string | null, except that in case there is no recent tag, it would then return '';. That might look strange, but we could add a comment saying why we're doing that or give that empty string a name that describe its purpose.
In any case, it seems that this line was merely copied from another function, so maybe we want to make that change in another PR?
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.
I like using null for clear distinction and visibility, but in any case I agree with revisiting this in its own ticket since this wasn't a change introduced by this PR.
5bd3d65 to
3aef0c9
Compare
mcmire
left a comment
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.
Hopefully in writing the tests no bugs are revealed, but comparing this to the original version, this makes sense to me.
| projectRootDirectory, | ||
| }: AddNewCommitsOptions) { | ||
| const commitRange = | ||
| mostRecentTag === null ? 'HEAD' : `${mostRecentTag}..HEAD`; |
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.
Hmm, we did use null intentionally to represent lack of a most recent tag, so the use of null matches the type that getMostRecentTag returns. However, I suppose that the tag name could be an empty string in theory if for some reason git describe returns an empty string, and that case we would want to fall back to HEAD. So, we could update getMostRecentTag to just return string instead of string | null, except that in case there is no recent tag, it would then return '';. That might look strange, but we could add a comment saying why we're doing that or give that empty string a name that describe its purpose.
In any case, it seems that this line was merely copied from another function, so maybe we want to make that change in another PR?
| } | ||
|
|
||
| if (mostRecentTag === `${tagPrefixes[0]}${currentVersion ?? ''}`) { | ||
| if (mostRecentTag === `${tagPrefixes[0]}${currentVersion}`) { |
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.
Hmm, I just realized that we only use the first tag prefix here, which seems strange. This may be a potential bug. But we can investigate that 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.
The jsdoc does specify that the first prefix is the intended prefix and the rest are fallbacks. parseChangelog also only uses the first prefix.
getMostRecentTag does iterate over the tagPrefix list. It should return the used prefix, or we could extract the prefix from the returned most recent tag.
But this also wasn't a change introduced in this PR, so it should get its own ticket.
Motivation
#158 incorrectly refactored the branches in updateChangelog, resulting in a state where new changelog entries weren't added to the return value if isReleaseCandidate is false.
Explanation
References
updateChangelogdoes nothing ifisReleaseCandidateisfalse#180updateChangelogand write comprehensive unit tests #188