diff --git a/.github/windows-installer.nsi b/.github/windows-installer.nsi new file mode 100644 index 0000000..415f363 --- /dev/null +++ b/.github/windows-installer.nsi @@ -0,0 +1,177 @@ +; DeepDiff DB — Windows Installer +; Built by the release workflow; __APP_VERSION__ is substituted at compile time. +; +; Installs deepdiffdb.exe to %ProgramFiles%\DeepDiffDB, adds that directory +; to the system PATH, and registers the app in Add/Remove Programs. + +Unicode true +SetCompressor /SOLID lzma + +!define APP_NAME "DeepDiff DB" +!define APP_VERSION "__APP_VERSION__" +!define PUBLISHER "iamvirul" +!define HOMEPAGE "https://iamvirul.github.io/deepdiff-db/" +!define INSTALL_DIR "$PROGRAMFILES64\DeepDiffDB" +!define UNINSTKEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\DeepDiffDB" +!define REGKEY "Software\DeepDiffDB" + +Name "${APP_NAME} ${APP_VERSION}" +OutFile "deepdiff-db-v__APP_VERSION__-windows-amd64-installer.exe" +InstallDir "${INSTALL_DIR}" +InstallDirRegKey HKLM "${REGKEY}" "InstallDir" +RequestExecutionLevel admin + +; ── Pages ────────────────────────────────────────────────────────────────── +Page directory +Page instfiles +UninstPage uninstConfirm +UninstPage instfiles + +; ── Install ──────────────────────────────────────────────────────────────── +Section "DeepDiff DB" SecMain + SectionIn RO + SetOutPath "$INSTDIR" + + File "deepdiffdb.exe" + File "README.md" + File "deepdiffdb.config.yaml.example" + + ; Add install dir to system PATH (append only when not already present) + ReadRegStr $0 HKLM \ + "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "Path" + StrCpy $1 $0 "" -1 ; last char of current PATH + StrCmp $1 ";" 0 +2 + StrCpy $0 $0 -1 ; strip trailing semicolon + ; Check whether INSTDIR already appears (simple prefix/suffix check is fine + ; because users rarely change the install location) + Push "$0" + Push "$INSTDIR" + Call StrContains + Pop $1 + StrCmp $1 "" 0 path_skip + WriteRegExpandStr HKLM \ + "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" \ + "Path" "$0;$INSTDIR" + SendMessage ${HWND_BROADCAST} ${WM_SETTINGCHANGE} 0 \ + "STR:Environment" /TIMEOUT=5000 + path_skip: + + ; Write uninstaller + WriteUninstaller "$INSTDIR\Uninstall.exe" + + ; Add/Remove Programs entry + WriteRegStr HKLM "${UNINSTKEY}" "DisplayName" "${APP_NAME} ${APP_VERSION}" + WriteRegStr HKLM "${UNINSTKEY}" "DisplayVersion" "${APP_VERSION}" + WriteRegStr HKLM "${UNINSTKEY}" "Publisher" "${PUBLISHER}" + WriteRegStr HKLM "${UNINSTKEY}" "URLInfoAbout" "${HOMEPAGE}" + WriteRegStr HKLM "${UNINSTKEY}" "InstallLocation" "$INSTDIR" + WriteRegStr HKLM "${UNINSTKEY}" "UninstallString" '"$INSTDIR\Uninstall.exe"' + WriteRegDWORD HKLM "${UNINSTKEY}" "NoModify" 1 + WriteRegDWORD HKLM "${UNINSTKEY}" "NoRepair" 1 + WriteRegStr HKLM "${REGKEY}" "InstallDir" "$INSTDIR" +SectionEnd + +; ── Uninstall ────────────────────────────────────────────────────────────── +Section "Uninstall" + Delete "$INSTDIR\deepdiffdb.exe" + Delete "$INSTDIR\README.md" + Delete "$INSTDIR\deepdiffdb.config.yaml.example" + Delete "$INSTDIR\Uninstall.exe" + RMDir "$INSTDIR" + + ; Remove install dir from system PATH + ReadRegStr $0 HKLM \ + "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "Path" + ; Strip "$INSTDIR;" and ";$INSTDIR" variants + Push "$0" + Push "$INSTDIR;" + Push "" + Call StrReplaceAll + Pop $0 + Push "$0" + Push ";$INSTDIR" + Push "" + Call StrReplaceAll + Pop $0 + WriteRegExpandStr HKLM \ + "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" \ + "Path" "$0" + SendMessage ${HWND_BROADCAST} ${WM_SETTINGCHANGE} 0 \ + "STR:Environment" /TIMEOUT=5000 + + DeleteRegKey HKLM "${UNINSTKEY}" + DeleteRegKey HKLM "${REGKEY}" +SectionEnd + +; ── Helper: StrContains ──────────────────────────────────────────────────── +; Stack: [haystack] [needle] → [match-start or ""] +; Searches haystack for needle; pushes "" if not found. +Function StrContains + Exch $1 ; needle + Exch + Exch $0 ; haystack + Push $2 + Push $3 + Push $4 + StrLen $3 $1 ; needle length + StrLen $4 $0 ; haystack length + IntOp $4 $4 - $3 + StrCpy $2 0 + loop: + IntCmp $2 $4 done_notfound done_notfound 0 + StrCpy $R0 $0 $3 $2 + StrCmp $R0 $1 done_found 0 + IntOp $2 $2 + 1 + Goto loop + done_found: + StrCpy $R0 $0 "" $2 + Goto done + done_notfound: + StrCpy $R0 "" + done: + Pop $4 + Pop $3 + Pop $2 + Pop $0 + Pop $1 + Push $R0 +FunctionEnd + +; ── Helper: StrReplaceAll ────────────────────────────────────────────────── +; Stack (top→bottom): [haystack] [find] [replace] → [result] +Function StrReplaceAll + Exch $2 ; replace + Exch + Exch $1 ; find + Exch 2 + Exch $0 ; haystack + Push $3 ; working copy + Push $4 ; needle length + Push $5 ; result accumulator + Push $6 ; position + StrCpy $5 "" + StrLen $4 $1 + StrCpy $3 $0 + loop: + StrLen $6 $3 + IntCmp $6 0 done 0 0 + StrCpy $6 $3 $4 + StrCmp $6 $1 found 0 + StrCpy $6 $3 1 + StrCpy $5 "$5$6" + StrCpy $3 $3 "" 1 + Goto loop + found: + StrCpy $5 "$5$2" + StrCpy $3 $3 "" $4 + Goto loop + done: + StrCpy $0 $5 + Pop $6 + Pop $5 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Exch $0 +FunctionEnd diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bd57522..f4327d3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -48,3 +48,128 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} + + macos-dmg: + name: Build macOS DMG (${{ matrix.arch }}) + runs-on: macos-latest + needs: goreleaser # wait for the release to be created first + strategy: + matrix: + include: + - arch: amd64 + goarch: amd64 + - arch: arm64 + goarch: arm64 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Build binary + env: + GOARCH: ${{ matrix.goarch }} + CGO_ENABLED: "0" + run: | + VERSION="${GITHUB_REF_NAME}" + go build \ + -ldflags "-s -w -X main.version=${VERSION}" \ + -o deepdiffdb \ + ./cmd/deepdiffdb + + - name: Create DMG + run: | + VERSION="${GITHUB_REF_NAME}" + DMG_NAME="deepdiff-db-${VERSION}-darwin-${{ matrix.arch }}.dmg" + + # --- staging folder --- + mkdir -p dmg-stage + cp deepdiffdb dmg-stage/ + cp README.md dmg-stage/ + cp deepdiffdb.config.yaml.example dmg-stage/ + + # Simple install helper + cat > dmg-stage/install.sh << 'INSTALL' + #!/usr/bin/env bash + set -e + SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + DEST="/usr/local/bin/deepdiffdb" + echo "Installing deepdiffdb → ${DEST}" + sudo install -m 755 "${SCRIPT_DIR}/deepdiffdb" "${DEST}" + echo "Installed: $(deepdiffdb --version)" + INSTALL + chmod +x dmg-stage/install.sh + + # Create read-only compressed DMG with hdiutil (built-in on macOS) + hdiutil create \ + -volname "DeepDiff DB ${VERSION}" \ + -srcfolder dmg-stage \ + -ov \ + -format UDZO \ + "${DMG_NAME}" + + echo "DMG_NAME=${DMG_NAME}" >> "$GITHUB_ENV" + + - name: Upload DMG to GitHub release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release upload "${GITHUB_REF_NAME}" "${DMG_NAME}" --clobber + + windows-installer: + name: Build Windows Installer (amd64) + runs-on: windows-latest + needs: goreleaser # wait for the release to be created first + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Build Windows binary + shell: bash + env: + GOARCH: amd64 + GOOS: windows + CGO_ENABLED: "0" + run: | + VERSION="${GITHUB_REF_NAME}" + go build \ + -ldflags "-s -w -X main.version=${VERSION}" \ + -o deepdiffdb.exe \ + ./cmd/deepdiffdb + + - name: Install NSIS + run: choco install nsis --no-progress -y + + - name: Prepare NSIS script + shell: bash + run: | + VERSION="${GITHUB_REF_NAME}" + VER_CLEAN="${VERSION#v}" # strip leading 'v': v1.4.0 → 1.4.0 + # Substitute the __APP_VERSION__ placeholder in the template + sed "s/__APP_VERSION__/${VER_CLEAN}/g" \ + .github/windows-installer.nsi > installer.nsi + echo "INSTALLER_NAME=deepdiff-db-${VERSION}-windows-amd64-installer.exe" \ + >> "$GITHUB_ENV" + + - name: Compile installer + shell: cmd + run: makensis installer.nsi + + - name: Upload installer to GitHub release + shell: bash + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release upload "${GITHUB_REF_NAME}" "${INSTALLER_NAME}" --clobber diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b4ca09..9926602 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.4.1] - 2026-05-03 + +### Added + +- **macOS DMG release artifacts** — `darwin/amd64` and `darwin/arm64` DMGs are now published to every GitHub release alongside the existing tarballs. Each DMG includes the binary, `README.md`, `deepdiffdb.config.yaml.example`, and an `install.sh` helper that copies the binary to `/usr/local/bin`. +- **Windows installer release artifact** — A native NSIS installer (`deepdiff-db-vX.Y.Z-windows-amd64-installer.exe`) is published to every GitHub release. It installs `deepdiffdb.exe` to `%ProgramFiles%\DeepDiffDB`, adds that directory to the system PATH (idempotent, no reboot required), registers the app in Add/Remove Programs, and includes a full uninstaller. + ## [1.4.0] - 2026-05-03 ### Added @@ -484,6 +491,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - MySQL foreign key check handling [Unreleased]: https://github.com/iamvirul/deepdiff-db/compare/v1.4.0...HEAD +[1.4.1]: https://github.com/iamvirul/deepdiff-db/compare/v1.4.0...v1.4.1 [1.4.0]: https://github.com/iamvirul/deepdiff-db/compare/v1.3.0...v1.4.0 [1.3.0]: https://github.com/iamvirul/deepdiff-db/compare/v1.2.0...v1.3.0 [1.2.0]: https://github.com/iamvirul/deepdiff-db/compare/v1.1.0...v1.2.0