Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions packages/changesets-cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# @qualcomm-ui/changesets-cli Changelog

## 1.0.2

Apr 11th, 2026

### Code Refactoring

- [changesets-cli]: replace --from-release-tags with --commit-sha option ([440fa24](https://github.com/qualcomm/qualcomm-ui-utils/commit/440fa24))
- [changesets-cli]: rename diff functions for clarity ([440fa24](https://github.com/qualcomm/qualcomm-ui-utils/commit/440fa24))

### Documentation

- [changesets-cli]: update readme with new --commit-sha option ([440fa24](https://github.com/qualcomm/qualcomm-ui-utils/commit/440fa24))

## 1.0.1

Apr 6th, 2026
Expand Down
24 changes: 12 additions & 12 deletions packages/changesets-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ Runs the full release-prep pipeline sequentially:
qui-changesets prep-release [options]
```

| Option | Description | Default |
| ----------------------------- | ----------------------------------------------------------------------------- | ------------------------ |
| `--in-steps` | Pause after each step and wait for confirmation | `false` |
| `--from-release-tags` | Diff each package from its most recent release tag instead of the base branch | `false` |
| `--include-commit-links` | Embed commit hashes in changeset summaries for changelog links | `false` |
| `--package-manager <command>` | Package manager command to use for `changeset version` | `pnpm` |
| `--config <path>` | Path to the changesets config file, relative to the project root | `.changeset/config.json` |
| Option | Description | Default |
| ----------------------------- | ----------------------------------------------------------------------------------- | ------------------------ |
| `--in-steps` | Pause after each step and wait for confirmation | `false` |
| `--commit-sha <sha>` | Diff each package against the target commit instead of the repository's base branch | |
| `--include-commit-links` | Embed commit hashes in changeset summaries for changelog links | `false` |
| `--package-manager <command>` | Package manager command to use for `changeset version` | `pnpm` |
| `--config <path>` | Path to the changesets config file, relative to the project root | `.changeset/config.json` |

### `changeset-generate`

Expand All @@ -41,11 +41,11 @@ Generates changesets from conventional commits without running the full pipeline
qui-changesets changeset-generate [options]
```

| Option | Description | Default |
| ------------------------ | ----------------------------------------------------------------------------- | ------------------------ |
| `--from-release-tags` | Diff each package from its most recent release tag instead of the base branch | `false` |
| `--include-commit-links` | Embed commit hashes in changeset summaries for changelog links | `false` |
| `--config <path>` | Path to the changesets config file, relative to the project root | `.changeset/config.json` |
| Option | Description | Default |
| ------------------------ | ----------------------------------------------------------------------------------- | ------------------------ |
| `--commit-sha` | Diff each package against the target commit instead of the repository's base branch | `false` |
| `--include-commit-links` | Embed commit hashes in changeset summaries for changelog links | `false` |
| `--config <path>` | Path to the changesets config file, relative to the project root | `.changeset/config.json` |

### `consolidate-changelogs`

Expand Down
2 changes: 1 addition & 1 deletion packages/changesets-cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@qualcomm-ui/changesets-cli",
"version": "1.0.1",
"version": "1.0.2",
"description": "Changeset automation CLI for conventional commits",
"author": "Ryan Bower",
"license": "BSD-3-Clause-Clear",
Expand Down
16 changes: 7 additions & 9 deletions packages/changesets-cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ interface Step {
}

function buildSteps(options: {
commitSha?: string
config?: string
fromReleaseTags?: boolean
includeCommitLinks?: boolean
packageManager?: string
}): Step[] {
Expand All @@ -32,8 +32,8 @@ function buildSteps(options: {
name: "changeset-generate",
run: () =>
conventionalCommitChangeset({
commitSha: options.commitSha,
configPath: options.config,
fromReleaseTags: options.fromReleaseTags,
includeCommitLinks: options.includeCommitLinks,
}),
},
Expand Down Expand Up @@ -72,8 +72,8 @@ async function waitForConfirmation(stepName: string): Promise<boolean> {
}

async function run(options: {
commitSha?: string
config?: string
fromReleaseTags?: boolean
includeCommitLinks?: boolean
inSteps?: boolean
packageManager?: string
Expand Down Expand Up @@ -116,9 +116,8 @@ program
false,
)
.option(
"--from-release-tags",
"Diff each package from its most recent release tag instead of the baseBranch from the changesets config",
false,
"--commit-sha <sha>",
"Diff each package against the target commit instead of the repository's base branch",
)
.option(
"--include-commit-links",
Expand All @@ -140,9 +139,8 @@ program
.command("changeset-generate")
.description("Generate changesets from conventional commits")
.option(
"--from-release-tags",
"Diff each package from its most recent release tag instead of the base branch",
false,
"--commit-sha <sha>",
"Diff each package against the target commit instead of the repository's base branch",
)
.option(
"--include-commit-links",
Expand Down
76 changes: 20 additions & 56 deletions packages/changesets-cli/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import {join} from "node:path"
import {
conventionalMessagesWithCommitsToChangesets,
difference,
getCommitsSincePackageRelease,
getCommitsSinceRef,
getCommitsSinceBranch,
getCommitsSinceCommit,
translateCommitsToConventionalCommitMessages,
} from "./utils"

Expand All @@ -33,8 +33,8 @@ function getCommitsWithMessages(commitHashes: string[]) {
}

export interface ChangesetGenerateOptions {
commitSha?: string | undefined
configPath?: string | undefined
fromReleaseTags?: boolean | undefined
includeCommitLinks?: boolean | undefined
}

Expand All @@ -54,59 +54,23 @@ export async function conventionalCommitChangeset(
)

const {baseBranch = "main"} = changesetConfig
const {fromReleaseTags, includeCommitLinks} = options

let changesets

if (fromReleaseTags) {
const allChangesets = packages.flatMap((pkg) => {
const packageName = pkg.packageJson.name
const version = pkg.packageJson.version
if (!packageName || !version) {
return []
}

const commitsSinceRelease = getCommitsSincePackageRelease(
packageName,
version,
baseBranch,
)

const commitsWithMessages = getCommitsWithMessages(commitsSinceRelease)
const changelogMessages =
translateCommitsToConventionalCommitMessages(commitsWithMessages)

return conventionalMessagesWithCommitsToChangesets(changelogMessages, {
ignoredFiles: ignored,
includeCommitLinks,
packages: [pkg],
})
})

changesets = allChangesets.filter(
(changeset, index, self) =>
index ===
self.findIndex(
(c) =>
c.summary === changeset.summary &&
JSON.stringify(c.releases) === JSON.stringify(changeset.releases),
),
)
} else {
const commitsSinceBase = getCommitsSinceRef(baseBranch)
const commitsWithMessages = getCommitsWithMessages(commitsSinceBase)
const changelogMessagesWithAssociatedCommits =
translateCommitsToConventionalCommitMessages(commitsWithMessages)

changesets = conventionalMessagesWithCommitsToChangesets(
changelogMessagesWithAssociatedCommits,
{
ignoredFiles: ignored,
includeCommitLinks,
packages,
},
)
}
const {commitSha, includeCommitLinks} = options

const commitsSinceRef = commitSha
? getCommitsSinceCommit(commitSha)
: getCommitsSinceBranch(baseBranch)
const commitsWithMessages = getCommitsWithMessages(commitsSinceRef)
const changelogMessages =
translateCommitsToConventionalCommitMessages(commitsWithMessages)

const changesets = conventionalMessagesWithCommitsToChangesets(
changelogMessages,
{
ignoredFiles: ignored,
includeCommitLinks,
packages,
},
)

const currentChangesets = await readChangeset(cwd)

Expand Down
76 changes: 11 additions & 65 deletions packages/changesets-cli/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,87 +220,33 @@ export function gitFetch(branch: string) {
}

/**
* Gets the name of the current git branch
* @returns Current branch name
* Gets all commit hashes since a specific commit
* @param sha - The commit SHA to compare against
* @returns Array of commit hashes since the given commit
*/
export function getCurrentBranch() {
return execSync("git rev-parse --abbrev-ref HEAD").toString().trim()
export function getCommitsSinceCommit(sha: string) {
return execSync(`git rev-list ${sha}..HEAD`)
.toString()
.split("\n")
.filter(Boolean)
.reverse()
}

/**
* Gets all commit hashes since a reference branch or tag
* @param branch - The branch to compare against
* @returns Array of commit hashes since the reference point
*/
export function getCommitsSinceRef(branch: string) {
export function getCommitsSinceBranch(branch: string) {
gitFetch(branch)
const currentBranch = getCurrentBranch()
let sinceRef = `origin/${branch}`

if (currentBranch === branch) {
try {
sinceRef = execSync("git describe --tags --abbrev=0").toString()
} catch (e) {
console.log(
"No git tags found, using repo's first commit for automated change detection. Note: this may take a while.",
)
sinceRef = execSync("git rev-list --max-parents=0 HEAD").toString()
}
}

sinceRef = sinceRef.trim()
const sinceRef = `origin/${branch}`
return execSync(`git rev-list ${sinceRef}..HEAD`)
.toString()
.split("\n")
.filter(Boolean)
.reverse()
}

/**
* Checks if a git tag exists
* @param tag - The tag name to check
* @returns True if the tag exists
*/
export function tagExists(tag: string): boolean {
try {
execSync(`git rev-parse --verify refs/tags/${tag}`, {stdio: "pipe"})
return true
} catch {
return false
}
}

/**
* Gets all commit hashes since a package's release tag
* Falls back to the base branch if the release tag doesn't exist
* @param packageName - The package name (e.g., "@qualcomm-ui/angular")
* @param version - The package's current version
* @param baseBranch - The base branch to fall back to
* @returns Array of commit hashes since the release tag or base branch
*/
export function getCommitsSincePackageRelease(
packageName: string,
version: string,
baseBranch: string,
): string[] {
const releaseTag = `${packageName}@${version}`

if (tagExists(releaseTag)) {
return execSync(`git rev-list ${releaseTag}..HEAD`)
.toString()
.split("\n")
.filter(Boolean)
.reverse()
}

gitFetch(baseBranch)
return execSync(`git rev-list origin/${baseBranch}..HEAD`)
.toString()
.split("\n")
.filter(Boolean)
.reverse()
}

/**
* Compares two changesets for equality
* @param a - First changeset
Expand Down
Loading