chore: replace pnpm with make

This commit is contained in:
Peter Steinberger 2026-01-03 06:31:55 +01:00
parent c4c9dc52f6
commit e763fa7d63
8 changed files with 147 additions and 55 deletions

View File

@ -14,15 +14,9 @@ jobs:
run: swift --version
- name: Install SwiftLint
run: brew install swiftlint
- name: Resolve packages
run: swift package resolve
- name: Patch dependencies
run: scripts/patch-deps.sh
- name: Swift format lint
run: swift format lint --recursive Sources Tests
- name: SwiftLint
run: swiftlint
- name: Swift test
run: swift test
- name: Swift build
run: swift build -c release --product imsg
- name: Lint
run: make lint
- name: Test
run: make test
- name: Build
run: make build ARCHES=$(uname -m)

View File

@ -1,30 +1,29 @@
# Repository Guidelines
## Project Structure & Module Organization
- `cmd/imsg` holds the CLI entrypoint (`main.go`) and top-level Cobra command wiring.
- `internal/db`, `internal/watch`, `internal/send`, `internal/util` contain SQLite access, polling/streaming, AppleScript send logic, and helpers; keep shared code inside `internal` to avoid external API drift.
- `bin/` is created by the build script for local artifacts; `coverage.out` is optional and should not be committed unless updating reports.
- `Sources/imsg` holds the CLI entrypoint and command wiring.
- `Sources/IMsgCore` contains SQLite access, watchers, AppleScript send logic, and helpers.
- `bin/` is created by `make build` for local artifacts.
## Build, Test, and Development Commands
- `pnpm imsg` (or `go run ./cmd/imsg`) — run the CLI locally.
- `pnpm build` — compile to `bin/imsg` using the current module versions.
- `pnpm lint` — run `golangci-lint` with `gofmt`, `goimports`, `revive`, `staticcheck`, etc.; fix before sending a PR.
- `pnpm test` — execute `go test ./...`; use `-run` to target specific packages when iterating.
- `make imsg` — clean rebuild + run debug CLI (use `ARGS=...`).
- `make build` — universal release build into `bin/`.
- `make lint` — run `swift format` lint + `swiftlint`.
- `make test` — run `swift test` after syncing version + patching deps.
## Coding Style & Naming Conventions
- Go 1.24 module; rely on standard library patterns, idiomatic error handling, and early returns.
- Formatting is enforced by `gofmt`/`goimports`; do not hand-edit import order or indentation (tabs per Go defaults).
- Keep package-visible types intentional; prefer concrete types over `interface{}` and avoid global state in `internal` packages.
- Cobra command flags: prefer long-form, kebab-case (`--chat-id`, `--attachments`) consistent with existing commands.
- Swift 6 module; prefer concrete types, early returns, and minimal globals.
- Formatting is enforced by `swift format` and `swiftlint`.
- CLI flags use long-form, kebab-case (`--chat-id`, `--attachments`).
## Testing Guidelines
- Unit tests live alongside code as `*_test.go`; name tests `TestFunctionBehavior` and table-drive where useful.
- For DB or watch logic, prefer deterministic fixtures over touching the users live Messages DB; skip or mark tests that require macOS integration.
- Aim to keep `go test ./...` clean; add regression tests for every bug fix touching parsing, filtering, or attachment metadata.
- Unit tests live in `Tests/` as `*Tests.swift`.
- Prefer deterministic fixtures over touching the live Messages DB.
- Add regression tests for fixes touching parsing, filtering, or attachment metadata.
## Commit & Pull Request Guidelines
- Follow the existing short, lowercase prefixes seen in history (`ci:`, `chore:`, `fix:`, `feat:`) with an imperative summary (e.g., `fix: handle missing attachments`).
- PRs should include: brief description, steps to repro/verify, and outputs of `pnpm lint` and `pnpm test`. For CLI changes, include sample commands and before/after snippets.
- PRs should include: brief description, steps to repro/verify, and outputs of `make lint` and `make test`. For CLI changes, include sample commands and before/after snippets.
- Keep changeset focused; avoid drive-by refactors unless they reduce risk or remove duplication in touched areas.
## Security & macOS Permissions

42
Makefile Normal file
View File

@ -0,0 +1,42 @@
SHELL := /bin/bash
.PHONY: help format lint test build imsg clean
help:
@printf "%s\n" \
"make format - swift format in-place" \
"make lint - swift format lint + swiftlint" \
"make test - sync version, patch deps, run swift test" \
"make build - universal release build into bin/" \
"make imsg - clean rebuild + run debug binary (ARGS=...)" \
"make clean - swift package clean"
format:
swift format --in-place --recursive Sources Tests
lint:
swift format lint --recursive Sources Tests
swiftlint
test:
scripts/generate-version.sh
swift package resolve
scripts/patch-deps.sh
swift test
build:
scripts/generate-version.sh
swift package resolve
scripts/patch-deps.sh
scripts/build-universal.sh
imsg:
scripts/generate-version.sh
swift package resolve
scripts/patch-deps.sh
swift package clean
swift build -c debug --product imsg
./.build/debug/imsg $(ARGS)
clean:
swift package clean

View File

@ -19,7 +19,7 @@ A macOS Messages.app CLI to send, read, and stream iMessage/SMS (with attachment
## Install
```bash
pnpm build
make build
# binary at ./bin/imsg
```
@ -67,15 +67,15 @@ If you see “unable to open database file” or empty output:
## Testing
```bash
pnpm test
make test
```
Note: pnpm scripts apply a small patch to SQLite.swift to silence a SwiftPM warning about `PrivacyInfo.xcprivacy`.
Note: `make test` applies a small patch to SQLite.swift to silence a SwiftPM warning about `PrivacyInfo.xcprivacy`.
## Linting & formatting
```bash
pnpm lint
pnpm format
make lint
make format
```
## Core library

View File

@ -8,12 +8,12 @@
1. Update `CHANGELOG.md` and version
- Move entries from `Unreleased` into a new `## X.Y.Z - YYYY-MM-DD` section.
- Credit contributors (e.g. `thanks @user`).
- Update `version.env` and `package.json` to `X.Y.Z`.
- Update `version.env` to `X.Y.Z`.
- Run `scripts/generate-version.sh` (also refreshes `Sources/imsg/Resources/Info.plist`).
2. Ensure CI is green on `main`
- `pnpm lint`
- `pnpm test`
- `pnpm format` (optional, if formatting changes are expected)
- `make lint`
- `make test`
- `make format` (optional, if formatting changes are expected)
3. Build, sign, and notarize
- Requires `APP_STORE_CONNECT_API_KEY_P8`, `APP_STORE_CONNECT_KEY_ID`, `APP_STORE_CONNECT_ISSUER_ID`.
- `scripts/sign-and-notarize.sh` (outputs `/tmp/imsg-macos.zip` by default)

View File

@ -1,15 +0,0 @@
{
"name": "imsg",
"version": "0.3.0",
"private": true,
"scripts": {
"version:sync": "scripts/generate-version.sh",
"deps:patch": "swift package resolve && scripts/patch-deps.sh",
"imsg": "pnpm -s version:sync && pnpm -s deps:patch && swift run imsg",
"start": "pnpm imsg",
"format": "swift format --in-place --recursive Sources Tests",
"lint": "swift format lint --recursive Sources Tests && swiftlint",
"test": "pnpm -s version:sync && pnpm -s deps:patch && swift test",
"build": "pnpm -s version:sync && pnpm -s deps:patch && mkdir -p bin && swift build -c release --product imsg && cp .build/release/imsg bin/imsg && for existing in bin/*.bundle; do [ -e \"$existing\" ] || continue; if command -v trash >/dev/null 2>&1; then trash \"$existing\"; else rm -rf \"$existing\"; fi; done && for bundle in .build/release/*.bundle; do [ -e \"$bundle\" ] || continue; cp -R \"$bundle\" bin/; done && codesign --force --sign - --entitlements Resources/imsg.entitlements --identifier com.steipete.imsg bin/imsg"
}
}

61
scripts/build-universal.sh Executable file
View File

@ -0,0 +1,61 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT=$(cd "$(dirname "$0")/.." && pwd)
APP_NAME="imsg"
ENTITLEMENTS="${ROOT}/Resources/imsg.entitlements"
OUTPUT_DIR="${OUTPUT_DIR:-${ROOT}/bin}"
ARCHES_VALUE=${ARCHES:-"arm64 x86_64"}
ARCH_LIST=( ${ARCHES_VALUE} )
BUILD_MODE=${BUILD_MODE:-release}
CODESIGN_IDENTITY=${CODESIGN_IDENTITY:-"-"}
for ARCH in "${ARCH_LIST[@]}"; do
swift build -c "$BUILD_MODE" --product "$APP_NAME" --arch "$ARCH"
done
FIRST_ARCH="${ARCH_LIST[0]}"
BINARIES=()
for ARCH in "${ARCH_LIST[@]}"; do
BINARIES+=("${ROOT}/.build/${ARCH}-apple-macosx/${BUILD_MODE}/${APP_NAME}")
done
DIST_DIR="$(mktemp -d "/tmp/${APP_NAME}-universal.XXXXXX")"
trap 'rm -rf "$DIST_DIR"' EXIT
lipo -create "${BINARIES[@]}" -output "${DIST_DIR}/${APP_NAME}"
if [[ "$CODESIGN_IDENTITY" == "-" ]]; then
codesign --force --sign - \
--entitlements "$ENTITLEMENTS" \
--identifier com.steipete.imsg \
"${DIST_DIR}/${APP_NAME}"
else
codesign --force --timestamp --options runtime --sign "$CODESIGN_IDENTITY" \
--entitlements "$ENTITLEMENTS" \
--identifier com.steipete.imsg \
"${DIST_DIR}/${APP_NAME}"
fi
for bundle in "${ROOT}/.build/${FIRST_ARCH}-apple-macosx/${BUILD_MODE}"/*.bundle; do
if [[ -e "$bundle" ]]; then
cp -R "$bundle" "$DIST_DIR/"
fi
done
mkdir -p "$OUTPUT_DIR"
if command -v trash >/dev/null 2>&1; then
for existing in "$OUTPUT_DIR/$APP_NAME" "$OUTPUT_DIR"/*.bundle; do
[[ -e "$existing" ]] || continue
trash "$existing"
done
fi
cp "${DIST_DIR}/${APP_NAME}" "$OUTPUT_DIR/$APP_NAME"
for bundle in "${DIST_DIR}"/*.bundle; do
if [[ -e "$bundle" ]]; then
cp -R "$bundle" "$OUTPUT_DIR/"
fi
done
echo "Built ${OUTPUT_DIR}/${APP_NAME} (${ARCHES_VALUE})"

View File

@ -9,6 +9,8 @@ CODESIGN_IDENTITY=${CODESIGN_IDENTITY:-"Developer ID Application: Peter Steinber
ENTITLEMENTS="${ROOT}/Resources/imsg.entitlements"
OUTPUT_DIR="${OUTPUT_DIR:-/tmp}"
ZIP_PATH="${OUTPUT_DIR}/imsg-macos.zip"
ARCHES_VALUE=${ARCHES:-"arm64 x86_64"}
ARCH_LIST=( ${ARCHES_VALUE} )
DIST_DIR="$(mktemp -d "/tmp/${APP_NAME}-dist.XXXXXX")"
API_KEY_FILE="$(mktemp "/tmp/${APP_NAME}-notary.XXXXXX.p8")"
@ -25,14 +27,23 @@ fi
echo "$APP_STORE_CONNECT_API_KEY_P8" | sed 's/\\n/\n/g' > "$API_KEY_FILE"
swift build -c release --product imsg
for ARCH in "${ARCH_LIST[@]}"; do
swift build -c release --product imsg --arch "$ARCH"
done
BINARIES=()
for ARCH in "${ARCH_LIST[@]}"; do
BINARIES+=("$ROOT/.build/${ARCH}-apple-macosx/release/imsg")
done
lipo -create "${BINARIES[@]}" -output "$DIST_DIR/imsg"
codesign --force --timestamp --options runtime --sign "$CODESIGN_IDENTITY" \
--entitlements "$ENTITLEMENTS" \
"$ROOT/.build/release/imsg"
"$DIST_DIR/imsg"
cp "$ROOT/.build/release/imsg" "$DIST_DIR/imsg"
for bundle in "$ROOT/.build/release"/*.bundle; do
FIRST_ARCH="${ARCH_LIST[0]}"
for bundle in "$ROOT/.build/${FIRST_ARCH}-apple-macosx/release"/*.bundle; do
if [[ -e "$bundle" ]]; then
cp -R "$bundle" "$DIST_DIR/"
fi