diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d943a14 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,55 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + test-macos: + name: Test on macOS + runs-on: macos-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Check Swift version + run: swift --version + + - name: Build + run: swift build + + - name: Run tests + run: swift test + + - name: Build CLI + run: swift build -c release + + test-linux: + name: Test on Linux + runs-on: ubuntu-latest + container: + image: swift:5.9 + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install dependencies + run: | + apt-get update + apt-get install -y libsodium-dev + + - name: Check Swift version + run: swift --version + + - name: Build + run: swift build + + - name: Run tests + run: swift test + + - name: Build CLI + run: swift build -c release diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..a4d33e0 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,126 @@ +name: Release + +on: + push: + tags: + - 'v*' + +jobs: + build-macos: + name: Build macOS Universal Binary + runs-on: macos-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Check Swift version + run: swift --version + + - name: Get version from tag + id: get_version + run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT + + - name: Run tests + run: swift test + + - name: Build release binary + run: ./scripts/build-release.sh ${{ steps.get_version.outputs.VERSION }} + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: macos-universal + path: | + release/*.tar.gz + release/*.sha256 + + create-release: + name: Create GitHub Release + needs: [build-macos] + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Download macOS artifact + uses: actions/download-artifact@v4 + with: + name: macos-universal + path: release/ + + - name: Get version from tag + id: get_version + run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT + + - name: Generate release notes + id: release_notes + run: | + cat > release_notes.md << 'EOF' + ## Installation + + ### macOS (Universal Binary - x86_64 + ARM64) + + Download and install: + ```bash + curl -L https://github.com/${{ github.repository }}/releases/download/v${{ steps.get_version.outputs.VERSION }}/ejson-${{ steps.get_version.outputs.VERSION }}-macos-universal.tar.gz | tar xz + sudo mv ejson /usr/local/bin/ + ejson --version + ``` + + Or with wget: + ```bash + wget https://github.com/${{ github.repository }}/releases/download/v${{ steps.get_version.outputs.VERSION }}/ejson-${{ steps.get_version.outputs.VERSION }}-macos-universal.tar.gz + tar xzf ejson-${{ steps.get_version.outputs.VERSION }}-macos-universal.tar.gz + sudo mv ejson /usr/local/bin/ + ejson --version + ``` + + ### Verify Checksum + + ```bash + # Download checksum file + curl -L https://github.com/${{ github.repository }}/releases/download/v${{ steps.get_version.outputs.VERSION }}/ejson-${{ steps.get_version.outputs.VERSION }}-macos-universal.tar.gz.sha256 -o ejson.sha256 + + # Verify (macOS) + shasum -a 256 -c ejson.sha256 + + # Verify (Linux) + sha256sum -c ejson.sha256 + ``` + + ## Features + + - 🔐 NaCl Box encryption compatible with Shopify EJSON + - 🔄 Full compatibility with Go EJSON implementation + - ⚡ Fast and native Swift implementation + - 📦 Universal macOS binary (works on both Intel and Apple Silicon) + + ## Usage + + ```bash + # Generate a keypair + ejson keygen + + # Encrypt a file + ejson encrypt secrets.json + + # Decrypt a file + ejson decrypt secrets.json + ``` + + For more information, see the [README](https://github.com/${{ github.repository }}/blob/main/README.md). + EOF + + - name: Create Release + uses: softprops/action-gh-release@v2 + with: + body_path: release_notes.md + files: | + release/*.tar.gz + release/*.sha256 + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 52fe2f7..8597743 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,7 @@ playground.xcworkspace # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. # Packages/ # Package.pins -# Package.resolved +Package.resolved # *.xcodeproj # # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata @@ -30,6 +30,7 @@ playground.xcworkspace # .swiftpm .build/ +release/ # CocoaPods # diff --git a/CLAUDE.md b/CLAUDE.md index cb5eb37..50fead3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -168,21 +168,20 @@ The library has been fully implemented with: ## Installing Swift for Testing -This project requires **Swift 6.2** or later. +This project requires **Swift 5.9** or later. ### Prerequisites -**IMPORTANT:** Install libsodium first (required for EJSONKit cryptography): +**Linux only:** Install libsodium-dev (required for EJSONKit cryptography on Linux): ```bash # Ubuntu/Debian sudo apt-get update sudo apt-get install -y libsodium-dev - -# macOS (using Homebrew) -brew install libsodium ``` +**macOS:** No additional dependencies needed. The swift-sodium package includes bundled libsodium (Clibsodium.xcframework) for Apple platforms. + ### Option 1: Direct Download from swift.org (Recommended) This is the most reliable method for getting Swift 6.2.1. @@ -310,7 +309,7 @@ warning: Using a system installation of libsodium - This is unsupported. Build complete! (2.00s) ``` -**Note:** The warning about using system libsodium is expected and safe to ignore. The library will work correctly with the system-installed libsodium. +**Note:** On Linux, you may see a warning "Using a system installation of libsodium - This is unsupported." This is expected and safe to ignore. The library will work correctly with the system-installed libsodium. On macOS, the bundled Clibsodium.xcframework is used automatically with no warnings. ### Run the test suite ```bash diff --git a/Package.resolved b/Package.resolved deleted file mode 100644 index fb5a8ee..0000000 --- a/Package.resolved +++ /dev/null @@ -1,15 +0,0 @@ -{ - "originHash" : "acad41c00966a27673a0ecefcefc1a31e23fc11ed83aaf43526d2c90046e64cb", - "pins" : [ - { - "identity" : "swift-sodium", - "kind" : "remoteSourceControl", - "location" : "https://github.com/jedisct1/swift-sodium.git", - "state" : { - "revision" : "4f9164a0a2c9a6a7ff53a2833d54a5c79c957342", - "version" : "0.9.1" - } - } - ], - "version" : 3 -} diff --git a/Package.swift b/Package.swift index 266144b..716de82 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 6.2 +// swift-tools-version: 5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription diff --git a/README.md b/README.md index 328d6c4..f64e592 100644 --- a/README.md +++ b/README.md @@ -284,18 +284,51 @@ EJSONKit includes a command-line tool compatible with the [Go EJSON CLI](https:/ ### Installation -Build the CLI: +#### Pre-built Binaries (Recommended) + +Download the latest release for your platform from [GitHub Releases](https://github.com/diogot/swift-ejson/releases): + +**macOS (Universal Binary - Intel & Apple Silicon):** ```bash -swift build -c release +# Download and install the latest version +VERSION="1.0.0" # Replace with latest version +curl -L "https://github.com/diogot/swift-ejson/releases/download/v${VERSION}/ejson-${VERSION}-macos-universal.tar.gz" | tar xz +sudo mv ejson /usr/local/bin/ +ejson help ``` -The executable will be at `.build/release/ejson`. You can copy it to your PATH: +**Verify the checksum:** ```bash +# Download checksum +curl -L "https://github.com/diogot/swift-ejson/releases/download/v${VERSION}/ejson-${VERSION}-macos-universal.tar.gz.sha256" -o ejson.sha256 + +# Verify +shasum -a 256 -c ejson.sha256 +``` + +#### Build from Source + +If you prefer to build from source: + +```bash +# Clone the repository +git clone https://github.com/diogot/swift-ejson.git +cd swift-ejson + +# Build the CLI +swift build -c release + +# Install to PATH cp .build/release/ejson /usr/local/bin/ ``` +**Requirements:** +- Swift 5.9+ +- Linux only: libsodium-dev (`apt-get install libsodium-dev`) +- macOS: No additional dependencies (uses bundled libsodium) + ### Usage ``` @@ -391,12 +424,13 @@ swift test ## Dependencies -- [swift-sodium](https://github.com/jedisct1/swift-sodium) (v0.9.1+) - Provides NaCl cryptography primitives +- [swift-sodium](https://github.com/jedisct1/swift-sodium) (v0.9.1+) - Provides NaCl cryptography primitives with bundled libsodium ## Requirements -- Swift 6.2+ +- Swift 5.9+ - macOS 10.15+ / iOS 13+ / tvOS 13+ / watchOS 6+ +- Linux: libsodium-dev package required ## Contributing diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 0000000..646cf53 --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,150 @@ +# Release Process + +This document describes how to create a new release of swift-ejson. + +## Prerequisites + +- Write access to the repository +- All tests passing on main branch +- Updated CHANGELOG (if applicable) + +## Release Steps + +### 1. Prepare the Release + +Ensure all changes for the release are merged to the main branch: + +```bash +git checkout main +git pull origin main +``` + +### 2. Update Version References + +Update version references in documentation if needed: + +- README.md (example version numbers in CLI installation) +- Package.swift (if you maintain a version constant) + +### 3. Create and Push a Tag + +Create a version tag following semantic versioning (vMAJOR.MINOR.PATCH): + +```bash +# Create an annotated tag +git tag -a v1.0.0 -m "Release version 1.0.0" + +# Push the tag to GitHub +git push origin v1.0.0 +``` + +### 4. Automated Build Process + +Once you push the tag, GitHub Actions will automatically: + +1. **Run Tests** - Ensure all tests pass on macOS and Linux +2. **Build macOS Binary** - Create a universal binary (x86_64 + ARM64) +3. **Create Archive** - Package the binary as `.tar.gz` +4. **Calculate Checksums** - Generate SHA256 checksums +5. **Create GitHub Release** - Publish release with all artifacts +6. **Upload Assets** - Attach binaries and checksums + +You can monitor the progress at: `https://github.com/diogot/swift-ejson/actions` + +### 5. Verify the Release + +After the workflow completes: + +1. Go to https://github.com/diogot/swift-ejson/releases +2. Verify the release was created with: + - Release notes + - Binary archive (`.tar.gz`) + - Checksum file (`.sha256`) + +### 6. Test the Release + +Download and test the binary: + +```bash +VERSION="1.0.0" +curl -L "https://github.com/diogot/swift-ejson/releases/download/v${VERSION}/ejson-${VERSION}-macos-universal.tar.gz" | tar xz +./ejson help +./ejson keygen +``` + +Verify the checksum: + +```bash +curl -L "https://github.com/diogot/swift-ejson/releases/download/v${VERSION}/ejson-${VERSION}-macos-universal.tar.gz.sha256" -o ejson.sha256 +shasum -a 256 -c ejson.sha256 +``` + +## Versioning Guidelines + +We follow [Semantic Versioning](https://semver.org/): + +- **MAJOR** version: Incompatible API changes +- **MINOR** version: New functionality (backwards compatible) +- **PATCH** version: Bug fixes (backwards compatible) + +Examples: +- `v1.0.0` - Initial stable release +- `v1.1.0` - Add new features +- `v1.0.1` - Bug fixes +- `v2.0.0` - Breaking changes + +## Troubleshooting + +### Build Fails + +If the GitHub Actions workflow fails: + +1. Check the Actions tab for error details +2. Fix issues in a new commit/PR +3. Delete the tag: `git tag -d v1.0.0 && git push origin :refs/tags/v1.0.0` +4. Create a new tag after fixes are merged + +### Release Already Exists + +If you need to update a release: + +1. Go to the Releases page +2. Edit the release +3. Delete old assets if needed +4. Manually upload new assets (or delete the release and re-run workflow) + +## Manual Release (Fallback) + +If automated builds fail, you can create a release manually: + +### Build Locally on macOS + +```bash +# Clean previous builds +rm -rf .build release + +# Run build script +./scripts/build-release.sh 1.0.0 + +# Verify the binary +./release/ejson help +``` + +### Create Release on GitHub + +1. Go to https://github.com/diogot/swift-ejson/releases/new +2. Choose the tag (v1.0.0) +3. Fill in the release title and description +4. Upload the files from `release/` directory: + - `ejson-1.0.0-macos-universal.tar.gz` + - `ejson-1.0.0-macos-universal.tar.gz.sha256` +5. Click "Publish release" + +## Post-Release + +After releasing: + +1. Announce the release (Twitter, forums, etc.) +2. Update documentation sites if applicable +3. Close related issues/PRs +4. Plan next release milestone diff --git a/scripts/build-release.sh b/scripts/build-release.sh new file mode 100755 index 0000000..cca500b --- /dev/null +++ b/scripts/build-release.sh @@ -0,0 +1,106 @@ +#!/bin/bash +set -e + +# Build script for creating release binaries of ejson CLI +# Supports building universal binaries for macOS (x86_64 + arm64) + +VERSION=${1:-"dev"} +PRODUCT_NAME="ejson" +BUILD_DIR=".build" +RELEASE_DIR="release" + +echo "Building ${PRODUCT_NAME} version ${VERSION}..." + +# Detect platform +if [[ "$OSTYPE" == "darwin"* ]]; then + PLATFORM="macos" +elif [[ "$OSTYPE" == "linux-gnu"* ]]; then + PLATFORM="linux" +else + echo "Unsupported platform: $OSTYPE" + exit 1 +fi + +# Clean previous builds +rm -rf "$BUILD_DIR" +rm -rf "$RELEASE_DIR" +mkdir -p "$RELEASE_DIR" + +if [[ "$PLATFORM" == "macos" ]]; then + echo "Building for macOS..." + + # Check if we can build universal binaries + if swift --version | grep -q "Apple Swift"; then + echo "Building universal binary (x86_64 + arm64)..." + + # Build for x86_64 + echo "Building for x86_64..." + swift build -c release --arch x86_64 + + # Build for arm64 + echo "Building for arm64..." + swift build -c release --arch arm64 + + # Create universal binary + echo "Creating universal binary..." + lipo -create \ + "$BUILD_DIR/x86_64-apple-macosx/release/$PRODUCT_NAME" \ + "$BUILD_DIR/arm64-apple-macosx/release/$PRODUCT_NAME" \ + -output "$RELEASE_DIR/$PRODUCT_NAME" + + ARCHIVE_NAME="${PRODUCT_NAME}-${VERSION}-macos-universal.tar.gz" + else + # Non-Apple Swift (shouldn't happen on macOS, but just in case) + echo "Building for current architecture..." + swift build -c release + cp "$BUILD_DIR/release/$PRODUCT_NAME" "$RELEASE_DIR/" + ARCHIVE_NAME="${PRODUCT_NAME}-${VERSION}-macos.tar.gz" + fi + +elif [[ "$PLATFORM" == "linux" ]]; then + echo "Building for Linux..." + swift build -c release + cp "$BUILD_DIR/release/$PRODUCT_NAME" "$RELEASE_DIR/" + ARCHIVE_NAME="${PRODUCT_NAME}-${VERSION}-linux-$(uname -m).tar.gz" +fi + +# Verify the binary +echo "Verifying binary..." +"$RELEASE_DIR/$PRODUCT_NAME" --version 2>&1 || "$RELEASE_DIR/$PRODUCT_NAME" help > /dev/null + +# Create archive +echo "Creating archive: $ARCHIVE_NAME" +cd "$RELEASE_DIR" +tar -czf "$ARCHIVE_NAME" "$PRODUCT_NAME" +cd .. + +# Calculate checksums +echo "Calculating checksums..." +if command -v sha256sum &> /dev/null; then + sha256sum "$RELEASE_DIR/$ARCHIVE_NAME" > "$RELEASE_DIR/$ARCHIVE_NAME.sha256" +elif command -v shasum &> /dev/null; then + shasum -a 256 "$RELEASE_DIR/$ARCHIVE_NAME" > "$RELEASE_DIR/$ARCHIVE_NAME.sha256" +fi + +echo "" +echo "Build complete!" +echo "Binary: $RELEASE_DIR/$PRODUCT_NAME" +echo "Archive: $RELEASE_DIR/$ARCHIVE_NAME" +if [[ -f "$RELEASE_DIR/$ARCHIVE_NAME.sha256" ]]; then + echo "Checksum: $RELEASE_DIR/$ARCHIVE_NAME.sha256" + cat "$RELEASE_DIR/$ARCHIVE_NAME.sha256" +fi + +# Show binary info +echo "" +echo "Binary info:" +if [[ "$PLATFORM" == "macos" ]]; then + file "$RELEASE_DIR/$PRODUCT_NAME" + if command -v lipo &> /dev/null; then + lipo -info "$RELEASE_DIR/$PRODUCT_NAME" + fi +else + file "$RELEASE_DIR/$PRODUCT_NAME" +fi + +ls -lh "$RELEASE_DIR/"