diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..9cfd949 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,7 @@ +{ + "permissions": { + "allow": [ + "Bash(Scripts/lint)" + ] + } +} diff --git a/.github/workflows/VerifyChanges.yaml b/.github/workflows/VerifyChanges.yaml index ddc9d96..54fe81c 100644 --- a/.github/workflows/VerifyChanges.yaml +++ b/.github/workflows/VerifyChanges.yaml @@ -6,38 +6,22 @@ on: push: branches: ["main"] -env: - XCODE_VERSION: 26.0.1 - jobs: - lint: - name: Lint - runs-on: macos-26 - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Select Xcode ${{ env.XCODE_VERSION }} - run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app - - name: Lint - run: | - Scripts/lint - build-and-test: name: Build and Test (${{ matrix.platform }}) - needs: lint runs-on: macos-26 strategy: fail-fast: false matrix: include: -# - platform: iOS -# xcode_destination: "platform=iOS Simulator,name=iPhone 17 Pro" + - platform: iOS + xcode_destination: "platform=iOS Simulator,name=iPhone 17 Pro" - platform: macOS xcode_destination: "platform=macOS,arch=arm64" -# - platform: tvOS -# xcode_destination: "platform=tvOS Simulator,name=Apple TV 4K (3rd generation)" -# - platform: watchOS -# xcode_destination: "platform=watchOS Simulator,name=Apple Watch Series 10 (46mm)" + - platform: tvOS + xcode_destination: "platform=tvOS Simulator,name=Apple TV 4K (3rd generation)" + - platform: watchOS + xcode_destination: "platform=watchOS Simulator,name=Apple Watch Series 11 (46mm)" env: DEV_BUILDS: DevBuilds/Sources @@ -47,16 +31,17 @@ jobs: XCODE_DESTINATION: ${{ matrix.xcode_destination }} XCODE_TEST_PLAN: DevTesting XCODE_TEST_PRODUCTS_PATH: .build/DevTesting.xctestproducts + XCODE_VERSION: 26.3 steps: - name: Select Xcode ${{ env.XCODE_VERSION }} - run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app + run: sudo xcode-select -s /Applications/Xcode_"$XCODE_VERSION".app - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Checkout DevBuilds - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: repository: DevKitOrganization/DevBuilds path: DevBuilds @@ -64,22 +49,25 @@ jobs: - name: Restore XCTestProducts if: github.event_name != 'push' id: cache-xctestproducts-restore - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 with: path: ${{ env.XCODE_TEST_PRODUCTS_PATH }} key: cache-xctestproducts-${{ github.workflow }}-${{ matrix.platform }}-${{ github.sha }} + - name: Lint + if: steps.cache-xctestproducts-restore.outputs.cache-hit != 'true' + run: Scripts/lint + - uses: irgaly/xcode-cache@v1 if: steps.cache-xctestproducts-restore.outputs.cache-hit != 'true' with: - key: xcode-cache-deriveddata-${{ github.workflow }}-${{ matrix.platform }}-${{ github.sha }} + key: xcode-cache-deriveddata-${{ env.XCODE_VERSION }}-${{ github.workflow }}-${{ matrix.platform }}-${{ github.sha }} restore-keys: | - xcode-cache-deriveddata-${{ github.workflow }}-${{ matrix.platform }}- - xcode-cache-deriveddata- + xcode-cache-deriveddata-${{ env.XCODE_VERSION }}-${{ github.workflow }}-${{ matrix.platform }}- + xcode-cache-deriveddata-${{ env.XCODE_VERSION }} deriveddata-directory: .build/DerivedData sourcepackages-directory: .build/DerivedData/SourcePackages swiftpm-package-resolved-file: Package.resolved - verbose: true - name: Build for Testing id: build-for-testing @@ -92,8 +80,8 @@ jobs: run: ${{ env.DEV_BUILDS }}/build_and_test.sh --action test-without-building - name: Save XCTestProducts - if: failure() && steps.cache-xctestproducts-restore.outputs.cache-hit != 'true' - uses: actions/cache/save@v4 + if: (cancelled() || failure()) && steps.cache-xctestproducts-restore.outputs.cache-hit != 'true' + uses: actions/cache/save@v5 with: path: ${{ env.XCODE_TEST_PRODUCTS_PATH }} key: ${{ steps.cache-xctestproducts-restore.outputs.cache-primary-key }} @@ -116,7 +104,7 @@ jobs: - name: Upload Logs and XCResults if: success() || failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: Logs_and_XCResults-${{ matrix.platform }} path: | @@ -126,7 +114,7 @@ jobs: - name: Upload xccovPretty output if: github.event_name != 'push' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: xccovPrettyOutput-${{ matrix.platform }} path: .build/xccovPretty-${{ matrix.platform }}.output @@ -142,7 +130,7 @@ jobs: steps: - name: Download xccovPretty output - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: xccovPrettyOutput-macOS diff --git a/.swift-format b/.swift-format index 84042b2..6e99bc1 100644 --- a/.swift-format +++ b/.swift-format @@ -59,14 +59,14 @@ "ReplaceForEachWithForLoop": true, "ReturnVoidInsteadOfEmptyTuple": true, "TypeNamesShouldBeCapitalized": true, - "UseEarlyExits": true, + "UseEarlyExits": false, "UseExplicitNilCheckInConditions": true, "UseLetInEveryBoundCaseVariable": true, "UseShorthandTypeNames": true, "UseSingleLinePropertyGetter": true, "UseSynthesizedInitializer": true, "UseTripleSlashForDocumentationComments": true, - "UseWhereClausesInForLoops": true, + "UseWhereClausesInForLoops": false, "ValidateDocumentationComments": false }, "spacesAroundRangeFormationOperators": true, diff --git a/CLAUDE.md b/CLAUDE.md index 633bfb4..696cdf5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -23,17 +23,11 @@ repository. - **Swift format configuration**: Uses `.swift-format` file with 4-space indentation and 120 character line length -### Platform Testing - - - **Test all platforms**: `Scripts/test-all-platforms` (runs tests on iOS, macOS, tvOS, and - watchOS simulators using xcodebuild) - ### Git Hooks - - **Install git hooks**: `Scripts/install-git-hooks` (installs both pre-commit and pre-push - hooks) - - **Pre-commit hook**: Automatically runs `Scripts/lint` before each commit - - **Pre-push hook**: Automatically runs `Scripts/test-all-platforms` before each push + - **Install git hooks**: `Scripts/install-git-hooks` (installs pre-push hook; supports git + worktrees) + - **Pre-push hook**: Automatically runs `Scripts/lint` before each push ### Documentation @@ -80,8 +74,28 @@ reproducibility. - **Test Plans**: Uses `DevTesting.xctestplan` for organized test execution - **Coverage Target**: Aims for 99%+ test coverage - **Platform Testing**: Tests run on iOS, macOS, tvOS, and watchOS simulators - - **CI/CD**: GitHub Actions workflow runs builds on macOS only (iOS, tvOS, and watchOS builds - disabled due to stability/reliability issues) + - **CI/CD**: GitHub Actions workflow runs builds on iOS, macOS, tvOS, and watchOS + +### Code Style Conventions + + - Always use `where` clauses to declare constraints on generic parameters + - Prefer `Float64` over `Double` and `Float32` over `Float` + - Always attribute files to the current user, not Claude (e.g., "Created by + on mm/dd/yyyy") + +#### Code Formatting and Spacing + + - **2 blank lines between major sections** including: + - Between the last property declaration and first function declaration + - Between all function/computed property implementations at the same scope level + - Between top-level type declarations (class, struct, enum, protocol, extension) + - Before MARK comments that separate major sections + - **1 blank line** for minor separations: + - Between property declarations and nested type definitions + - Between all function definitions in protocols + - After headers in documentation + - After MARK comments that separate major sections + - **File endings**: All Swift files must end with exactly one blank line ### Documentation Standards diff --git a/Documentation/MarkdownStyleGuide.md b/Documentation/MarkdownStyleGuide.md index d94f75c..297157f 100644 --- a/Documentation/MarkdownStyleGuide.md +++ b/Documentation/MarkdownStyleGuide.md @@ -1,7 +1,6 @@ # Markdown Style Guide -This document defines the Markdown formatting standards for documentation in the Shopper iOS -codebase. +This document defines the Markdown formatting standards for documentation in this codebase. ## General Formatting diff --git a/README.md b/README.md index 77aca97..fb0e67f 100644 --- a/README.md +++ b/README.md @@ -38,10 +38,10 @@ interfaces are fully documented and tested. We aim for overall test coverage ove To set up the development environment: - 1. Run `Scripts/install-git-hooks` to install git hooks that automatically check code - formatting on commits and run comprehensive tests before pushing. + 1. Run `Scripts/install-git-hooks` to install the pre-push hook that automatically checks + code formatting before pushing. 2. Use `Scripts/lint` to manually check code formatting at any time. - 3. Use `Scripts/test-all-platforms` to run tests on all supported platforms locally. + 3. Use `Scripts/format` to auto-fix code formatting issues. ## Continuous Integration @@ -49,14 +49,9 @@ To set up the development environment: DevTesting uses GitHub Actions for continuous integration. The CI pipeline: - **Linting**: Automatically checks code formatting on all pull requests using `swift format` - - **Testing**: Runs tests on macOS (iOS, tvOS, and watchOS testing are disabled in CI due to - reliability issues) + - **Testing**: Runs tests on iOS, macOS, tvOS, and watchOS - **Coverage**: Generates code coverage reports using xccovPretty -For comprehensive cross-platform testing, developers should run `Scripts/test-all-platforms` -locally or rely on the pre-push git hook which automatically runs all platform tests before -pushing changes. - ## Bugs and Feature Requests diff --git a/Scripts/format b/Scripts/format index d762974..a450349 100755 --- a/Scripts/format +++ b/Scripts/format @@ -8,6 +8,5 @@ REPO_ROOT="$(dirname "$SCRIPT_DIR")" # Run swift format with --in-place to fix formatting issues swift format --in-place --recursive \ - "$REPO_ROOT/Packages/" \ "$REPO_ROOT/Sources/" \ "$REPO_ROOT/Tests/" diff --git a/Scripts/install-git-hooks b/Scripts/install-git-hooks index e29caa6..56d6935 100755 --- a/Scripts/install-git-hooks +++ b/Scripts/install-git-hooks @@ -6,78 +6,51 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # Go to the repository root (one level up from Scripts) REPO_ROOT="$(dirname "$SCRIPT_DIR")" -# Check if we're in a git repository -if [ ! -d "$REPO_ROOT/.git" ]; then +# Check if we're in a git repository and get the git directory +# This works for both regular repos and worktrees +cd "$REPO_ROOT" +if ! git rev-parse --git-dir > /dev/null 2>&1; then echo "Error: Not in a git repository" exit 1 fi -mkdir -p "$REPO_ROOT/.git/hooks" - -# Function to install the pre-commit hook -install_pre_commit_hook() { - local pre_commit_hook="$REPO_ROOT/.git/hooks/pre-commit" - - echo "Installing pre-commit hook..." - - cat > "$pre_commit_hook" << 'EOF' -#!/bin/bash - -# Get the directory where this hook is located -HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -# Go to the repository root (two levels up from .git/hooks) -REPO_ROOT="$(dirname "$(dirname "$HOOK_DIR")")" - -# Run the lint script -echo "Running lint check..." -if ! "$REPO_ROOT/Scripts/lint"; then - echo "Lint check failed. Please fix formatting issues before committing." +# Get the common git directory (shared across all worktrees) +GIT_COMMON_DIR="$(git rev-parse --git-common-dir)" +if [ ! -d "$GIT_COMMON_DIR" ]; then + echo "Error: Could not find git directory" exit 1 fi -echo "Lint check passed." -EOF - - chmod +x "$pre_commit_hook" - echo "Pre-commit hook installed successfully!" -} +mkdir -p "$GIT_COMMON_DIR/hooks" # Function to install the pre-push hook install_pre_push_hook() { - local pre_push_hook="$REPO_ROOT/.git/hooks/pre-push" + local pre_push_hook="$GIT_COMMON_DIR/hooks/pre-push" echo "Installing pre-push hook..." cat > "$pre_push_hook" << 'EOF' #!/bin/bash -# Get the directory where this hook is located -HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -# Go to the repository root (two levels up from .git/hooks) -REPO_ROOT="$(dirname "$(dirname "$HOOK_DIR")")" +# Resolve the repository root using git, which correctly handles worktrees +REPO_ROOT="$(git rev-parse --show-toplevel)" -# Run the test-all-platforms script -echo "Running tests on all platforms..." -if ! "$REPO_ROOT/Scripts/test-all-platforms"; then - echo "Platform tests failed. Please fix issues before pushing." +# Run the lint script +echo "Running lint check..." +if ! "$REPO_ROOT/Scripts/lint"; then + echo "Lint check failed. Please fix formatting issues before pushing." exit 1 fi -echo "All platform tests passed." +echo "Lint check passed." EOF chmod +x "$pre_push_hook" echo "Pre-push hook installed successfully!" } -# Install the pre-commit hook -install_pre_commit_hook - # Install the pre-push hook install_pre_push_hook echo "All git hooks installed successfully!" -echo "The pre-commit hook will run 'Scripts/lint' before each commit." -echo "The pre-push hook will run 'Scripts/test-all-platforms' before each push." +echo "The pre-push hook will run 'Scripts/lint' before each push." diff --git a/Scripts/test-all-platforms b/Scripts/test-all-platforms deleted file mode 100755 index f756cc8..0000000 --- a/Scripts/test-all-platforms +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -# Function to print colored output -print_status() { - echo -e "${YELLOW}[$(date +'%H:%M:%S')] $1${NC}" -} - -print_success() { - echo -e "${GREEN}✓ $1${NC}" -} - -print_error() { - echo -e "${RED}✗ $1${NC}" -} - -# Platforms to test -PLATFORMS=( - "iOS Simulator,name=iPhone 17 Pro" - "macOS" - "tvOS Simulator,name=Apple TV 4K" - "watchOS Simulator,name=Apple Watch Series 10" -) - -SCHEME="DevTesting" -FAILED_PLATFORMS=() - -print_status "Starting tests on all platforms..." -echo - -for platform in "${PLATFORMS[@]}"; do - platform_name=$(echo "$platform" | cut -d',' -f1) - print_status "Testing on $platform_name..." - - if xcodebuild test -scheme "$SCHEME" -destination "platform=$platform"; then - print_success "$platform_name tests passed" - else - print_error "$platform_name tests failed" - FAILED_PLATFORMS+=("$platform_name") - fi - echo -done - -# Summary -echo "==========================" -if [ ${#FAILED_PLATFORMS[@]} -eq 0 ]; then - print_success "All platform tests passed!" - exit 0 -else - print_error "Tests failed on: ${FAILED_PLATFORMS[*]}" - exit 1 -fi