diff --git a/.github/workflows/build-plugin.yml b/.github/workflows/build-plugin.yml index c66ef778..e8ebf9ef 100644 --- a/.github/workflows/build-plugin.yml +++ b/.github/workflows/build-plugin.yml @@ -17,15 +17,40 @@ env: XCODE_PROJECT: TablePro.xcodeproj jobs: + resolve-tags: + name: Resolve Plugin Tags + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.tags.outputs.matrix }} + steps: + - id: tags + run: | + if [ -n "${{ inputs.tags }}" ]; then + IFS=',' read -ra TAGS <<< "${{ inputs.tags }}" + else + TAGS=("${{ github.ref_name }}") + fi + JSON='{"include":[' + FIRST=true + for TAG in "${TAGS[@]}"; do + TAG=$(echo "$TAG" | xargs) + if [ "$FIRST" = true ]; then FIRST=false; else JSON+=','; fi + JSON+="{\"tag\":\"$TAG\"}" + done + JSON+=']}' + echo "matrix=$JSON" >> "$GITHUB_OUTPUT" + echo "Matrix: $JSON" + build-plugin: - name: Build Plugin - runs-on: self-hosted - timeout-minutes: 60 + name: "Build ${{ matrix.tag }}" + needs: resolve-tags + runs-on: macos-15 + timeout-minutes: 30 + strategy: + matrix: ${{ fromJson(needs.resolve-tags.outputs.matrix) }} + fail-fast: false steps: - - name: Install Git LFS - run: brew list git-lfs &>/dev/null || brew install git-lfs; git lfs install - - name: Checkout code uses: actions/checkout@v4 with: @@ -34,17 +59,44 @@ jobs: - name: Pull LFS files run: git lfs pull - - name: Build and release plugins + - name: Select Xcode + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: "26.2" + + - name: Import signing certificate + env: + CERTIFICATES_P12: ${{ secrets.CERTIFICATES_P12 }} + CERTIFICATES_PASSWORD: ${{ secrets.CERTIFICATES_PASSWORD }} + run: | + KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db + security create-keychain -p "" "$KEYCHAIN_PATH" + security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" + security unlock-keychain -p "" "$KEYCHAIN_PATH" + echo "$CERTIFICATES_P12" | base64 --decode > $RUNNER_TEMP/certificate.p12 + security import $RUNNER_TEMP/certificate.p12 -P "$CERTIFICATES_PASSWORD" \ + -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" + security set-key-partition-list -S apple-tool:,apple: -k "" "$KEYCHAIN_PATH" + security list-keychain -d user -s "$KEYCHAIN_PATH" login.keychain + + - name: Configure notarization + env: + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + NOTARY_PASSWORD: ${{ secrets.NOTARY_PASSWORD }} + run: | + xcrun notarytool store-credentials "TablePro" \ + --apple-id "$APPLE_ID" \ + --team-id "$APPLE_TEAM_ID" \ + --password "$NOTARY_PASSWORD" + + - name: Build and release plugin env: REGISTRY_DEPLOY_KEY: ${{ secrets.REGISTRY_DEPLOY_KEY }} GH_TOKEN: ${{ github.token }} run: | - # Build tag list: from input (comma-separated) or from push event (single tag) - if [ -n "${{ inputs.tags }}" ]; then - IFS=',' read -ra TAGS <<< "${{ inputs.tags }}" - else - TAGS=("${{ github.ref_name }}") - fi + TAG="${{ matrix.tag }}" + echo "Processing: $TAG" # Get current app version for minAppVersion MIN_APP_VERSION=$(sed -n 's/.*MARKETING_VERSION = \(.*\);/\1/p' \ @@ -112,46 +164,37 @@ jobs: esac } - for TAG in "${TAGS[@]}"; do - TAG=$(echo "$TAG" | xargs) # trim whitespace - echo "" - echo "========================================" - echo "Processing: $TAG" - echo "========================================" - - PLUGIN_NAME=$(echo "$TAG" | sed -E 's/^plugin-([a-z]+)-v.*$/\1/') - VERSION=$(echo "$TAG" | sed -E 's/^plugin-[a-z]+-v(.*)$/\1/') - - resolve_plugin_info "$PLUGIN_NAME" || continue - - echo "Building $TARGET v$VERSION" - - # Build Cassandra dependencies if needed - if [ "$PLUGIN_NAME" = "cassandra" ]; then - ./scripts/build-cassandra.sh both - fi - - # Build both architectures - ./scripts/build-plugin.sh "$TARGET" arm64 - ./scripts/build-plugin.sh "$TARGET" x86_64 - - # Capture SHA-256 - ARM64_SHA=$(cat "build/Plugins/${BUNDLE_NAME}-arm64.zip.sha256") - X86_SHA=$(cat "build/Plugins/${BUNDLE_NAME}-x86_64.zip.sha256") - - # Notarize if enabled - if [ "${NOTARIZE_PLUGINS:-}" = "true" ]; then - for zip in build/Plugins/${BUNDLE_NAME}-*.zip; do - xcrun notarytool submit "$zip" \ - --apple-id "$APPLE_ID" \ - --team-id "D7HJ5TFYCU" \ - --keychain-profile "notarytool-profile" \ - --wait - done - fi - - # Create GitHub Release - RELEASE_BODY="## $DISPLAY_NAME v$VERSION + PLUGIN_NAME=$(echo "$TAG" | sed -E 's/^plugin-([a-z]+)-v.*$/\1/') + VERSION=$(echo "$TAG" | sed -E 's/^plugin-[a-z]+-v(.*)$/\1/') + + resolve_plugin_info "$PLUGIN_NAME" + + echo "Building $TARGET v$VERSION" + + # Build Cassandra dependencies if needed + if [ "$PLUGIN_NAME" = "cassandra" ]; then + ./scripts/build-cassandra.sh both + fi + + # Build both architectures + ./scripts/build-plugin.sh "$TARGET" arm64 + ./scripts/build-plugin.sh "$TARGET" x86_64 + + # Capture SHA-256 + ARM64_SHA=$(cat "build/Plugins/${BUNDLE_NAME}-arm64.zip.sha256") + X86_SHA=$(cat "build/Plugins/${BUNDLE_NAME}-x86_64.zip.sha256") + + # Notarize if enabled + if [ "${NOTARIZE_PLUGINS:-}" = "true" ]; then + for zip in build/Plugins/${BUNDLE_NAME}-*.zip; do + xcrun notarytool submit "$zip" \ + --keychain-profile "TablePro" \ + --wait + done + fi + + # Create GitHub Release + RELEASE_BODY="## $DISPLAY_NAME v$VERSION Plugin release for TablePro. @@ -162,33 +205,33 @@ jobs: - ARM64: \`$ARM64_SHA\` - x86_64: \`$X86_SHA\`" - # Delete existing release if any, then create - gh release delete "$TAG" --yes 2>/dev/null || true - gh release create "$TAG" \ - --title "$DISPLAY_NAME v$VERSION" \ - --notes "$RELEASE_BODY" \ - build/Plugins/${BUNDLE_NAME}-arm64.zip \ - build/Plugins/${BUNDLE_NAME}-x86_64.zip - - # Update plugin registry - if [ -n "${REGISTRY_DEPLOY_KEY:-}" ]; then - ARM64_URL="https://github.com/${{ github.repository }}/releases/download/${TAG}/${BUNDLE_NAME}-arm64.zip" - X86_64_URL="https://github.com/${{ github.repository }}/releases/download/${TAG}/${BUNDLE_NAME}-x86_64.zip" - - WORK=$(mktemp -d) - eval "$(ssh-agent -s)" - echo "$REGISTRY_DEPLOY_KEY" | ssh-add - - - git clone git@github.com:datlechin/tablepro-plugins.git "$WORK/registry" - cd "$WORK/registry" - git pull --rebase origin main - - python3 - \ - "$BUNDLE_ID" "$DISPLAY_NAME" "$VERSION" "$SUMMARY" \ - "$DB_TYPE_IDS" "$ARM64_URL" "$ARM64_SHA" \ - "$X86_64_URL" "$X86_SHA" "$MIN_APP_VERSION" \ - "$ICON" "$HOMEPAGE" "$CATEGORY" \ - <<'PYTHON_SCRIPT' + # Delete existing release if any, then create + gh release delete "$TAG" --yes 2>/dev/null || true + gh release create "$TAG" \ + --title "$DISPLAY_NAME v$VERSION" \ + --notes "$RELEASE_BODY" \ + build/Plugins/${BUNDLE_NAME}-arm64.zip \ + build/Plugins/${BUNDLE_NAME}-x86_64.zip + + # Update plugin registry + if [ -n "${REGISTRY_DEPLOY_KEY:-}" ]; then + ARM64_URL="https://github.com/${{ github.repository }}/releases/download/${TAG}/${BUNDLE_NAME}-arm64.zip" + X86_64_URL="https://github.com/${{ github.repository }}/releases/download/${TAG}/${BUNDLE_NAME}-x86_64.zip" + + WORK=$(mktemp -d) + eval "$(ssh-agent -s)" + echo "$REGISTRY_DEPLOY_KEY" | ssh-add - + + git clone git@github.com:datlechin/tablepro-plugins.git "$WORK/registry" + cd "$WORK/registry" + git pull --rebase origin main + + python3 - \ + "$BUNDLE_ID" "$DISPLAY_NAME" "$VERSION" "$SUMMARY" \ + "$DB_TYPE_IDS" "$ARM64_URL" "$ARM64_SHA" \ + "$X86_64_URL" "$X86_SHA" "$MIN_APP_VERSION" \ + "$ICON" "$HOMEPAGE" "$CATEGORY" \ + <<'PYTHON_SCRIPT' import json, sys bundle_id, name, version, summary = sys.argv[1:5] @@ -225,25 +268,16 @@ jobs: f.write("\n") PYTHON_SCRIPT - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add plugins.json - git commit -m "Update $DISPLAY_NAME to v$VERSION" - git push + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add plugins.json + git commit -m "Update $DISPLAY_NAME to v$VERSION" + git push - ssh-add -D - eval "$(ssh-agent -k)" - cd - - rm -rf "$WORK" - fi - - # Clean plugin build artifacts for next iteration - rm -f build/Plugins/${BUNDLE_NAME}-*.zip build/Plugins/${BUNDLE_NAME}-*.sha256 - - echo "✅ $DISPLAY_NAME v$VERSION released" - done + ssh-add -D + eval "$(ssh-agent -k)" + cd - + rm -rf "$WORK" + fi - echo "" - echo "========================================" - echo "All plugins processed!" - echo "========================================" + echo "$DISPLAY_NAME v$VERSION released" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f71284d1..19576893 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ env: jobs: lint: name: SwiftLint - runs-on: self-hosted + runs-on: macos-15 timeout-minutes: 10 steps: @@ -31,19 +31,21 @@ jobs: build-arm64: name: Build ARM64 - runs-on: self-hosted + runs-on: macos-15 needs: lint timeout-minutes: 20 steps: - - name: Install Git LFS - run: brew list git-lfs &>/dev/null || brew install git-lfs; git lfs install - - name: Checkout code uses: actions/checkout@v4 with: lfs: true + - name: Select Xcode + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: '26.2' + - name: Pull LFS files run: git lfs pull @@ -78,6 +80,32 @@ jobs: ANALYTICS_HMAC_SECRET: ${{ secrets.ANALYTICS_HMAC_SECRET }} run: echo "ANALYTICS_HMAC_SECRET = ${ANALYTICS_HMAC_SECRET}" > Secrets.xcconfig + - name: Import signing certificate + env: + CERTIFICATES_P12: ${{ secrets.CERTIFICATES_P12 }} + CERTIFICATES_PASSWORD: ${{ secrets.CERTIFICATES_PASSWORD }} + run: | + KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db + security create-keychain -p "" "$KEYCHAIN_PATH" + security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" + security unlock-keychain -p "" "$KEYCHAIN_PATH" + echo "$CERTIFICATES_P12" | base64 --decode > $RUNNER_TEMP/certificate.p12 + security import $RUNNER_TEMP/certificate.p12 -P "$CERTIFICATES_PASSWORD" \ + -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" + security set-key-partition-list -S apple-tool:,apple: -k "" "$KEYCHAIN_PATH" + security list-keychain -d user -s "$KEYCHAIN_PATH" login.keychain + + - name: Configure notarization + env: + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + NOTARY_PASSWORD: ${{ secrets.NOTARY_PASSWORD }} + run: | + xcrun notarytool store-credentials "TablePro" \ + --apple-id "$APPLE_ID" \ + --team-id "$APPLE_TEAM_ID" \ + --password "$NOTARY_PASSWORD" + - name: Build ARM64 env: ANALYTICS_HMAC_SECRET: ${{ secrets.ANALYTICS_HMAC_SECRET }} @@ -92,74 +120,44 @@ jobs: - name: Package artifacts env: NOTARIZE: "true" - run: scripts/ci/package-artifacts.sh arm64 "/tmp/tablepro-artifacts-${{ github.sha }}" + run: scripts/ci/package-artifacts.sh arm64 + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: artifacts-arm64 + path: | + build/Release/TablePro-*.dmg + build/Release/TablePro-*.zip build-x86_64: name: Build x86_64 - runs-on: self-hosted + runs-on: macos-15 needs: lint timeout-minutes: 20 steps: - - name: Install Git LFS - run: brew list git-lfs &>/dev/null || brew install git-lfs; git lfs install - - name: Checkout code uses: actions/checkout@v4 with: lfs: true + - name: Select Xcode + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: '26.2' + - name: Pull LFS files run: git lfs pull - name: Install Rosetta 2 - run: | - if ! arch -x86_64 /usr/bin/true 2>/dev/null; then - echo "Installing Rosetta 2..." - if ! softwareupdate --install-rosetta --agree-to-license; then - echo "❌ ERROR: Failed to install Rosetta 2" - exit 1 - fi - - # Verify Rosetta 2 works - if ! arch -x86_64 /usr/bin/true 2>/dev/null; then - echo "❌ ERROR: Rosetta 2 installed but not functional" - exit 1 - fi - - echo "✅ Rosetta 2 installed" - else - echo "✅ Rosetta 2 already installed" - fi + run: softwareupdate --install-rosetta --agree-to-license || true - name: Install x86_64 Homebrew run: | if [ ! -f /usr/local/bin/brew ]; then echo "Installing x86_64 Homebrew..." - - if ! arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"; then - echo "❌ ERROR: Homebrew installation failed" - exit 1 - fi - - if [ ! -f /usr/local/bin/brew ]; then - echo "❌ ERROR: Homebrew not found after installation" - exit 1 - fi - - if ! /usr/local/bin/brew --version; then - echo "❌ ERROR: Homebrew not functional" - exit 1 - fi - - echo "✅ x86_64 Homebrew installed" - else - echo "x86_64 Homebrew already installed" - - if ! /usr/local/bin/brew --version; then - echo "❌ ERROR: Homebrew not functional" - exit 1 - fi + arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" fi - name: Install x86_64 dependencies @@ -193,6 +191,32 @@ jobs: ANALYTICS_HMAC_SECRET: ${{ secrets.ANALYTICS_HMAC_SECRET }} run: echo "ANALYTICS_HMAC_SECRET = ${ANALYTICS_HMAC_SECRET}" > Secrets.xcconfig + - name: Import signing certificate + env: + CERTIFICATES_P12: ${{ secrets.CERTIFICATES_P12 }} + CERTIFICATES_PASSWORD: ${{ secrets.CERTIFICATES_PASSWORD }} + run: | + KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db + security create-keychain -p "" "$KEYCHAIN_PATH" + security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" + security unlock-keychain -p "" "$KEYCHAIN_PATH" + echo "$CERTIFICATES_P12" | base64 --decode > $RUNNER_TEMP/certificate.p12 + security import $RUNNER_TEMP/certificate.p12 -P "$CERTIFICATES_PASSWORD" \ + -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" + security set-key-partition-list -S apple-tool:,apple: -k "" "$KEYCHAIN_PATH" + security list-keychain -d user -s "$KEYCHAIN_PATH" login.keychain + + - name: Configure notarization + env: + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + NOTARY_PASSWORD: ${{ secrets.NOTARY_PASSWORD }} + run: | + xcrun notarytool store-credentials "TablePro" \ + --apple-id "$APPLE_ID" \ + --team-id "$APPLE_TEAM_ID" \ + --password "$NOTARY_PASSWORD" + - name: Build x86_64 env: ANALYTICS_HMAC_SECRET: ${{ secrets.ANALYTICS_HMAC_SECRET }} @@ -207,11 +231,19 @@ jobs: - name: Package artifacts env: NOTARIZE: "true" - run: scripts/ci/package-artifacts.sh x86_64 "/tmp/tablepro-artifacts-${{ github.sha }}" + run: scripts/ci/package-artifacts.sh x86_64 + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: artifacts-x86_64 + path: | + build/Release/TablePro-*.dmg + build/Release/TablePro-*.zip release: name: Create GitHub Release - runs-on: self-hosted + runs-on: macos-15 needs: [build-arm64, build-x86_64] if: startsWith(github.ref, 'refs/tags/v') timeout-minutes: 10 @@ -224,12 +256,23 @@ jobs: with: fetch-depth: 0 - - name: Collect staged artifacts + - name: Select Xcode + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: '26.2' + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts-raw/ + merge-multiple: true + + - name: Flatten artifacts run: | - STAGING="/tmp/tablepro-artifacts-${{ github.sha }}" mkdir -p artifacts/ - cp "$STAGING"/* artifacts/ - echo "✅ Artifacts collected from $STAGING" + find artifacts-raw/ -type f \( -name "*.dmg" -o -name "*.zip" \) -exec mv {} artifacts/ \; + rm -rf artifacts-raw/ + echo "Artifacts:" ls -lh artifacts/ - name: Verify and organize artifacts for release diff --git a/TablePro/ContentView.swift b/TablePro/ContentView.swift index 9de6a7fd..5501023f 100644 --- a/TablePro/ContentView.swift +++ b/TablePro/ContentView.swift @@ -396,7 +396,6 @@ struct ContentView: View { storage.deleteConnection(connection) } - } #Preview { diff --git a/TablePro/Core/Plugins/PluginMetadataRegistry.swift b/TablePro/Core/Plugins/PluginMetadataRegistry.swift index 125eb5a6..566d42ed 100644 --- a/TablePro/Core/Plugins/PluginMetadataRegistry.swift +++ b/TablePro/Core/Plugins/PluginMetadataRegistry.swift @@ -39,7 +39,6 @@ final class PluginMetadataRegistry: @unchecked Sendable { registerBuiltInDefaults() } - // swiftlint:disable function_body_length private func registerBuiltInDefaults() { let defaults: [(typeId: String, snapshot: PluginMetadataSnapshot)] = [ ("MySQL", PluginMetadataSnapshot( @@ -126,7 +125,8 @@ final class PluginMetadataRegistry: @unchecked Sendable { ExplainVariant(id: "ast", label: "AST", sqlPrefix: "EXPLAIN AST"), ExplainVariant(id: "syntax", label: "Syntax", sqlPrefix: "EXPLAIN SYNTAX"), ExplainVariant(id: "estimate", label: "Estimate", sqlPrefix: "EXPLAIN ESTIMATE"), - ], pathFieldRole: .database, + ], + pathFieldRole: .database, supportsHealthMonitor: true, urlSchemes: ["clickhouse", "ch"], postConnectActions: [], brandColorHex: "#FFD100" )), @@ -164,8 +164,6 @@ final class PluginMetadataRegistry: @unchecked Sendable { } } } - // swiftlint:enable function_body_length - func register(snapshot: PluginMetadataSnapshot, forTypeId typeId: String) { lock.lock() defer { lock.unlock() } diff --git a/TablePro/Core/Plugins/Registry/DownloadCountService.swift b/TablePro/Core/Plugins/Registry/DownloadCountService.swift index 8cc39d91..1c16feb5 100644 --- a/TablePro/Core/Plugins/Registry/DownloadCountService.swift +++ b/TablePro/Core/Plugins/Registry/DownloadCountService.swift @@ -96,7 +96,6 @@ final class DownloadCountService { } return map } - } // MARK: - GitHub API Models diff --git a/TablePro/Core/SSH/HostKeyStore.swift b/TablePro/Core/SSH/HostKeyStore.swift index 79d84c8a..83d41ef3 100644 --- a/TablePro/Core/SSH/HostKeyStore.swift +++ b/TablePro/Core/SSH/HostKeyStore.swift @@ -149,7 +149,7 @@ internal final class HostKeyStore: @unchecked Sendable { /// Build the host identifier string: [hostname]:port private func hostIdentifier(_ hostname: String, _ port: Int) -> String { - return "[\(hostname)]:\(port)" + "[\(hostname)]:\(port)" } /// Load all entries from the known_hosts file diff --git a/TablePro/Core/SSH/LibSSH2TunnelFactory.swift b/TablePro/Core/SSH/LibSSH2TunnelFactory.swift index 55c1cbe3..915c1f6c 100644 --- a/TablePro/Core/SSH/LibSSH2TunnelFactory.swift +++ b/TablePro/Core/SSH/LibSSH2TunnelFactory.swift @@ -31,7 +31,6 @@ internal enum LibSSH2TunnelFactory { // MARK: - Public - // swiftlint:disable:next function_body_length static func createTunnel( connectionId: UUID, config: SSHConfiguration, @@ -185,7 +184,6 @@ internal enum LibSSH2TunnelFactory { ) return tunnel - } catch { // Clean up currentSession if it differs from all hop sessions // (happens when a nextSession was created but failed auth/verify) diff --git a/TablePro/Core/SSH/SSHTunnelManager.swift b/TablePro/Core/SSH/SSHTunnelManager.swift index c50712b8..7c8f3f3c 100644 --- a/TablePro/Core/SSH/SSHTunnelManager.swift +++ b/TablePro/Core/SSH/SSHTunnelManager.swift @@ -52,9 +52,7 @@ actor SSHTunnelManager { private init() {} - /// Create an SSH tunnel for a database connection - /// - Returns: Local port number for the tunnel - // swiftlint:disable:next function_parameter_count + /// Create an SSH tunnel for a database connection. func createTunnel( connectionId: UUID, sshHost: String, @@ -129,7 +127,6 @@ actor SSHTunnelManager { Self.logger.info("Tunnel created for \(connectionId) on local port \(localPort)") return localPort - } catch let error as SSHTunnelError { if case .tunnelCreationFailed(let msg) = error, msg.contains("already in use") { diff --git a/TablePro/Core/Services/Infrastructure/AppNotifications.swift b/TablePro/Core/Services/Infrastructure/AppNotifications.swift index 7cdd1222..f0043105 100644 --- a/TablePro/Core/Services/Infrastructure/AppNotifications.swift +++ b/TablePro/Core/Services/Infrastructure/AppNotifications.swift @@ -18,5 +18,4 @@ extension Notification.Name { static let connectionUpdated = Notification.Name("connectionUpdated") static let databaseDidConnect = Notification.Name("databaseDidConnect") - } diff --git a/TablePro/Views/Connection/ConnectionFormView.swift b/TablePro/Views/Connection/ConnectionFormView.swift index 4fd464ba..471ab662 100644 --- a/TablePro/Views/Connection/ConnectionFormView.swift +++ b/TablePro/Views/Connection/ConnectionFormView.swift @@ -10,8 +10,10 @@ import SwiftUI import TableProPluginKit import UniformTypeIdentifiers +// swiftlint:disable file_length + /// Form for creating or editing a database connection -struct ConnectionFormView: View { +struct ConnectionFormView: View { // swiftlint:disable:this type_body_length private static let logger = Logger(subsystem: "com.TablePro", category: "ConnectionFormView") @Environment(\.openWindow) private var openWindow diff --git a/TablePro/Views/Settings/Plugins/BrowsePluginsView.swift b/TablePro/Views/Settings/Plugins/BrowsePluginsView.swift index d319b228..1c7193da 100644 --- a/TablePro/Views/Settings/Plugins/BrowsePluginsView.swift +++ b/TablePro/Views/Settings/Plugins/BrowsePluginsView.swift @@ -181,8 +181,8 @@ struct BrowsePluginsView: View { } private func formattedCount(_ count: Int) -> String { - if count >= 1000 { - return String(format: "%.1fk", Double(count) / 1000.0) + if count >= 1_000 { + return String(format: "%.1fk", Double(count) / 1_000.0) } return "\(count)" } diff --git a/TablePro/Views/Sidebar/SidebarView.swift b/TablePro/Views/Sidebar/SidebarView.swift index 75cb48bd..07778a71 100644 --- a/TablePro/Views/Sidebar/SidebarView.swift +++ b/TablePro/Views/Sidebar/SidebarView.swift @@ -238,7 +238,6 @@ struct SidebarView: View { sidebarState.selectedTables.removeAll() } } - } // MARK: - Preview diff --git a/scripts/build-release.sh b/scripts/build-release.sh index 070feeb1..264f8ed5 100755 --- a/scripts/build-release.sh +++ b/scripts/build-release.sh @@ -310,7 +310,12 @@ build_for_arch() { echo "🔨 Building for $arch..." # Fetch build settings once for this arch (used by build_for_arch and bundle_dylibs) - build_settings=$(xcodebuild -project "$PROJECT" -scheme "$SCHEME" -configuration "$CONFIG" -arch "$arch" -showBuildSettings 2>&1) + echo "Fetching build settings..." + if ! build_settings=$(xcodebuild -project "$PROJECT" -scheme "$SCHEME" -configuration "$CONFIG" -arch "$arch" -skipPackagePluginValidation -showBuildSettings 2>&1); then + echo "❌ FATAL: xcodebuild -showBuildSettings failed" + echo "$build_settings" + exit 1 + fi # Prepare architecture-specific libraries prepare_mariadb "$arch" diff --git a/scripts/ci/package-artifacts.sh b/scripts/ci/package-artifacts.sh index 600017aa..f202cce2 100755 --- a/scripts/ci/package-artifacts.sh +++ b/scripts/ci/package-artifacts.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash set -euo pipefail -ARCH="${1:?Usage: package-artifacts.sh }" -STAGING="${2:?Usage: package-artifacts.sh }" +ARCH="${1:?Usage: package-artifacts.sh [staging_dir]}" +STAGING="${2:-}" if [[ "$ARCH" != "arm64" && "$ARCH" != "x86_64" ]]; then echo "❌ ERROR: Invalid architecture: $ARCH (expected arm64 or x86_64)" @@ -59,9 +59,11 @@ ls -lh "TablePro-${ARCH}.zip" cd - > /dev/null -# --- Stage artifacts --- -mkdir -p "$STAGING" -cp build/Release/*.dmg "$STAGING/" 2>/dev/null || true -cp "build/Release/TablePro-${ARCH}.zip" "$STAGING/" 2>/dev/null || true -echo "✅ ${ARCH} artifacts staged to $STAGING" -ls -lh "$STAGING" +# --- Stage artifacts (optional, for local/self-hosted use) --- +if [ -n "$STAGING" ]; then + mkdir -p "$STAGING" + cp build/Release/*.dmg "$STAGING/" 2>/dev/null || true + cp "build/Release/TablePro-${ARCH}.zip" "$STAGING/" 2>/dev/null || true + echo "Artifacts staged to $STAGING" + ls -lh "$STAGING" +fi diff --git a/scripts/ci/verify-build.sh b/scripts/ci/verify-build.sh index b1e2b349..721da88b 100755 --- a/scripts/ci/verify-build.sh +++ b/scripts/ci/verify-build.sh @@ -83,11 +83,9 @@ fi echo "✅ PlugIns directory exists" REQUIRED_PLUGINS=( - "MSSQLDriver.tableplugin" - "MongoDBDriver.tableplugin" "MySQLDriver.tableplugin" "PostgreSQLDriver.tableplugin" - "RedisDriver.tableplugin" + "SQLiteDriver.tableplugin" ) MISSING_PLUGINS=0