-
Notifications
You must be signed in to change notification settings - Fork 0
Contribution
Athar Reza edited this page Nov 1, 2025
·
1 revision
Thank you for your interest in contributing to AgriSense! This guide will help you get started with contributing to the project.
- Code of Conduct
- Getting Started
- Development Workflow
- Coding Standards
- Commit Guidelines
- Pull Request Process
- Testing Requirements
- Documentation
We are committed to providing a welcoming and inclusive environment for all contributors, regardless of:
- Experience level
- Gender identity and expression
- Sexual orientation
- Disability
- Personal appearance
- Body size
- Race or ethnicity
- Age
- Religion
- Nationality
Positive Behavior:
- β Using welcoming and inclusive language
- β Being respectful of differing viewpoints
- β Gracefully accepting constructive criticism
- β Focusing on what's best for the community
- β Showing empathy towards others
Unacceptable Behavior:
- β Trolling, insulting, or derogatory comments
- β Personal or political attacks
- β Public or private harassment
- β Publishing others' private information
- β Unprofessional conduct
-
Read the Documentation
-
Setup Development Environment
# Clone the repository git clone https://github.com/Athar891/AgrisenseiOS.git cd AgrisenseiOS # Install dependencies (Xcode handles SPM packages) open Agrisense.xcodeproj
-
Create a GitHub Account
- Fork the repository
- Star the project β
Good First Issues:
- Look for issues tagged with
good first issue - Documentation improvements
- Bug fixes
- UI enhancements
- Test coverage improvements
Where to Start:
- Browse open issues
- Comment on issue you want to work on
- Wait for maintainer approval
- Fork and create branch
- Start coding!
# Fork repository on GitHub (click Fork button)
# Clone your fork
git clone https://github.com/YOUR_USERNAME/AgrisenseiOS.git
cd AgrisenseiOS
# Add upstream remote
git remote add upstream https://github.com/Athar891/AgrisenseiOS.git# Update main branch
git checkout main
git pull upstream main
# Create feature branch
git checkout -b feature/your-feature-name
# Or for bug fixes
git checkout -b fix/bug-description
# Or for documentation
git checkout -b docs/what-you-are-documentingBranch Naming Convention:
-
feature/- New features -
fix/- Bug fixes -
docs/- Documentation -
refactor/- Code refactoring -
test/- Test improvements -
chore/- Maintenance tasks
# Open in Xcode
open Agrisense.xcodeproj
# Make your changes
# Follow coding standards (see below)
# Write tests
# Update documentation# Run tests in Xcode
βU
# Or via command line
xcodebuild test \
-project Agrisense.xcodeproj \
-scheme Agrisense \
-destination 'platform=iOS Simulator,name=iPhone 14 Pro'
# Test on physical device
# Build and run on multiple iOS versions# Stage changes
git add .
# Commit with meaningful message
git commit -m "Add: feature description"
# Or use conventional commits
git commit -m "feat: add crop disease detection"# Push to your fork
git push origin feature/your-feature-name- Go to your fork on GitHub
- Click "New Pull Request"
- Fill in PR template
- Request review from maintainers
- Address review comments
- Wait for approval and merge
// Classes, Structs, Enums, Protocols: PascalCase
class UserManager { }
struct Crop { }
enum CropType { }
protocol Identifiable { }
// Variables, Functions, Properties: camelCase
var userName: String
func fetchCrops() { }
let isLoading: Bool
// Constants: camelCase or SCREAMING_SNAKE_CASE for globals
let maxRetries = 3
let API_BASE_URL = "https://api.example.com"
// Boolean variables: should read as assertions
var isLoading: Bool // β
var loading: Bool // β
var hasError: Bool // β
var error: Bool // β// MARK: - Type Definition
class CropManager: ObservableObject {
// MARK: - Properties
@Published var crops: [Crop] = []
private let db = Firestore.firestore()
// MARK: - Initialization
init() {
// Setup
}
// MARK: - Public Methods
func fetchCrops() async throws {
// Implementation
}
// MARK: - Private Methods
private func validateCrop(_ crop: Crop) -> Bool {
// Implementation
}
}struct CropListView: View {
// MARK: - Properties
@StateObject private var cropManager = CropManager()
@State private var isShowingAddView = false
// MARK: - Body
var body: some View {
NavigationView {
contentView
.navigationTitle("Crops")
.toolbar { toolbarContent }
}
}
// MARK: - View Components
private var contentView: some View {
List(cropManager.crops) { crop in
CropRow(crop: crop)
}
}
private var toolbarContent: some ToolbarContent {
ToolbarItem(placement: .navigationBarTrailing) {
Button("Add") { isShowingAddView = true }
}
}
}// Use custom error types
enum CropError: LocalizedError {
case invalidInput
case networkFailure
case notFound(id: String)
var errorDescription: String? {
switch self {
case .invalidInput:
return "Invalid crop data provided"
case .networkFailure:
return "Network connection failed"
case .notFound(let id):
return "Crop with ID \(id) not found"
}
}
}
// Use Result type for complex operations
func fetchCrop(id: String) async -> Result<Crop, CropError> {
// Implementation
}
// Use throws for straightforward operations
func saveCrop(_ crop: Crop) async throws {
// Implementation
}/// Manages crop data and operations
///
/// This class handles all crop-related operations including:
/// - Fetching crops from Firestore
/// - Creating and updating crops
/// - Deleting crops
/// - Image upload to Cloudinary
class CropManager: ObservableObject {
/// Fetches all crops for the current user
///
/// - Returns: Array of crops
/// - Throws: `CropError.networkFailure` if network request fails
func fetchCrops() async throws -> [Crop] {
// Implementation
}
}// Use meaningful variable names
let userName = user.name // β
let x = user.name // β
// Use guard for early returns
guard let user = currentUser else { return } // β
if currentUser == nil { return } // β (less clear)
// Use async/await
func fetchData() async throws { // β
let data = try await service.fetch()
}
// Use type inference when obvious
let count = 0 // β
let count: Int = 0 // β (redundant)
// Use trailing closures
button.action { // β
doSomething()
}// Don't use force unwrapping (except in tests)
let name = user.name! // β Dangerous
// Don't use magic numbers
if crops.count > 50 { } // β
let maxCrops = 50
if crops.count > maxCrops { } // β
// Don't create massive functions
func doEverything() { // β
// 500 lines of code
}
// Don't ignore errors
try? riskyOperation() // β (usually)
do { // β
try riskyOperation()
} catch {
handleError(error)
}<type>(<scope>): <subject>
<body>
<footer>
- feat: New feature
- fix: Bug fix
- docs: Documentation changes
- style: Code style changes (formatting, etc.)
- refactor: Code refactoring
- test: Adding or updating tests
- chore: Maintenance tasks
# Feature
git commit -m "feat(crops): add disease detection feature"
# Bug fix
git commit -m "fix(auth): resolve Google Sign-In crash on iOS 16"
# Documentation
git commit -m "docs(readme): update installation instructions"
# With body
git commit -m "feat(ai): add voice interruption support
Added ability to interrupt AI while speaking by:
- Implementing stop mechanism in TTS service
- Adding interrupt button to UI
- Handling state transitions properly
Closes #123"## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Documentation update
- [ ] Code refactoring
## Testing
- [ ] Unit tests added/updated
- [ ] UI tests added/updated
- [ ] Manual testing completed
- [ ] Tested on physical device
## Screenshots (if applicable)
Add screenshots here
## Checklist
- [ ] Code follows style guidelines
- [ ] Self-review completed
- [ ] Comments added for complex code
- [ ] Documentation updated
- [ ] No new warnings
- [ ] Tests pass locally-
Automated Checks
- Build success
- Tests pass
- No SwiftLint violations
-
Code Review
- At least one approval required
- Address all comments
- Resolve all conversations
-
Merge
- Squash and merge (default)
- Delete branch after merge
- Unit Test Coverage: > 70%
- UI Test Coverage: Critical user flows
- No Crashes: On iOS 16, 17
- Performance: No regressions
// Unit Test Example
class CropManagerTests: XCTestCase {
var sut: CropManager!
override func setUp() {
super.setUp()
sut = CropManager()
}
override func tearDown() {
sut = nil
super.tearDown()
}
func testFetchCrops() async throws {
// Given
let expectedCount = 5
// When
try await sut.fetchCrops()
// Then
XCTAssertEqual(sut.crops.count, expectedCount)
}
}- Update README.md if needed
- Add inline comments for complex logic
- Update wiki pages for new features
- Include code examples
- Add screenshots for UI changes
/// Brief one-line description
///
/// Detailed description explaining:
/// - What the function does
/// - When to use it
/// - Any important considerations
///
/// - Parameters:
/// - param1: Description of param1
/// - param2: Description of param2
/// - Returns: Description of return value
/// - Throws: Possible errors that can be thrown
///
/// # Example
/// ```swift
/// let result = try await function(param1: value1, param2: value2)
/// ```
func function(param1: Type1, param2: Type2) async throws -> ReturnType {
// Implementation
}All contributors will be:
- Listed in CONTRIBUTORS.md
- Credited in release notes
- Mentioned in project README
- Given contributor badge
Contributors with significant impact may receive:
- Special recognition
- Priority review
- Collaborator status
- General Questions: Discussions
- Bug Reports: Issues
- Security Issues: security@agrisense.app
- Email: support@agrisense.app
By contributing, you agree that your contributions will be licensed under the MIT License.
Thank you for contributing to AgriSense! πΎ
Every contribution, no matter how small, helps make farming smarter.