Skip to content

Commit ce63853

Browse files
committed
feat: Add comprehensive documentation, contribution guidelines, issue/PR templates, code quality tools, and new test suites for submodules and credential helpers.
1 parent 453a2e3 commit ce63853

13 files changed

Lines changed: 405 additions & 2 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
name: Bug report
3+
about: Create a report to help us improve
4+
title: ""
5+
labels: bug
6+
assignees: ''
7+
---
8+
9+
**Describe the bug**
10+
A clear and concise description of what the bug is.
11+
12+
**Reproduction steps**
13+
1. Steps to reproduce
14+
2. Expected behavior
15+
3. Actual behavior
16+
17+
**Environment**
18+
- macOS / Linux
19+
- Swift version: `swift --version`
20+
21+
**Additional context**
22+
Any other information, logs, or screenshots.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
name: Feature request
3+
about: Suggest an idea for this project
4+
title: ""
5+
labels: enhancement
6+
assignees: ''
7+
---
8+
9+
**Describe the feature**
10+
A clear and concise description of the desired feature.
11+
12+
**Motivation**
13+
Why is this feature useful?
14+
15+
**Design notes / constraints**
16+
Any API/design/compatibility considerations.

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
## Summary
2+
3+
Describe the change and why it is needed (1-3 sentences).
4+
5+
## Checklist
6+
- [ ] I added/updated tests for changed behavior
7+
- [ ] I ran `swift test` locally
8+
- [ ] I updated `AGENTS.md`/`CONTRIBUTING.md` if I added formatting or linting
9+
- [ ] This change does not modify `Sources/SwiftGit/Resource/git-instance.bundle` unless intentional
10+
11+
## Notes
12+
Additional context for reviewers, CI notes, or follow-ups.

.swiftformat

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
--indent 4
2+
--line-length 120
3+
--exclude Sources/SwiftGit/Resource/git-instance.bundle
4+
--trimwhitespace always
5+
--stripunusedargs closure-only
6+
7+
# Keep parentheses formatting conservative for readability
8+
--wraparguments before-first
9+
--removelinestrailingwhitespace always

.swiftlint.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
# Enable stricter defaults: avoid trailing whitespace and enforce line length
3+
disabled_rules: []
4+
5+
opt_in_rules:
6+
- empty_count
7+
- explicit_init
8+
- always_use_lowerCamelCase
9+
10+
excluded:
11+
- Sources/SwiftGit/Resource/git-instance.bundle
12+
13+
line_length:
14+
warning: 120
15+
error: 160
16+
17+
# Recommended autocorrect rules are not enabled by default; enable locally as needed
18+
disabled_by_default:
19+
- nimble_operator
20+
- prefer_self_in_static_references
21+
22+
reporter: xcode

AGENTS.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ swift test --package-path . --filter <TestName>
4343
- SwiftLint: `brew install swiftlint` then `swiftlint lint` (or `swiftlint autocorrect`).
4444
- swift-format: follow Apple or community formatter and add a `.swift-format` config if you want automated formatting.
4545

46-
- If you add a formatter/linter, update this document and add its config to the repo root.
46+
- If you add a formatter/linter, update this document and add its config to the repo root.
47+
- This repository now includes minimal configuration examples:
48+
- `.swiftformat` — basic formatting rules used by `swiftformat`/community tools.
49+
- `.swiftlint.yml` — basic SwiftLint configuration. These are small defaults; adjust rules to taste.
4750

4851
- **Common CI commands**
4952
- Build + test (fast): `swift test --enable-test-discovery`

CONTRIBUTING.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
Thank you for contributing to SwiftGit — this document explains the recommended workflow, tests, and PR guidance used by automated agents and maintainers.
2+
3+
Quick start
4+
- Build: `swift build`
5+
- Run tests (all): `swift test`
6+
- Run a single test: `swift test --filter <TestName>`
7+
8+
Branching & commits
9+
- Create a short-lived feature branch: `git checkout -b feat/short-description` or `fix/description`.
10+
- Keep commits small and focused. Commit messages should explain *why* (1–2 lines).
11+
- Do not amend pushed commits unless explicitly requested.
12+
13+
Tests
14+
- Prefer adding unit tests under `Tests/SwiftGitTests/` using existing helpers.
15+
- Integration tests use an embedded or system `git` and will `XCTSkip` when none is available. Use `envOrSkip()` helpers where appropriate.
16+
- Run a specific test case by name with `swift test --filter Test.testName`.
17+
18+
Style & lint
19+
- Follow the conventions in `AGENTS.md` (imports ordering, 4-space indentation, minimal force-unwrapping).
20+
- This repo includes minimal config files for format/lint: `.swiftformat` and `.swiftlint.yml`.
21+
- A simple pre-commit example is available at `tools/pre-commit.sh`. To enable it locally, run:
22+
23+
```
24+
mkdir -p .git/hooks
25+
cp tools/pre-commit.sh .git/hooks/pre-commit
26+
chmod +x .git/hooks/pre-commit
27+
```
28+
29+
This hook runs `swiftformat` and `swiftlint autocorrect` if those tools are installed. It is optional and not enforced by CI by default.
30+
31+
PR checklist
32+
- Include a short summary and why the change is needed.
33+
- Add or update tests for behavior changes.
34+
- Ensure `swift test` passes locally.
35+
- Mention any CI requirements or special environment needs (e.g., credential helpers).
36+
37+
CI
38+
- This repo includes a GitHub Actions workflow at `.github/workflows/ci.yml`.
39+
- CI runs on macOS and uses the embedded git bundle when appropriate.
40+
41+
Large changes
42+
- For changes to public APIs, document migration notes and consider a changelog entry.
43+
- Avoid modifying the embedded git bundle at `Sources/SwiftGit/Resource/git-instance.bundle` unless intentional.
44+
45+
Need help?
46+
- Open an issue using the templates in `.github/ISSUE_TEMPLATE/`.

Package.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ let package = Package(
2121
resources: [
2222
.copy("Resource/git-instance.bundle")
2323
]),
24+
// Example target removed — no Examples/ directory present in this tree.
2425
.testTarget(
2526
name: "SwiftGitTests",
2627
dependencies: [

README.md

Lines changed: 139 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,141 @@
11
# SwiftGit
22

3-
A description of this package.
3+
SwiftGit is a Swift Package that wraps and orchestrates Git command-line functionality
4+
so you can drive Git operations programmatically from Swift. It includes a small
5+
shell abstraction, typed models for common git results, command builders for many
6+
git subcommands, and an embedded portable git distribution for environments that
7+
don't provide `git` on PATH.
8+
9+
This README gives a focused code-oriented overview of the implementation in
10+
`Sources/` and practical instructions for building, testing, and contributing.
11+
12+
Key features
13+
- Thin, testable wrappers around `git` commands (clone, commit, push, tag, stash, etc.)
14+
- Centralized process execution utilities in `Shell` supporting Combine and async/await
15+
- Typed models for common git outputs (`GitStatus`, `Commit`, `ShowCommitResult`)
16+
- Embedded portable git at `Sources/SwiftGit/Resource/git-instance.bundle` for hermetic runs
17+
- Extensive unit and integration tests that exercise parsing and real git workflows
18+
19+
Table of contents
20+
- Project layout
21+
- Build & test
22+
- Important modules (quick code map)
23+
- Embedded git bundle
24+
- Tests and integration tests
25+
- Contribution notes
26+
- Contribution notes
27+
- See `CONTRIBUTING.md` for contribution workflow, pre-commit hook instructions, and lint/format guidance.
28+
29+
Project layout (sources)
30+
- `Sources/SwiftGit/` — main package sources
31+
- `Custom/` — hand-written implementation
32+
- `commands/` — high-level command helpers, e.g. `git-commands-clone.swift`, `git-commands-tag.swift`
33+
- `models/` — typed models like `GitStatus.swift`, `Commit.swift`, `Reference.swift`
34+
- `results/` — parsing results and helpers (e.g. `ShowCommitResult.swift`)
35+
- `Shell.swift` — centralized Process wrapper with Combine + async/await support
36+
- `GitEnvironment.swift` — locate and configure embedded or system git
37+
- `Git.swift` — top-level `Git` class, wiring environment, shell, and triggers
38+
- `Repository.swift` (+ extensions) — repository-level helpers
39+
- `Resource/git-instance.bundle/` — portable git binaries and extras included in the package
40+
- `options/` — typed option values used to compose command arguments
41+
42+
Build & test
43+
- Build the package (debug):
44+
45+
```bash
46+
swift build
47+
```
48+
49+
- Build for release:
50+
51+
```bash
52+
swift build -c release
53+
```
54+
55+
- Run the full test suite:
56+
57+
```bash
58+
swift test
59+
```
60+
61+
- Run a single test by name (recommended):
62+
63+
```bash
64+
# filter matches test case and/or function name
65+
swift test --filter ParseTests.testChangedEntryIndex_valid
66+
swift test --filter test_format_date
67+
```
68+
69+
- Run tests in parallel (CI friendly):
70+
71+
```bash
72+
swift test --parallel
73+
```
74+
75+
Important modules (quick code map)
76+
- `Shell` (`Sources/SwiftGit/Custom/Shell.swift`)
77+
- Centralizes process creation, captures stdout/stderr, provides publishers and async helpers.
78+
- Use `Git.data(...)` or `Git.run(...)` which delegate to `Shell.Instance`.
79+
80+
- `GitEnvironment` (`Sources/SwiftGit/Custom/GitEnvironment.swift`)
81+
- Selects between embedded git (`.embed`), system git (`.system`), or custom folder.
82+
- Exposes environment variables used to run git (e.g. `GIT_EXEC_PATH`).
83+
84+
- `Git` (`Sources/SwiftGit/Custom/Git.swift`)
85+
- High-level entrypoint. Use `Git(environment:)` or `try Git.shared` (throws if environment fails).
86+
- Methods: `run`, `runPublisher`, `data` with variants for arrays of args and string commands.
87+
88+
- `Repository` (`Sources/SwiftGit/Custom/Repository.swift` + `Repository+*.swift`)
89+
- Convenience methods that operate in a repository directory (run, clone, status, tag, etc.).
90+
91+
- `GitStatus` and parsing models (`Sources/SwiftGit/Custom/models/GitStatus.swift`)
92+
- Strongly-typed representations of `git status` output. Parsing code is defensive to avoid crashes on malformed input.
93+
94+
Embedded git bundle
95+
- This repository includes a pre-packaged git distribution at:
96+
97+
`Sources/SwiftGit/Resource/git-instance.bundle`
98+
99+
- `GitEnvironment` will prefer the embedded instance when `Style.embed` is selected or when `Style.auto` finds it.
100+
- Agents and tests should not modify files under the bundle. Use `GitEnvironment.Style.custom(URL)` to point to an alternate git distribution.
101+
102+
Tests and integration tests
103+
- Tests live under `Tests/SwiftGitTests/`.
104+
- Unit tests: parsing and helpers (safe parsing of `git` output, command splitting).
105+
- Integration tests: initialize temporary repos and run real git workflows (init, add, commit, tag, branch, stash, rebase, plumbing commands like `write-tree`).
106+
- Integration tests try to use the embedded git first and fall back to system git. If neither is available they skip.
107+
- Helper examples: `Tests/SwiftGitTests/IntegrationTests.swift`, `PlumbingTests.swift`, `ShowCommitResultTests.swift`.
108+
109+
Design & safety notes
110+
- Parsing: code attempts to be defensive; `GitStatus` uses failable/parsing helpers and falls back to safe defaults for malformed input.
111+
- Process execution: `Shell` captures stdout/stderr and surfaces a typed error when a process exits non‑zero (includes exit code and working directory where possible).
112+
- Command string handling: the library provides a `splitCommandLine` helper to handle quoted/escaped arguments for string-based overloads. Prefer array-based overloads when possible to avoid shell-escaping issues.
113+
114+
CI
115+
- A GitHub Actions workflow is included at `.github/workflows/ci.yml` and runs the build + tests on `macos-latest`.
116+
117+
Contributing and agents
118+
- There is an `AGENTS.md` file with rules and commands for automated agents and contributors. Agents should follow its guidelines when editing, testing, and committing.
119+
120+
Example usage
121+
- Simple programmatic example (conceptual):
122+
123+
```swift
124+
import SwiftGit
125+
126+
// create environment and git
127+
let env = try GitEnvironment(type: .auto)
128+
let git = try Git(environment: env)
129+
130+
// run git --version
131+
let version = try git.run(["--version"])
132+
print("git version: \(version)")
133+
```
134+
135+
Where to look next
136+
- If you want to understand parsing code, start with `Sources/SwiftGit/Custom/results/ShowCommitResult.swift` and
137+
`Sources/SwiftGit/Custom/models/GitStatus.swift`.
138+
- To add a new command helper, follow existing patterns under `Sources/SwiftGit/Custom/commands/`.
139+
140+
Questions or issues
141+
- Open an issue describing what you tried, including commands and repository state. If you want me to extend tests to cover more commands from the official Git docs, say which areas to prioritize (plumbing, submodule flows, network edge cases, etc.).

Sources/SwiftGit/Custom/Shell.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,29 @@
187187
.get()
188188
}
189189

190+
@discardableResult
191+
public func data(_ args: Shell.Arguments, input: Data?) throws -> Data {
192+
var args = args
193+
changedArgsBeforeRun?(&args)
194+
let process = self.setupProcess(args.exec, args.commands, context: args.context)
195+
196+
if let input = input {
197+
let inputPipe = Pipe()
198+
process.standardInput = inputPipe
199+
try inputPipe.fileHandleForWriting.write(contentsOf: input)
200+
try inputPipe.fileHandleForWriting.close()
201+
}
202+
203+
let output = Shell.Standard(publisher: args.context?.standardOutput).append(
204+
to: &process.standardOutput)
205+
let error = Shell.Standard(publisher: args.context?.standardError).append(
206+
to: &process.standardError)
207+
try process.run()
208+
process.waitUntilExit()
209+
return try result(process, output: output.availableData, error: error.availableData)
210+
.get()
211+
}
212+
190213
@discardableResult
191214
public func zshPublisher(_ args: Shell.ShellArguments) -> AnyPublisher<Data, Error> {
192215
dataPublisher(args.arguments)

0 commit comments

Comments
 (0)