Thank you for your interest in contributing to DropShot. Whether you are reporting a bug, suggesting a feature, improving documentation, or writing code, your help is appreciated.
This project follows the Contributor Covenant Code of Conduct. By participating, you agree to uphold a welcoming and respectful environment for everyone.
- Search existing issues to make sure the bug has not already been reported.
- Open a new issue using the Bug Report template.
- Include your macOS version, DropShot version, and clear steps to reproduce the problem.
- If relevant, attach console logs from Console.app filtered by "DropShot".
Open an issue using the Feature Request template. Describe the use case, not just the solution -- understanding why helps us design the right approach.
- Fork the repository and create a feature branch from
main. - Make your changes (see the development workflow below).
- Write or update tests to cover your changes.
- Submit a pull request targeting
main.
- macOS 13.0 (Ventura) or later
- Xcode 15.0 or later
- Docker (for integration tests only)
git clone https://github.com/YOUR_USERNAME/DropShot.git
cd DropShot
swift build# Unit tests
swift test
# Integration tests (requires Docker)
docker compose -f docker-compose.test.yml up -d
swift test --filter IntegrationTests
docker compose -f docker-compose.test.yml down -vswift run DropShotDropShot follows standard Swift conventions. Key points:
- Naming: Use
camelCasefor variables, functions, and parameters. UsePascalCasefor types and protocols. Acronyms are uppercase only when they begin a type name (SFTPTransport, notSftpTransport). - Access control: Mark types and members with the most restrictive access level that works. Prefer
privateoverinternalwhen something is only used within its declaring scope. - MARK comments: Use
// MARK: -to organize sections within a file (Properties, Initialization, Public Methods, Private Helpers, etc.). - Documentation: Add doc comments (
///) to all public types, methods, and properties. - SwiftLint: The project includes SwiftLint rules. Run
swiftlintbefore submitting a PR to catch style issues. CI runs SwiftLint as well, though violations are non-blocking to avoid friction. - Line length: Aim for 120 characters or fewer. The linter warns at 150.
- Force unwrapping: Avoid
!except in tests and truly impossible-nil situations. Preferguard let,if let, or??. - Trailing closures: Use trailing closure syntax for the last closure parameter only.
Use a descriptive prefix:
feature/-- new functionality (e.g.feature/clipboard-upload)fix/-- bug fixes (e.g.fix/unicode-filename-encoding)docs/-- documentation changesrefactor/-- code restructuring without behavior changestest/-- new or updated tests
Write clear, imperative-mood commit messages:
Add upload progress animation to menu bar icon
The menu bar icon now shows an animated progress indicator during
active uploads. The animation respects the Reduce Motion accessibility
setting by falling back to a static badge.
- First line: 50 characters or fewer, imperative mood ("Add", "Fix", "Remove", not "Added", "Fixed", "Removed").
- Blank line, then an optional body wrapping at 72 characters.
Before requesting review, verify:
- The code compiles without warnings (
swift build) - All existing tests pass (
swift test) - New tests cover the changes
- Documentation is updated if behavior changed
- SwiftLint reports no new violations
- The PR description explains what changed and why
- At least one maintainer approval is required before merging.
- CI must pass (build, tests).
- PRs are squash-merged to keep the history clean.
- Unit tests are required for all new logic -- models, services, utilities.
- Integration tests are required for changes to SFTP transport, connection handling, or file transfer logic. These run against the Docker-based SFTP server.
- UI tests are encouraged but not required for v1.0.
- Tests must not depend on network access or external services (except the Docker SFTP container for integration tests).
The project is organized into four main layers:
DropShot/
App/ Entry point, Info.plist, app lifecycle
Models/ Data structures: ServerConfiguration, AppSettings, UploadRecord
Core/ Business logic: PathBuilder, SFTPTransport protocol
Services/ Service layer: upload orchestration, Keychain, network monitor
UI/ SwiftUI views and components
Resources/ Assets, localization files
- Models are plain Swift structs and enums with
Codableconformance. - Core defines protocols and stateless utilities.
- Services implement the protocols and manage side effects (network, filesystem, Keychain).
- UI contains SwiftUI views that observe service state via
@Observableor@ObservedObject.
DropShot ships with English (en) and Czech (cs) translations.
- Create a new
.lprojdirectory underDropShot/Resources/(e.g.de.lproj/for German). - Copy
Localizable.stringsfromen.lproj(once it exists) into the new directory. - Translate all string values, keeping the keys unchanged.
- Test by changing your macOS language in System Settings or by passing
-AppleLanguages "(de)"as a launch argument. - Submit a PR with the new translations.
- Use
NSLocalizedString("key", comment: "Context for translators")or SwiftUI'sLocalizedStringKey. - Keep keys descriptive:
"upload.progress.percent"not"str47". - Include a meaningful comment for every localized string to help translators.
If anything is unclear, open a Discussion or ask in a PR comment. We are happy to help.