chore(release): add changelog generation and release automation
This commit is contained in:
parent
aa6acbabc9
commit
eaf9d9d1c9
4 changed files with 391 additions and 43 deletions
192
CHANGELOG.md
192
CHANGELOG.md
|
|
@ -8,50 +8,158 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- Init wizard with daemon install step (`unarr init`, replaces `unarr setup`)
|
||||
- Interactive config menu with 7 categories (`unarr config [category]`)
|
||||
- Migration wizard from Sonarr/Radarr/Prowlarr (`unarr migrate`) [pre-beta]
|
||||
- Auto-detect instances via Docker, config files, port scan, Prowlarr
|
||||
- Import download history and blocklist to avoid re-downloading
|
||||
- Detect Plex/Jellyfin/Emby media servers and library paths
|
||||
- Extract debrid tokens from *arr download clients
|
||||
- JSON export with `--dry-run --json`
|
||||
- Media server detection in `unarr init` (suggests library paths as download directory)
|
||||
- `preferred_quality` setting in config (2160p/1080p/720p)
|
||||
- Clean command to remove temp files, logs, and cached data (`unarr clean`)
|
||||
- Daemon mode with background download management (`unarr start`)
|
||||
- One-shot download command (`unarr download`)
|
||||
- Stream to media player (`unarr stream`)
|
||||
- Doctor command for diagnostics (`unarr doctor`)
|
||||
- Status command for daemon monitoring (`unarr status`)
|
||||
- Download engine with torrent support (debrid and usenet coming soon)
|
||||
- File organization (Movies/TV Shows directory structure)
|
||||
- Post-download verification
|
||||
- Desktop notifications (Linux, macOS)
|
||||
- Docker support with multi-stage build
|
||||
- Cross-platform install scripts (shell, PowerShell)
|
||||
- Dependabot for automated dependency updates
|
||||
- golangci-lint configuration with gosec
|
||||
|
||||
### Changed
|
||||
- Renamed `internal/commands/` to `internal/cmd/`
|
||||
- **organize**: use server metadata for file organization and subtitle handling
|
||||
- **stream**: add NAT-PMP port mapping for remote downloads
|
||||
|
||||
## [0.1.0] - 2025-02-14
|
||||
## [0.4.1] - 2026-04-01
|
||||
|
||||
### Added
|
||||
- Initial release
|
||||
- Search across 30+ torrent sources with advanced filters
|
||||
- TrueSpec torrent inspection (quality, codec, seeds, score)
|
||||
- Watch command (streaming providers + torrent alternatives)
|
||||
- Popular and recent content browsing
|
||||
- System statistics
|
||||
- Interactive configuration
|
||||
- JSON output mode (`--json`) for scripting
|
||||
- Colored terminal output with `--no-color` support
|
||||
- Homebrew tap distribution
|
||||
- GoReleaser with UPX compression
|
||||
- CI pipeline (test, build, lint, vet)
|
||||
- Lefthook git hooks (gofmt, go vet, conventional commits)
|
||||
|
||||
[Unreleased]: https://github.com/torrentclaw/unarr/compare/v0.1.0...HEAD
|
||||
[0.1.0]: https://github.com/torrentclaw/unarr/releases/tag/v0.1.0
|
||||
- **cli**: add login command and refactor shared helpers
|
||||
- **stream**: report watch progress to API via HTTP Range tracking
|
||||
|
||||
### Fixed
|
||||
|
||||
- **ci**: fix lint errors and pin CI to Go 1.25
|
||||
- **lint**: remove unused newStubCmd function
|
||||
|
||||
### Other
|
||||
|
||||
- **cli**: remove moreseed stub command
|
||||
- **cli**: remove redundant stub commands (monitor, open, add, compare)
|
||||
|
||||
## [0.4.0] - 2026-03-31
|
||||
|
||||
### Added
|
||||
|
||||
- **cli**: upgrade command, rich status, and version cache
|
||||
|
||||
### Fixed
|
||||
|
||||
- **progress**: always report status transitions and poll for control signals
|
||||
|
||||
## [0.3.7] - 2026-03-31
|
||||
|
||||
### CI/CD
|
||||
|
||||
- **docker**: remove dockerhub-description sync step
|
||||
|
||||
## [0.3.6] - 2026-03-31
|
||||
|
||||
### CI/CD
|
||||
|
||||
- **deps**: bump docker/metadata-action from 5 to 6
|
||||
- **deps**: bump docker/setup-qemu-action from 3 to 4
|
||||
- **deps**: bump docker/login-action from 3 to 4
|
||||
- **deps**: bump docker/build-push-action from 6 to 7
|
||||
- **deps**: bump codecov/codecov-action from 5 to 6
|
||||
- **docker**: add Docker Hub description sync and DOCKERHUB.md
|
||||
|
||||
### Fixed
|
||||
|
||||
- **ci**: upgrade golangci-lint to v2.11.3 for Go 1.25 support
|
||||
- **docker**: upgrade alpine packages to patch CVE-2025-60876 and CVE-2026-27171
|
||||
- **lint**: use default:none to disable errcheck, fix all gofmt and exhaustive
|
||||
- **lint**: disable errcheck, tune gosec/exclusions for codebase state
|
||||
- **lint**: configure linters for codebase maturity, fix gofmt and ineffassign
|
||||
- **lint**: exclude common fire-and-forget patterns from errcheck
|
||||
- **lint**: resolve errcheck and bodyclose warnings for golangci-lint v2
|
||||
|
||||
## [0.3.5] - 2026-03-30
|
||||
|
||||
### Changed
|
||||
|
||||
- migrate lint config to v2, remove daemon auto-upgrade, add trust badges
|
||||
|
||||
## [0.3.3] - 2026-03-30
|
||||
|
||||
### Fixed
|
||||
|
||||
- **ci**: remove go-client checkout steps
|
||||
|
||||
## [0.3.2] - 2026-03-30
|
||||
|
||||
### Added
|
||||
|
||||
- **init**: add 60s countdown, skip key, and cancel detection to browser auth
|
||||
|
||||
### CI/CD
|
||||
|
||||
- **release**: add Docker Hub publish and VirusTotal scan jobs
|
||||
|
||||
### Documentation
|
||||
|
||||
- add beta notice, fix install URLs to get.torrentclaw.com
|
||||
|
||||
### Fixed
|
||||
|
||||
- **ci**: fix virustotal job condition syntax
|
||||
- **docker**: simplify Dockerfile for CI builds (no local go-client)
|
||||
- **release**: disable homebrew tap (needs PAT, not GITHUB_TOKEN)
|
||||
|
||||
### Other
|
||||
|
||||
- re-enable homebrew tap in goreleaser
|
||||
|
||||
## [0.3.1] - 2026-03-30
|
||||
|
||||
### Fixed
|
||||
|
||||
- **build**: unused variable in Windows process check
|
||||
- **release**: disable homebrew tap until repo is created
|
||||
|
||||
### Other
|
||||
|
||||
- rename module from torrentclaw-cli to unarr
|
||||
|
||||
### Build
|
||||
|
||||
- remove UPX compression (antivirus false positives, startup penalty)
|
||||
|
||||
## [0.3.0] - 2026-03-29
|
||||
|
||||
### Added
|
||||
|
||||
- **agent**: add WebSocket transport with HTTP fallback
|
||||
- **auth**: browser-based CLI authentication (like Claude Code)
|
||||
- **daemon**: add auto-scan, force start, and stall timeout default
|
||||
- **debrid**: add HTTPS downloader for debrid direct URLs
|
||||
- **stream**: UPnP port forwarding for remote video playback
|
||||
- **usenet**: implement full NNTP download pipeline
|
||||
- add migrate command, media server detection, and debrid auto-config
|
||||
- replace setup with init wizard + interactive config menu
|
||||
- add clean command to remove temp files, logs, and cached data
|
||||
- add Sentry error reporting
|
||||
- improve daemon resilience, streaming, and usenet downloads
|
||||
- initial commit — unarr CLI
|
||||
|
||||
### Changed
|
||||
|
||||
- extract BuildSyncItems to library package, remove duplication
|
||||
|
||||
### Documentation
|
||||
|
||||
- improve CLI help, shell completion, and README
|
||||
|
||||
### Fixed
|
||||
|
||||
- **torrent**: expand tracker list, add DHT persistence and configurable timeouts
|
||||
- force-start tasks bypass HasCapacity check in dispatch loop
|
||||
- add panic recovery to auto-scan, cap DHT nodes at 200
|
||||
- harden usenet/debrid downloaders from critico review
|
||||
|
||||
### Build
|
||||
|
||||
- add -s -w -trimpath to Makefile, add build-small target with UPX
|
||||
[Unreleased]: https://github.com/torrentclaw/unarr/compare/v0.4.1...HEAD
|
||||
[0.4.1]: https://github.com/torrentclaw/unarr/compare/v0.4.0...v0.4.1
|
||||
[0.4.0]: https://github.com/torrentclaw/unarr/compare/v0.3.7...v0.4.0
|
||||
[0.3.7]: https://github.com/torrentclaw/unarr/compare/v0.3.6...v0.3.7
|
||||
[0.3.6]: https://github.com/torrentclaw/unarr/compare/v0.3.5...v0.3.6
|
||||
[0.3.5]: https://github.com/torrentclaw/unarr/compare/v0.3.3...v0.3.5
|
||||
[0.3.3]: https://github.com/torrentclaw/unarr/compare/v0.3.2...v0.3.3
|
||||
[0.3.2]: https://github.com/torrentclaw/unarr/compare/v0.3.1...v0.3.2
|
||||
[0.3.1]: https://github.com/torrentclaw/unarr/compare/v0.3.0...v0.3.1
|
||||
[0.3.0]: https://github.com/torrentclaw/unarr/releases/tag/v0.3.0
|
||||
|
||||
|
|
|
|||
25
Makefile
25
Makefile
|
|
@ -1,4 +1,4 @@
|
|||
.PHONY: all build test lint coverage clean fmt vet check install-hooks
|
||||
.PHONY: all build test lint coverage clean fmt vet check install-hooks changelog release release-patch release-minor release-major release-dry
|
||||
|
||||
BINARY = unarr
|
||||
SENTRY_DSN ?=
|
||||
|
|
@ -48,6 +48,29 @@ install-hooks:
|
|||
install:
|
||||
go install ./cmd/unarr/
|
||||
|
||||
## Preview changelog for next release
|
||||
changelog:
|
||||
@git-cliff --unreleased --strip header
|
||||
|
||||
## Create a release: make release-patch, release-minor, release-major, or release V=0.5.0
|
||||
release:
|
||||
@test -n "$(V)" || { echo "Usage: make release V=0.5.0"; exit 1; }
|
||||
@./scripts/release.sh $(V)
|
||||
|
||||
release-patch:
|
||||
@./scripts/release.sh patch
|
||||
|
||||
release-minor:
|
||||
@./scripts/release.sh minor
|
||||
|
||||
release-major:
|
||||
@./scripts/release.sh major
|
||||
|
||||
## Preview release without making changes
|
||||
release-dry:
|
||||
@test -n "$(V)" || { echo "Usage: make release-dry V=patch|minor|major|0.5.0"; exit 1; }
|
||||
@./scripts/release.sh --dry-run $(V)
|
||||
|
||||
## Remove generated files
|
||||
clean:
|
||||
rm -f $(BINARY) coverage.out coverage.html
|
||||
|
|
|
|||
79
cliff.toml
Normal file
79
cliff.toml
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# git-cliff configuration
|
||||
# https://git-cliff.org/docs/configuration
|
||||
|
||||
[changelog]
|
||||
header = """# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n
|
||||
"""
|
||||
body = """
|
||||
{%- macro remote_url() -%}
|
||||
https://github.com/torrentclaw/unarr
|
||||
{%- endmacro -%}
|
||||
|
||||
{% if version -%}
|
||||
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
|
||||
{%- else -%}
|
||||
## [Unreleased]
|
||||
{%- endif %}
|
||||
|
||||
{% for group, commits in commits | group_by(attribute="group") %}
|
||||
### {{ group | striptags | trim | upper_first }}
|
||||
{% for commit in commits
|
||||
| filter(attribute="scope")
|
||||
| sort(attribute="scope") %}
|
||||
- **{{ commit.scope }}**: {{ commit.message }}
|
||||
{%- if commit.breaking %} (**BREAKING**){% endif %}
|
||||
{%- endfor -%}
|
||||
{% for commit in commits %}
|
||||
{%- if not commit.scope %}
|
||||
- {{ commit.message }}
|
||||
{%- if commit.breaking %} (**BREAKING**){% endif %}
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
{% endfor %}
|
||||
"""
|
||||
footer = """
|
||||
{%- macro remote_url() -%}
|
||||
https://github.com/torrentclaw/unarr
|
||||
{%- endmacro -%}
|
||||
|
||||
{% for release in releases -%}
|
||||
{% if release.version -%}
|
||||
{% if release.previous.version -%}
|
||||
[{{ release.version | trim_start_matches(pat="v") }}]: {{ self::remote_url() }}/compare/{{ release.previous.version }}...{{ release.version }}
|
||||
{% else -%}
|
||||
[{{ release.version | trim_start_matches(pat="v") }}]: {{ self::remote_url() }}/releases/tag/{{ release.version }}
|
||||
{% endif -%}
|
||||
{% else -%}
|
||||
{% if release.previous.version -%}
|
||||
[Unreleased]: {{ self::remote_url() }}/compare/{{ release.previous.version }}...HEAD
|
||||
{% endif -%}
|
||||
{% endif -%}
|
||||
{% endfor %}
|
||||
"""
|
||||
trim = true
|
||||
|
||||
[git]
|
||||
conventional_commits = true
|
||||
filter_unconventional = true
|
||||
split_commits = false
|
||||
commit_parsers = [
|
||||
{ message = "^feat", group = "Added" },
|
||||
{ message = "^fix", group = "Fixed" },
|
||||
{ message = "^perf", group = "Performance" },
|
||||
{ message = "^refactor", group = "Changed" },
|
||||
{ message = "^style", group = "Changed" },
|
||||
{ message = "^doc", group = "Documentation" },
|
||||
{ message = "^ci", group = "CI/CD" },
|
||||
{ message = "^chore\\(deps\\)", skip = true },
|
||||
{ message = "^chore", group = "Other" },
|
||||
{ message = "^test", skip = true },
|
||||
]
|
||||
protect_breaking_commits = false
|
||||
filter_commits = false
|
||||
tag_pattern = "v[0-9].*"
|
||||
sort_commits = "newest"
|
||||
138
scripts/release.sh
Executable file
138
scripts/release.sh
Executable file
|
|
@ -0,0 +1,138 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# release.sh — Automate version bump, changelog generation, and tag creation.
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/release.sh patch|minor|major Auto-bump from latest tag
|
||||
# ./scripts/release.sh 0.5.0 Explicit version
|
||||
# ./scripts/release.sh --dry-run patch Preview without changes
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
VERSION_FILE="internal/cmd/version.go"
|
||||
CHANGELOG_FILE="CHANGELOG.md"
|
||||
|
||||
# ── Colors ──────────────────────────────────────────────────────────
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
CYAN='\033[0;36m'
|
||||
BOLD='\033[1m'
|
||||
NC='\033[0m'
|
||||
|
||||
info() { echo -e "${CYAN}▸${NC} $*"; }
|
||||
ok() { echo -e "${GREEN}✓${NC} $*"; }
|
||||
warn() { echo -e "${YELLOW}⚠${NC} $*"; }
|
||||
error() { echo -e "${RED}✗${NC} $*" >&2; }
|
||||
die() { error "$@"; exit 1; }
|
||||
|
||||
# ── Args ────────────────────────────────────────────────────────────
|
||||
DRY_RUN=false
|
||||
BUMP=""
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--dry-run) DRY_RUN=true ;;
|
||||
patch|minor|major) BUMP="$arg" ;;
|
||||
[0-9]*) BUMP="$arg" ;;
|
||||
-h|--help)
|
||||
echo "Usage: $0 [--dry-run] <patch|minor|major|X.Y.Z>"
|
||||
exit 0
|
||||
;;
|
||||
*) die "Unknown argument: $arg" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
[ -z "$BUMP" ] && die "Usage: $0 [--dry-run] <patch|minor|major|X.Y.Z>"
|
||||
|
||||
# ── Prerequisites ───────────────────────────────────────────────────
|
||||
command -v git-cliff >/dev/null 2>&1 || die "git-cliff not found. Install: https://git-cliff.org/docs/installation"
|
||||
|
||||
if [ "$DRY_RUN" = false ]; then
|
||||
[ -n "$(git status --porcelain)" ] && die "Working tree is dirty. Commit or stash changes first."
|
||||
fi
|
||||
|
||||
CURRENT_BRANCH=$(git branch --show-current)
|
||||
[ "$CURRENT_BRANCH" = "main" ] || warn "Not on main branch (current: $CURRENT_BRANCH)"
|
||||
|
||||
# ── Resolve version ────────────────────────────────────────────────
|
||||
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
|
||||
LATEST_VERSION="${LATEST_TAG#v}"
|
||||
|
||||
bump_version() {
|
||||
local version="$1" part="$2"
|
||||
IFS='.' read -r major minor patch <<< "$version"
|
||||
case "$part" in
|
||||
major) echo "$((major + 1)).0.0" ;;
|
||||
minor) echo "$major.$((minor + 1)).0" ;;
|
||||
patch) echo "$major.$minor.$((patch + 1))" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
case "$BUMP" in
|
||||
patch|minor|major) NEXT_VERSION=$(bump_version "$LATEST_VERSION" "$BUMP") ;;
|
||||
*) NEXT_VERSION="$BUMP" ;;
|
||||
esac
|
||||
|
||||
NEXT_TAG="v${NEXT_VERSION}"
|
||||
|
||||
echo ""
|
||||
echo -e "${BOLD} Release Plan${NC}"
|
||||
echo -e " ─────────────────────────────"
|
||||
echo -e " Current tag: ${YELLOW}${LATEST_TAG}${NC}"
|
||||
echo -e " Next version: ${GREEN}${NEXT_TAG}${NC}"
|
||||
echo -e " Dry run: ${DRY_RUN}"
|
||||
echo ""
|
||||
|
||||
# ── Preview changelog ───────────────────────────────────────────────
|
||||
info "Generating changelog for ${NEXT_TAG}..."
|
||||
CHANGELOG_PREVIEW=$(git-cliff --tag "$NEXT_TAG" --unreleased --strip header)
|
||||
|
||||
if [ -z "$CHANGELOG_PREVIEW" ]; then
|
||||
die "No conventional commits found since ${LATEST_TAG}. Nothing to release."
|
||||
fi
|
||||
|
||||
echo -e "${BOLD} Changes in ${NEXT_TAG}:${NC}"
|
||||
echo "$CHANGELOG_PREVIEW" | sed 's/^/ /'
|
||||
echo ""
|
||||
|
||||
# ── Dry run stops here ─────────────────────────────────────────────
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
ok "Dry run complete. No changes made."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ── Confirm ─────────────────────────────────────────────────────────
|
||||
echo -ne "${YELLOW}Proceed with release ${NEXT_TAG}? [y/N]${NC} "
|
||||
read -r CONFIRM
|
||||
[[ "$CONFIRM" =~ ^[Yy]$ ]] || { info "Aborted."; exit 0; }
|
||||
|
||||
# ── Update version.go ──────────────────────────────────────────────
|
||||
info "Updating ${VERSION_FILE}..."
|
||||
sed -i "s/var Version = \".*\"/var Version = \"${NEXT_VERSION}\"/" "$VERSION_FILE"
|
||||
ok "Version set to ${NEXT_VERSION}"
|
||||
|
||||
# ── Update CHANGELOG.md ────────────────────────────────────────────
|
||||
info "Updating ${CHANGELOG_FILE}..."
|
||||
git-cliff --tag "$NEXT_TAG" --output "$CHANGELOG_FILE"
|
||||
ok "Changelog updated"
|
||||
|
||||
# ── Commit and tag ──────────────────────────────────────────────────
|
||||
info "Creating release commit..."
|
||||
git add "$VERSION_FILE" "$CHANGELOG_FILE"
|
||||
git commit -m "chore(release): ${NEXT_VERSION}
|
||||
|
||||
- Bump version to ${NEXT_VERSION}
|
||||
- Update CHANGELOG.md"
|
||||
|
||||
info "Creating annotated tag ${NEXT_TAG}..."
|
||||
git tag -a "$NEXT_TAG" -m "Release ${NEXT_TAG}"
|
||||
|
||||
echo ""
|
||||
ok "Release ${NEXT_TAG} created successfully!"
|
||||
echo ""
|
||||
echo -e " ${BOLD}Next steps:${NC}"
|
||||
echo -e " Push to trigger CI release pipeline:"
|
||||
echo ""
|
||||
echo -e " ${CYAN}git push origin main --follow-tags${NC}"
|
||||
echo ""
|
||||
Loading…
Add table
Add a link
Reference in a new issue