diff --git a/README.md b/README.md index e049435..55afa62 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,8 @@ npx skills add https://github.com/codebeltnet/agentic --skill git-repo-digest npx skills add https://github.com/codebeltnet/agentic --skill trunk-first-repo npx skills add https://github.com/codebeltnet/agentic --skill dotnet-strong-name-signing npx skills add https://github.com/codebeltnet/agentic --skill dotnet-new-app-slnx -npx skills add https://github.com/codebeltnet/agentic --skill dotnet-new-lib-slnx +npx skills add https://github.com/codebeltnet/agentic --skill dotnet-new-lib-slnx +npx skills add https://github.com/codebeltnet/agentic --skill git-remote-release # npx skills add https://github.com/codebeltnet/agentic --skill another-skill ``` @@ -91,7 +92,8 @@ npx skills add https://github.com/codebeltnet/agentic --skill dotnet-new-lib-sln | [dotnet-new-lib-slnx](skills/dotnet-new-lib-slnx/SKILL.md) | Scaffold a new .NET NuGet library solution following codebeltnet engineering conventions. Dynamic defaults for TFM/repository metadata, latest-stable NuGet package resolution, tuning projects plus a tooling-based benchmark runner, TFM-aware test environments, strong-name signing, NuGet packaging, DocFX documentation, CI/CD pipeline, and code quality tooling. | | [dotnet-new-app-slnx](skills/dotnet-new-app-slnx/SKILL.md) | Scaffold a new .NET standalone application solution following codebeltnet engineering conventions. Supports Console, Web, and Worker host families with Startup or Minimal hosting patterns; Web expands into Empty Web, Web API, MVC, or Web App / Razor, plus functional tests and a simplified CI pipeline. | | [trunk-first-repo](skills/trunk-first-repo/SKILL.md) | Initialize a git repository following [scaled trunk-based development](https://trunkbaseddevelopment.com/#scaled-trunk-based-development). Seeds an empty `main` branch and creates a versioned feature branch (`v0.1.0/init`), enforcing a PR-first workflow where content only reaches main through peer-reviewed pull requests. | -| [dotnet-strong-name-signing](skills/dotnet-strong-name-signing/SKILL.md) | Generate a strong name key (`.snk`) file for signing .NET assemblies using pure .NET cryptography — no Visual Studio Developer PowerShell or `sn.exe` required. Works in any terminal. Defaults to 1024-bit RSA (matching `sn.exe`), with 2048 and 4096 available as options. | +| [dotnet-strong-name-signing](skills/dotnet-strong-name-signing/SKILL.md) | Generate a strong name key (`.snk`) file for signing .NET assemblies using pure .NET cryptography — no Visual Studio Developer PowerShell or `sn.exe` required. Works in any terminal. Defaults to 1024-bit RSA (matching `sn.exe`), with 2048 and 4096 available as options. | +| [git-remote-release](skills/git-remote-release/SKILL.md) | Generate GitHub release notes by summarizing all commits and pull requests between two Git tags or branches in a remote GitHub repository. Accepts a compare URL or separate owner/repo, previous ref, and current ref values; falls back to comparing the current branch against the upstream default branch when no input is provided. Produces a human-friendly `## What's Changed` summary with optional GitHub alert blocks, a `Sources:` section preserving PR and commit references, and a full changelog compare link. | ### Copyable Install Commands @@ -165,10 +167,16 @@ npx skills add https://github.com/codebeltnet/agentic --skill trunk-first-repo `dotnet-strong-name-signing` -```bash -npx skills add https://github.com/codebeltnet/agentic --skill dotnet-strong-name-signing -``` - +```bash +npx skills add https://github.com/codebeltnet/agentic --skill dotnet-strong-name-signing +``` + +`git-remote-release` + +```bash +npx skills add https://github.com/codebeltnet/agentic --skill git-remote-release +``` + ### Why git-visual-commits? Commit messages are the most-read documentation in any codebase — yet they're usually an afterthought. "fix stuff", "wip", "address PR feedback" tells you nothing six months later. Writing good commits takes discipline, and when you're in flow, it's the first thing that slips. @@ -468,8 +476,26 @@ Most repositories start with `git init` followed by committing everything direct - **Review from day one** — no "we'll add branch protection later" that never happens - **Clean, meaningful history** — main tells the story of reviewed, approved changes - **Version-aware branches** — `v0.0.1/spike-auth` vs `v1.0.0/release-prep` signals project maturity at a glance -- **Zero-friction setup** — one skill invocation, not a 10-step checklist - +- **Zero-friction setup** — one skill invocation, not a 10-step checklist + +### Why git-remote-release? + +Writing release notes is tedious. Raw commit logs are too noisy, PR titles often lack context, and the best release notes explain what changed and why it matters — not just what was merged. That gap between "here are the commits" and "here is what this release means for you" is where **git-remote-release** fits. + +**git-remote-release** reads all commits and pull requests between two tags or branches in a remote GitHub repository and produces a polished, paste-ready release note. + +- **Remote-first workflow** that works entirely through GitHub's API, with no local clone required, +- **Compare URL awareness** where a pasted GitHub compare URL is used to extract the owner, repository, and both tags, +- **Pull request-preferred analysis** that uses rich PR metadata when available and gracefully falls back to raw commits, +- **Default-branch-aware comparisons** that resolve the upstream base and collect only commits on the current branch, +- **Effect-oriented summaries** that explain what users and maintainers can expect from the release, not just what code was merged, +- **Thematic grouping** where related changes are discussed together instead of listed chronologically, +- **GitHub alert blocks** that use `NOTE`, `TIP`, `IMPORTANT`, `WARNING`, and `CAUTION` alerts sparingly and only when the release data supports the attention level, +- **Source preservation** where every release note includes a `Sources:` section with the original PR and commit references, +- **Strict format** that always starts with `## What's Changed` and always ends with the full changelog compare link, +- **No invented claims** so every statement in the summary is backed by the commits and pull requests collected, +- **Read-only operation** that never mutates repository state. + ## Repository structure ``` diff --git a/skills/git-remote-release/FORMS.md b/skills/git-remote-release/FORMS.md new file mode 100644 index 0000000..703c8d6 --- /dev/null +++ b/skills/git-remote-release/FORMS.md @@ -0,0 +1,40 @@ +# Parameter Form + +Collect input values, present a summary, and ask for confirmation before generating release notes. + +## Fields + +### compare_url +- **type:** text +- **required:** no +- **prompt:** Do you have a GitHub compare URL? (e.g. `https://github.com/owner/repo/compare/v1.0.0...v1.0.1`) When provided, all other fields are inferred automatically. + +### repository +- **type:** text +- **required:** yes (unless compare_url is provided or using default resolution) +- **prompt:** Which GitHub repository? Use `owner/repo` format (e.g. `codebeltnet/agentic`). + +### previous_ref +- **type:** text +- **required:** yes (unless compare_url is provided or using default resolution) +- **prompt:** What is the previous tag or branch to compare from? (e.g. `v1.0.0` or `main`) + +### current_ref +- **type:** text +- **required:** yes (unless compare_url is provided or using default resolution) +- **prompt:** What is the current tag or branch to compare to? (e.g. `v1.0.1` or `feature/my-branch`) + +## Presentation Rules + +0. If the user provided no input at all (no URL, no repository, no tags or branches), skip this form entirely and proceed directly to the Default Resolution Behavior defined in `SKILL.md`. Do not prompt for individual fields. +1. If the user provided a compare URL, parse it and present the inferred values: + ``` + Ready to generate release notes: + Repository: {owner}/{repo} + Previous: {previousRef} + Current: {currentRef} + ``` + Then ask: "Ready to proceed? (yes / no)" +2. If the user provided separate values, present them in the same summary format, then ask: "Ready to proceed? (yes / no)" +3. If any required value is missing and the user did provide partial input, ask for it individually before presenting the summary. +4. After confirmation, proceed immediately to data collection. diff --git a/skills/git-remote-release/SKILL.md b/skills/git-remote-release/SKILL.md new file mode 100644 index 0000000..1610c65 --- /dev/null +++ b/skills/git-remote-release/SKILL.md @@ -0,0 +1,351 @@ +--- +name: git-remote-release +description: > + Generate GitHub release notes by summarizing all commits and pull requests between two Git tags, branches, or the current branch and the upstream default branch. Use when the user asks to write release notes, generate release notes, draft a GitHub release, create release notes from tags, summarize changes between versions, summarize the current branch, or provides a GitHub compare URL. Trigger phrases: "release notes", "generate release notes", "what changed between", "summarize changes from v1 to v2", "GitHub release", "summarize this branch", compare URLs like "github.com/owner/repo/compare/v1...v2". When no explicit input is given, detects the current branch and compares against the upstream default branch automatically. +--- + +# Git Remote Release + +![Git Remote Release](assets/hero.jpg) + +This skill generates polished GitHub release notes from the commits and pull requests between two tags, two branches, or the current branch and the upstream default branch. It produces a human-friendly summary optimized for release notes, not a raw commit log. + +When explicit tags or a compare URL are provided, the skill works entirely through GitHub's API — no local clone is needed. When no input is provided, the skill detects the current Git working repository and resolves the comparison range from local branch and remote state. + +## Input + +The skill accepts input in three ways, checked in this order: + +**1. Compare URL:** + +When the user provides a GitHub compare URL like `https://github.com/codebeltnet/agentic/compare/v1.0.0...v1.0.1`, extract the owner, repository, previous ref, and current ref from it. + +**2. Separate values:** + +- Repository in `owner/repo` format (e.g. `codebeltnet/agentic`) +- Previous ref — a tag (e.g. `v1.0.0`) or branch name +- Current ref — a tag (e.g. `v1.0.1`) or branch name + +**3. Default resolution (no input provided):** + +When the user does not provide an explicit repository, tag range, compare URL, or branch name, the skill operates on the current Git working repository. See **Default Resolution Behavior** below. + +If any required value is missing and cannot be inferred or resolved, ask the user for it before proceeding. + +## Default Resolution Behavior + +If the user does not provide an explicit repository, tag range, compare URL, branch name, or release range, the skill must operate on the current Git working repository. + +In that case, the skill must: + +1. Detect the current branch. +2. Detect the upstream remote for the repository. +3. Detect the upstream repository's default branch — usually `main`, but do not assume `main` if the remote default branch can be resolved. +4. Compare the current branch against the upstream remote default branch. +5. Include all commits on the current branch that are not present in the upstream remote default branch. +6. Include all contributors represented by those commits or associated pull requests. +7. Generate the release-note optimized summary from that comparison. + +The default comparison should be conceptually equivalent to: + +```text +upstream/default-branch...current-branch +``` + +For example, if the current branch is `feature/git-remote-release` and the upstream default branch is `main`, the comparison should be treated as: + +```text +upstream/main...feature/git-remote-release +``` + +If the repository uses `origin` as the upstream remote, use: + +```text +origin/main...current-branch +``` + +If the repository has both `origin` and `upstream`, prefer the remote that represents the canonical source repository. In fork-based workflows, this is usually `upstream`. In single-repository workflows, this is usually `origin`. + +The skill must not silently assume the wrong base branch. If the default branch cannot be resolved, fall back in this order: + +1. `origin/HEAD` +2. `upstream/HEAD` +3. `origin/main` +4. `origin/master` +5. `upstream/main` +6. `upstream/master` + +If none of these can be resolved, ask the user to provide the base branch or compare URL. + +Useful commands for default resolution: + +```bash +git rev-parse --abbrev-ref HEAD +git remote +git symbolic-ref refs/remotes/origin/HEAD --short +git symbolic-ref refs/remotes/upstream/HEAD --short +git merge-base HEAD {resolvedBase} +git log --oneline {resolvedBase}..HEAD +``` + +## Contributor Handling + +Contributor attribution should be based on available GitHub metadata when possible. If GitHub metadata is unavailable, use Git commit author information. + +The `Sources:` section must preserve contributor attribution using this format when a GitHub username is available: + +``` +* by @<author> in <pull-request-or-commit-url> +``` + +If a GitHub username is unavailable, use the commit author name without the `@` prefix: + +``` +* <title> by <author-name> in <commit-url-or-sha> +``` + +When using the current branch default behavior, the skill must include all contributors involved in the detected commits and pull requests. Do not collapse contributor attribution in a way that hides who contributed to the release. + +## Workflow + +### Step 1: Resolve the input parameters + +Determine which input path applies: + +- **Compare URL provided:** Extract owner, repository, previous ref, and current ref from the URL. +- **Separate values provided:** Use the supplied repository, previous ref, and current ref. +- **No input provided:** Follow the Default Resolution Behavior to detect the current branch, upstream remote, and base branch from the local Git working repository. + +Validate that the repository exists and both refs are reachable before continuing. + +### Step 2: Collect commits in the comparison range + +Fetch all commits included in the range `previousRef...currentRef` using the GitHub API or local Git commands. For each commit, collect: + +- Commit SHA +- Commit message (subject and body) +- Author login + +### Step 3: Collect pull requests + +For each commit in the range, determine whether it belongs to a merged pull request. Prefer pull request metadata over raw commit data when available, because PRs carry richer context: descriptions, labels, review discussions, and linked issues. + +Collect unique pull requests only. If multiple commits map to the same pull request, record that pull request once and preserve all contributing commits through the single PR source entry. + +For each pull request, collect: + +- PR number and title +- Author login +- PR URL +- PR description/body +- Labels +- Files changed (when available and relevant) + +Use commits directly only when: + +- A commit is not associated with a pull request +- Pull request metadata is unavailable +- The change was committed directly to the release branch + +### Step 4: Analyze and summarize + +Read through all collected pull requests and commits. Understand what changed, why it matters, and how it affects users and maintainers. Group related changes together. Identify breaking changes, new features, bug fixes, dependency updates, CI/CD changes, documentation updates, and infrastructure work. + +The summary should explain the effect of the changes, not just the implementation. A good release note tells users what they can expect from this version, not just what code was modified. + +### Step 5: Compose the release notes + +Follow the exact output format defined below. Every release note must start with `## What's Changed` and end with the full changelog link. Nothing may appear after the changelog link. + +## Output Format + +```markdown +## What's Changed + +<optimized-summary> + +<optional-alert-blocks> + +Sources: + +* <title> by @<author> in <url> +* <title> by @<author> in <url> + +**Full Changelog**: https://github.com/{owner}/{repo}/compare/{previousRef}...{currentRef} +``` + +### The summary section + +The summary is the heart of the release note. It must be: + +- **Human-friendly** — written for someone scanning the release to understand what changed +- **Effect-oriented** — explains what users and maintainers can expect, not just what was modified +- **Evidence-backed** — every claim must be supported by the commits or pull requests collected +- **Grouped logically** — related changes are discussed together, not listed chronologically +- **Honest** — no invented impact, no unsupported claims, no vague filler like "various improvements" + +For small releases (a handful of changes), prefer a concise paragraph or short bullet list. + +For larger releases, prefer grouped bullets organized by theme: new features, fixes, infrastructure, breaking changes, etc. + +Avoid simply repeating PR titles or commit messages unless they are already clear and release-note friendly. Rewrite them into prose that explains the effect. + +### Key capabilities formatting (when included) + +When the release note includes a "Key capabilities" section, each bullet must be written as a natural sentence with a bolded lead-in. + +Do not use a bold label followed by an em dash, colon, or definition-style fragment. + +Avoid this style: + +```markdown +- **Thematic grouping** — Related changes are discussed together instead of listed chronologically +``` + +Use this style instead: + +```markdown +- **Thematic grouping** where related changes are discussed together instead of listed chronologically, +``` + +The bold text should highlight the capability name, but the full bullet must read as one natural sentence. + +Preferred pattern: + +```markdown +- **<Capability name>** where/that/so/with <natural sentence continuation>, +``` + +End each bullet with `,` except the final bullet in a populated section, which must end with `.`. + +### GitHub alert blocks (optional) + +Alert blocks draw attention to information that deserves special notice. Use them sparingly — prefer zero to two per release. Only include alerts when the release data genuinely supports the attention level. + +Alert blocks appear after the summary and before the `Sources:` section. + +**When to use each alert type:** + +`> [!NOTE]` — Helpful context, compatibility notes, clarifications for skimmers, non-breaking behavior explanations. + +`> [!TIP]` — Recommended usage, easier migration paths, better ways to use a new or changed feature, practical follow-up actions. + +`> [!IMPORTANT]` — New capabilities users should notice, required configuration changes, important behavior changes, major release highlights. + +`> [!WARNING]` — Breaking changes, deprecated behavior that may affect users soon, changes that can cause builds, tests, runtime behavior, or integrations to fail if ignored. + +`> [!CAUTION]` — Security-sensitive changes, data loss risks, removal of functionality, operational risks, changes where misuse can lead to negative outcomes. + +Do not invent alerts. Do not add a `WARNING` or `CAUTION` unless the release data supports that level of attention. Breaking changes should normally use `WARNING`. Security-sensitive or risk-heavy changes should normally use `CAUTION`. + +### The Sources section + +The `Sources:` section preserves the original references that informed the summary. This gives readers a path to the raw details if the summary is not enough. + +Each source entry follows this format: + +``` +* <title> by @<author> in <url> +``` + +For pull requests, use the PR title and PR URL: + +``` +* Add validation for skill templates by @gimlichael in https://github.com/codebeltnet/agentic/pull/19 +``` + +For direct commits without a PR, use the commit subject and commit URL: + +``` +* Fix script path handling by @gimlichael in https://github.com/codebeltnet/agentic/commit/abc123def +``` + +List every pull request and direct commit that contributed to the release. Do not omit sources. + +### The changelog link + +The final line of the release note must always be: + +``` +**Full Changelog**: https://github.com/{owner}/{repo}/compare/{previousRef}...{currentRef} +``` + +When comparing tags, use the tag names (e.g. `v1.0.0...v1.0.1`). When comparing branches from default resolution, use the branch names (e.g. `main...feature/my-branch`). + +Nothing may appear after this line. + +## Non-Negotiable Rules + +- The first line of the output is exactly `## What's Changed`. +- The summary covers all meaningful changes in the comparison range. +- The summary is optimized for GitHub release notes, not raw commit history. +- Alert blocks are included only when they add value and are supported by the release data. +- Alert severity matches the actual impact of the change. +- The `Sources:` section is always included. +- Source entries use the `* <title> by @<author> in <url>` format, falling back to `* <title> by <author-name> in <url>` when no GitHub username is available. +- The final line is the full changelog link in the exact format shown above. +- Nothing appears after the full changelog link. +- No unsupported claims are invented. +- Breaking changes, if any, are clearly identified. +- Vague wording like "various improvements" or "miscellaneous changes" is avoided. +- The skill prefers pull request metadata over raw commits when available. +- Direct commits are used only when PR metadata is unavailable or the change was committed directly. +- Related changes are grouped in the summary rather than listed chronologically. +- The summary explains the effect of changes, not just the implementation. +- Dependency, build, test, documentation, CI/CD, and infrastructure changes are included when meaningful. +- The skill does not mutate any repository state — it is entirely read-only. +- When no explicit input is provided, the skill follows the Default Resolution Behavior instead of asking the user for a repository or tag range. +- All contributors in the comparison range are represented in the Sources section. + +## Data Collection Strategy + +The skill uses GitHub's API and local Git commands to gather data. The preferred approach depends on the input path and what tools are available. + +**When explicit tags or a compare URL are provided**, use GitHub's API. The preferred approach depends on what tools are available in the agent environment. + +When GitHub MCP tools are available (such as `github_list_commits`, `github_get_commit`, `github_pull_request_read`), use them directly. They provide structured data without requiring shell access. + +When `gh` CLI is available, use these commands: + +```bash +gh api repos/{owner}/{repo}/compare/{previousRef}...{currentRef} --jq '.commits[]' +gh api repos/{owner}/{repo}/commits/{sha}/pulls --jq '.[]' +gh pr view {number} --repo {owner}/{repo} --json title,author,body,labels,files,url +``` + +The GitHub compare API can return fewer commits than the range contains. After fetching a compare response, compare `total_commits` with the number of collected `.commits[]` entries. If `total_commits` is greater than the collected commit count, fetch remaining pages when possible; otherwise warn the user that commit data is capped and do not present the `Sources:` section as complete. + +**When using default resolution (no explicit input)**, combine local Git commands with GitHub API. First resolve the base branch (see **Default Resolution Behavior** above), then substitute the resolved value into `{resolvedBase}` — do not hardcode `origin/main`: + +```bash +git rev-parse --abbrev-ref HEAD +git remote +git symbolic-ref refs/remotes/origin/HEAD --short +git log --oneline {resolvedBase}..HEAD +git log --format="%H%x09%an%x09%ae%x09%s%x09%b" {resolvedBase}..HEAD +``` + +Then use the GitHub API to enrich local commit data with pull request metadata, labels, and descriptions. + +**When neither is available**, guide the user to install `gh` or authenticate with GitHub. + +For each commit in the compare range, check whether it belongs to a pull request. GitHub's API can resolve this through the commit's associated pull requests endpoint. When a commit maps to a PR, use the PR's metadata (title, description, labels) as the primary source of truth for that change. + +## Quality Checklist + +Before returning the result, verify: + +1. The first line is exactly `## What's Changed`. +2. The summary is human-friendly and optimized for GitHub release notes. +3. The summary covers the meaningful changes in the comparison range. +4. GitHub alert blocks are included only when they add value. +5. Alert severity matches the actual impact of the change. +6. Alert blocks are supported by the release data. +7. A `Sources:` section is included with all contributing PRs and commits. +8. Source entries use the `* <title> by @<author> in <url>` format, with fallback to author name when no GitHub username is available. +9. All contributors in the comparison range are represented in the Sources section. +10. The final line is the full changelog link. +11. Nothing appears after the full changelog link. +12. No unsupported claims were invented. +13. Breaking changes, if any, are clearly identified. +14. When using default resolution, the comparison range correctly reflects the current branch against the upstream default branch. diff --git a/skills/git-remote-release/assets/hero.jpg b/skills/git-remote-release/assets/hero.jpg new file mode 100644 index 0000000..06ee66d Binary files /dev/null and b/skills/git-remote-release/assets/hero.jpg differ diff --git a/skills/git-remote-release/evals/evals.json b/skills/git-remote-release/evals/evals.json new file mode 100644 index 0000000..00515a5 --- /dev/null +++ b/skills/git-remote-release/evals/evals.json @@ -0,0 +1,59 @@ +{ + "skill_name": "git-remote-release", + "evals": [ + { + "id": 1, + "prompt": "Generate release notes for https://github.com/codebeltnet/agentic/compare/v0.4.5...v0.4.6", + "expected_output": "Release notes starting with ## What's Changed, a human-friendly summary of changes between v0.4.5 and v0.4.6, a Sources section with PR/commit references, and ending with the full changelog link.", + "expectations": [ + "First line is exactly ## What's Changed", + "Parses the compare URL to extract owner, repo, previous tag, and current tag", + "Summary explains the effect of changes rather than listing raw commit messages", + "Sources section includes all contributing PRs and/or commits with author and URL", + "Final line is the full changelog compare link in the exact required format", + "Nothing appears after the changelog link" + ] + }, + { + "id": 2, + "prompt": "I need release notes for the cli/cli repo, from v2.60.0 to v2.61.0. Write something I can paste directly into a GitHub release.", + "expected_output": "Release notes for cli/cli between v2.60.0 and v2.61.0, formatted for direct paste into a GitHub release, with grouped changes and proper sources.", + "expectations": [ + "First line is exactly ## What's Changed", + "Uses separate repository, previous tag, and current tag values correctly", + "Summary groups related changes by theme rather than listing chronologically", + "Alert blocks are included only when supported by the release data", + "Sources section lists every contributing PR and/or commit", + "Final line is the full changelog compare link for cli/cli v2.60.0...v2.61.0" + ] + }, + { + "id": 3, + "prompt": "Write release notes for dotnet/runtime from v9.0.0 to v9.0.1. This is a patch release so it should be concise. Highlight any security fixes if there are any.", + "expected_output": "A concise release note for a patch release with focused summary, any justified security alerts using CAUTION blocks, and complete sources.", + "expectations": [ + "First line is exactly ## What's Changed", + "Summary is appropriately concise for a patch release", + "Security-sensitive changes are highlighted with CAUTION alert blocks when supported by evidence", + "No alerts are invented without supporting evidence from the commits or PRs", + "Sources section preserves all contributing references", + "Final line is the full changelog compare link" + ] + }, + { + "id": 4, + "prompt": "Generate release notes for my current branch.", + "prerequisites": "Run this eval from a manually bootstrapped Git workspace with a non-default branch containing at least one commit not present on the upstream default branch, a configured upstream remote, and a resolvable remote default branch.", + "expected_output": "Release notes generated from the current branch compared against the upstream default branch, with all contributors included in the Sources section.", + "expectations": [ + "First line is exactly ## What's Changed", + "Detects the current branch from the local Git working repository", + "Resolves the upstream remote and default branch using the fallback order", + "Compares current branch against the upstream default branch", + "Includes all contributors from the detected commits and pull requests", + "Sources section uses @author format when GitHub username is available, plain author name otherwise", + "Final line is the full changelog compare link using branch names" + ] + } + ] +}