Skip to content

Merge pull request #10 from streed/update-installer-scripts #31

Merge pull request #10 from streed/update-installer-scripts

Merge pull request #10 from streed/update-installer-scripts #31

Workflow file for this run

name: Release
on:
push:
branches: [main]
workflow_dispatch:
inputs:
version_bump:
description: 'Version bump type (patch, minor, major)'
required: false
default: 'patch'
type: choice
options:
- patch
- minor
- major
prerelease:
description: 'Create as pre-release'
required: false
default: false
type: boolean
draft:
description: 'Create as draft'
required: false
default: false
type: boolean
permissions:
contents: write
pull-requests: write
jobs:
release:
name: Create Release
runs-on: ubuntu-latest
outputs:
has_changes: ${{ steps.check_changes.outputs.has_changes }}
version: ${{ steps.next_version.outputs.version }}
version_without_v: ${{ steps.next_version.outputs.version_without_v }}
changelog: ${{ steps.changelog.outputs.changelog }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history for tags
- name: Get previous tag
id: prev_tag
run: |
# Get the latest tag, default to v0.0.0 if no tags exist
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
echo "tag=${LATEST_TAG}" >> $GITHUB_OUTPUT
echo "Latest tag: ${LATEST_TAG}"
- name: Calculate next version
id: next_version
run: |
LATEST_TAG="${{ steps.prev_tag.outputs.tag }}"
BUMP_TYPE="${{ github.event.inputs.version_bump || 'patch' }}"
# Remove 'v' prefix if present
VERSION=${LATEST_TAG#v}
# Split version into components
IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"
# Default values if parsing fails
MAJOR=${MAJOR:-0}
MINOR=${MINOR:-0}
PATCH=${PATCH:-0}
# Increment based on bump type
case "$BUMP_TYPE" in
major)
MAJOR=$((MAJOR + 1))
MINOR=0
PATCH=0
;;
minor)
MINOR=$((MINOR + 1))
PATCH=0
;;
patch)
PATCH=$((PATCH + 1))
;;
esac
# Create new version
NEW_VERSION="v${MAJOR}.${MINOR}.${PATCH}"
echo "version=${NEW_VERSION}" >> $GITHUB_OUTPUT
echo "version_without_v=${MAJOR}.${MINOR}.${PATCH}" >> $GITHUB_OUTPUT
echo "bump_type=${BUMP_TYPE}" >> $GITHUB_OUTPUT
echo "Next version: ${NEW_VERSION} (${BUMP_TYPE} bump)"
- name: Check for changes
id: check_changes
run: |
# Check if there are any changes since the last tag
LATEST_TAG="${{ steps.prev_tag.outputs.tag }}"
if [ "$LATEST_TAG" = "v0.0.0" ]; then
echo "has_changes=true" >> $GITHUB_OUTPUT
else
CHANGES=$(git diff --name-only ${LATEST_TAG}..HEAD | grep -v '^\.github/' || true)
if [ -n "$CHANGES" ]; then
echo "has_changes=true" >> $GITHUB_OUTPUT
echo "Changes detected since ${LATEST_TAG}"
else
echo "has_changes=false" >> $GITHUB_OUTPUT
echo "No changes detected since ${LATEST_TAG}"
fi
fi
- name: Generate changelog
id: changelog
if: steps.check_changes.outputs.has_changes == 'true'
run: |
LATEST_TAG="${{ steps.prev_tag.outputs.tag }}"
NEW_VERSION="${{ steps.next_version.outputs.version }}"
# Generate changelog from commit messages
echo "## What's Changed" > CHANGELOG.md
echo "" >> CHANGELOG.md
if [ "$LATEST_TAG" = "v0.0.0" ]; then
# First release - include all commits
git log --pretty=format:"* %s (%h)" >> CHANGELOG.md
else
# Include commits since last tag
git log ${LATEST_TAG}..HEAD --pretty=format:"* %s (%h)" >> CHANGELOG.md
fi
echo "" >> CHANGELOG.md
echo "" >> CHANGELOG.md
echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${LATEST_TAG}...${NEW_VERSION}" >> CHANGELOG.md
# Output changelog for release body
echo "changelog<<EOF" >> $GITHUB_OUTPUT
cat CHANGELOG.md >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Setup Go
if: steps.check_changes.outputs.has_changes == 'true'
uses: actions/setup-go@v5
with:
go-version: "1.22"
- name: Run tests
if: steps.check_changes.outputs.has_changes == 'true'
run: |
go test -v -race ./...
build-cli:
name: Build CLI Binaries
if: needs.release.outputs.has_changes == 'true'
needs: release
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: ubuntu-latest
goos: linux
goarch: amd64
name: linux-amd64
ext: ""
- os: macos-latest
goos: darwin
goarch: amd64
name: darwin-amd64
ext: ""
- os: macos-latest
goos: darwin
goarch: arm64
name: darwin-arm64
ext: ""
- os: windows-latest
goos: windows
goarch: amd64
name: windows-amd64
ext: ".exe"
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.22"
- name: Setup Windows build environment
if: matrix.goos == 'windows'
shell: bash
run: |
# Install MSYS2 for complete build environment
choco install msys2 -y
# Initialize MSYS2 and install required packages
C:/tools/msys64/usr/bin/bash -lc 'pacman --noconfirm -S mingw-w64-x86_64-gcc mingw-w64-x86_64-pkg-config mingw-w64-x86_64-sqlite3'
# Add MSYS2 MinGW64 to PATH
echo "C:\\tools\\msys64\\mingw64\\bin" >> $GITHUB_PATH
# Verify installation
C:/tools/msys64/mingw64/bin/gcc --version || echo "GCC not found"
- name: Build CLI binary
shell: bash
run: |
VERSION="${{ needs.release.outputs.version_without_v }}"
BUILD_TIME=$(date -u '+%Y-%m-%d_%H:%M:%S')
GIT_COMMIT=$(git rev-parse --short HEAD)
mkdir -p dist
if [ "${{ matrix.goos }}" = "windows" ]; then
# Set up CGO environment for Windows with MSYS2
export CGO_ENABLED=1
export CC=C:/tools/msys64/mingw64/bin/gcc.exe
export CXX=C:/tools/msys64/mingw64/bin/g++.exe
export PKG_CONFIG_PATH="C:/tools/msys64/mingw64/lib/pkgconfig"
export PATH="C:/tools/msys64/mingw64/bin:$PATH"
fi
# Build CLI binary
CGO_ENABLED=1 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build \
-ldflags "-X main.Version=${VERSION} -X main.BuildTime=${BUILD_TIME} -X main.GitCommit=${GIT_COMMIT}" \
-o dist/ml-notes-cli-${{ matrix.name }}${{ matrix.ext }} ./app/cli
- name: Upload CLI artifact
uses: actions/upload-artifact@v4
with:
name: ml-notes-cli-${{ matrix.name }}
path: dist/ml-notes-cli-${{ matrix.name }}${{ matrix.ext }}
retention-days: 1
build-desktop:
name: Build Desktop Binaries
if: needs.release.outputs.has_changes == 'true'
needs: release
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: ubuntu-latest
platform: linux/amd64
name: linux-amd64
- os: macos-latest
platform: darwin/universal
name: darwin-universal
- os: windows-latest
platform: windows/amd64
name: windows-amd64
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.22"
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install Wails
run: go install github.com/wailsapp/wails/v2/cmd/wails@latest
- name: Setup Windows build environment
if: matrix.os == 'windows-latest'
shell: bash
run: |
# Install MSYS2 for complete build environment
choco install msys2 -y
# Initialize MSYS2 and install required packages
C:/tools/msys64/usr/bin/bash -lc 'pacman --noconfirm -S mingw-w64-x86_64-gcc mingw-w64-x86_64-pkg-config mingw-w64-x86_64-sqlite3'
# Add MSYS2 MinGW64 to PATH
echo "C:\\tools\\msys64\\mingw64\\bin" >> $GITHUB_PATH
- name: Setup Linux dependencies
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev
- name: Install frontend dependencies
if: hashFiles('frontend/package.json') != ''
run: |
if [ -d "frontend" ]; then
cd frontend
npm install
fi
- name: Build desktop application
shell: bash
run: |
VERSION="${{ needs.release.outputs.version_without_v }}"
BUILD_TIME=$(date -u '+%Y-%m-%d_%H:%M:%S')
GIT_COMMIT=$(git rev-parse --short HEAD)
if [ "${{ matrix.os }}" = "windows-latest" ]; then
# Set up CGO environment for Windows with MSYS2
export CGO_ENABLED=1
export CC=C:/tools/msys64/mingw64/bin/gcc.exe
export CXX=C:/tools/msys64/mingw64/bin/g++.exe
export PKG_CONFIG_PATH="C:/tools/msys64/mingw64/lib/pkgconfig"
export PATH="C:/tools/msys64/mingw64/bin:$PATH"
fi
# Build with Wails
wails build -clean -platform ${{ matrix.platform }} \
-ldflags "-X main.Version=${VERSION} -X main.BuildTime=${BUILD_TIME} -X main.GitCommit=${GIT_COMMIT}"
- name: Prepare desktop artifacts
shell: bash
run: |
mkdir -p dist
if [ "${{ matrix.os }}" = "windows-latest" ]; then
cp build/bin/ml-notes.exe dist/ml-notes-${{ matrix.name }}.exe
elif [ "${{ matrix.os }}" = "darwin-latest" ]; then
# For macOS, copy the app bundle
if [ -d "build/bin/ml-notes.app" ]; then
tar -czf dist/ml-notes-${{ matrix.name }}.tar.gz -C build/bin ml-notes.app
else
cp build/bin/ml-notes dist/ml-notes-${{ matrix.name }}
fi
else
cp build/bin/ml-notes dist/ml-notes-${{ matrix.name }}
fi
- name: Upload desktop artifacts
uses: actions/upload-artifact@v4
with:
name: ml-notes-desktop-${{ matrix.name }}
path: |
dist/ml-notes-${{ matrix.name }}*
retention-days: 1
package:
name: Create Release Packages
if: needs.release.outputs.has_changes == 'true'
needs: [release, build-cli, build-desktop]
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Create release archives
run: |
VERSION="${{ needs.release.outputs.version }}"
mkdir -p dist/release
# Move all artifacts to dist directory
find artifacts -type f -name "ml-notes-*" -exec cp {} dist/ \;
# List available files for debugging
echo "Available files:"
ls -la dist/
# Create CLI packages
# Linux CLI
if [ -f "dist/ml-notes-cli-linux-amd64" ]; then
tar -czf dist/release/ml-notes-cli-${VERSION}-linux-amd64.tar.gz -C dist ml-notes-cli-linux-amd64
fi
# macOS CLI (Intel)
if [ -f "dist/ml-notes-cli-darwin-amd64" ]; then
tar -czf dist/release/ml-notes-cli-${VERSION}-darwin-amd64.tar.gz -C dist ml-notes-cli-darwin-amd64
fi
# macOS CLI (Apple Silicon)
if [ -f "dist/ml-notes-cli-darwin-arm64" ]; then
tar -czf dist/release/ml-notes-cli-${VERSION}-darwin-arm64.tar.gz -C dist ml-notes-cli-darwin-arm64
fi
# Windows CLI
if [ -f "dist/ml-notes-cli-windows-amd64.exe" ]; then
cd dist && zip release/ml-notes-cli-${VERSION}-windows-amd64.zip ml-notes-cli-windows-amd64.exe
cd ..
fi
# Create Desktop packages
# Linux Desktop
if [ -f "dist/ml-notes-linux-amd64" ]; then
tar -czf dist/release/ml-notes-desktop-${VERSION}-linux-amd64.tar.gz -C dist ml-notes-linux-amd64
fi
# macOS Desktop (Universal)
if [ -f "dist/ml-notes-darwin-universal.tar.gz" ]; then
cp dist/ml-notes-darwin-universal.tar.gz dist/release/ml-notes-desktop-${VERSION}-darwin-universal.tar.gz
elif [ -f "dist/ml-notes-darwin-universal" ]; then
tar -czf dist/release/ml-notes-desktop-${VERSION}-darwin-universal.tar.gz -C dist ml-notes-darwin-universal
fi
# Windows Desktop
if [ -f "dist/ml-notes-windows-amd64.exe" ]; then
cd dist && zip release/ml-notes-desktop-${VERSION}-windows-amd64.zip ml-notes-windows-amd64.exe
cd ..
fi
# Create checksums
cd dist/release
sha256sum * > checksums.txt
# Create installation README
cat > README.md << EOF
# ML Notes ${VERSION} - Release Packages
ML Notes provides two distinct binaries:
- **CLI Binary** (\`ml-notes-cli\`): Command-line interface for terminal usage, automation, and MCP server
- **Desktop App** (\`ml-notes\`): Native desktop application with GUI
## Download the right package for your platform:
### Command-Line Interface (CLI)
- **Linux x64**: \`ml-notes-cli-${VERSION}-linux-amd64.tar.gz\`
- **macOS Intel**: \`ml-notes-cli-${VERSION}-darwin-amd64.tar.gz\`
- **macOS Apple Silicon**: \`ml-notes-cli-${VERSION}-darwin-arm64.tar.gz\`
- **Windows x64**: \`ml-notes-cli-${VERSION}-windows-amd64.zip\`
### Desktop Application
- **Linux x64**: \`ml-notes-desktop-${VERSION}-linux-amd64.tar.gz\`
- **macOS Universal**: \`ml-notes-desktop-${VERSION}-darwin-universal.tar.gz\`
- **Windows x64**: \`ml-notes-desktop-${VERSION}-windows-amd64.zip\`
## Installation
### CLI Binary (Linux/macOS)
1. Download the appropriate CLI \`.tar.gz\` file
2. Extract: \`tar -xzf ml-notes-cli-${VERSION}-<platform>.tar.gz\`
3. Install: \`sudo mv ml-notes-cli-<platform> /usr/local/bin/ml-notes-cli\`
4. Initialize: \`ml-notes-cli init\`
### CLI Binary (Windows)
1. Download \`ml-notes-cli-${VERSION}-windows-amd64.zip\`
2. Extract the ZIP file
3. Add the extracted directory to your PATH
4. Initialize: \`ml-notes-cli init\`
### Desktop Application (Linux/macOS)
1. Download the appropriate desktop \`.tar.gz\` file
2. Extract: \`tar -xzf ml-notes-desktop-${VERSION}-<platform>.tar.gz\`
3. Linux: \`sudo mv ml-notes-<platform> /usr/local/bin/ml-notes\`
4. macOS: Move \`ml-notes.app\` to \`/Applications/\`
### Desktop Application (Windows)
1. Download \`ml-notes-desktop-${VERSION}-windows-amd64.zip\`
2. Extract the ZIP file
3. Run \`ml-notes.exe\` or add to PATH
## Usage
### CLI Commands
\`\`\`bash
ml-notes-cli --version # Check version
ml-notes-cli init # Initialize configuration
ml-notes-cli add -t "Title" -c "Content" # Add note
ml-notes-cli serve # Start web interface
ml-notes-cli mcp # Run MCP server for Claude
\`\`\`
### Desktop Application
- Launch the desktop app and enjoy the native GUI experience
- All features available through visual interface
- Shares same configuration and data with CLI
## Verification
Verify your installation:
\`\`\`bash
ml-notes-cli --version # For CLI binary
ml-notes --version # For desktop binary (if in PATH)
\`\`\`
## Checksums
Verify download integrity using \`checksums.txt\`:
\`\`\`bash
sha256sum -c checksums.txt
\`\`\`
## Documentation
- Full documentation: https://github.com/streed/ml-notes
- CLI usage guide: See README.md in the repository
- Desktop app features: Built-in help and tooltips
EOF
- name: Upload release artifacts
uses: actions/upload-artifact@v4
with:
name: release-packages
path: dist/release/
retention-days: 1
- name: Create Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.release.outputs.version }}
name: Release ${{ needs.release.outputs.version }}
body: ${{ needs.release.outputs.changelog }}
draft: ${{ github.event.inputs.draft || false }}
prerelease: ${{ github.event.inputs.prerelease || false }}
files: |
dist/release/*.tar.gz
dist/release/*.zip
dist/release/checksums.txt
dist/release/README.md
fail_on_unmatched_files: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}