mirror of
https://github.com/johndoe6345789/WizardMerge.git
synced 2026-04-24 13:44:55 +00:00
Update formal spec, add libcurl via Conan, update documentation
Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
46
README.md
46
README.md
@@ -15,7 +15,12 @@ WizardMerge uses a multi-frontend architecture with a high-performance C++ backe
|
||||
- **Build System**: CMake + Ninja
|
||||
- **Package Manager**: Conan
|
||||
- **Web Framework**: Drogon
|
||||
- **Features**: Three-way merge algorithm, conflict detection, auto-resolution, HTTP API
|
||||
- **Features**:
|
||||
- Three-way merge algorithm
|
||||
- Conflict detection and auto-resolution
|
||||
- HTTP API endpoints
|
||||
- GitHub Pull Request integration
|
||||
- Pull request conflict resolution
|
||||
|
||||
### Frontends
|
||||
|
||||
@@ -96,6 +101,45 @@ ninja
|
||||
|
||||
See [frontends/cli/README.md](frontends/cli/README.md) for details.
|
||||
|
||||
## Pull Request Conflict Resolution
|
||||
|
||||
WizardMerge can automatically resolve conflicts in GitHub pull requests using advanced merge algorithms.
|
||||
|
||||
### Using the CLI
|
||||
|
||||
```sh
|
||||
# Resolve conflicts in a pull request
|
||||
./wizardmerge-cli-frontend pr-resolve --url https://github.com/owner/repo/pull/123
|
||||
|
||||
# With GitHub token for private repos
|
||||
./wizardmerge-cli-frontend pr-resolve --url https://github.com/owner/repo/pull/123 --token ghp_xxx
|
||||
|
||||
# Or use environment variable
|
||||
export GITHUB_TOKEN=ghp_xxx
|
||||
./wizardmerge-cli-frontend pr-resolve --url https://github.com/owner/repo/pull/123
|
||||
```
|
||||
|
||||
### Using the HTTP API
|
||||
|
||||
```sh
|
||||
# POST /api/pr/resolve
|
||||
curl -X POST http://localhost:8080/api/pr/resolve \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"pr_url": "https://github.com/owner/repo/pull/123",
|
||||
"github_token": "ghp_xxx",
|
||||
"create_branch": true,
|
||||
"branch_name": "wizardmerge-resolved-pr-123"
|
||||
}'
|
||||
```
|
||||
|
||||
The API will:
|
||||
1. Parse the PR URL and fetch PR metadata from GitHub
|
||||
2. Retrieve base and head versions of all modified files
|
||||
3. Apply the three-way merge algorithm to each file
|
||||
4. Auto-resolve conflicts using heuristics
|
||||
5. Return merged content with conflict status
|
||||
|
||||
## Research Foundation
|
||||
|
||||
WizardMerge is based on research from The University of Hong Kong achieving:
|
||||
|
||||
@@ -12,11 +12,20 @@ find_package(GTest QUIET)
|
||||
find_package(CURL QUIET)
|
||||
|
||||
# Library sources
|
||||
add_library(wizardmerge
|
||||
set(WIZARDMERGE_SOURCES
|
||||
src/merge/three_way_merge.cpp
|
||||
src/git/github_client.cpp
|
||||
)
|
||||
|
||||
# Add git sources only if CURL is available
|
||||
if(CURL_FOUND)
|
||||
list(APPEND WIZARDMERGE_SOURCES src/git/github_client.cpp)
|
||||
message(STATUS "CURL found - including GitHub API client")
|
||||
else()
|
||||
message(WARNING "CURL not found - GitHub API features will be unavailable")
|
||||
endif()
|
||||
|
||||
add_library(wizardmerge ${WIZARDMERGE_SOURCES})
|
||||
|
||||
target_include_directories(wizardmerge
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
@@ -30,11 +39,18 @@ endif()
|
||||
|
||||
# Executable (only if Drogon is found)
|
||||
if(Drogon_FOUND)
|
||||
add_executable(wizardmerge-cli
|
||||
set(CLI_SOURCES
|
||||
src/main.cpp
|
||||
src/controllers/MergeController.cc
|
||||
src/controllers/PRController.cc
|
||||
)
|
||||
|
||||
# Add PR controller only if CURL is available
|
||||
if(CURL_FOUND)
|
||||
list(APPEND CLI_SOURCES src/controllers/PRController.cc)
|
||||
message(STATUS "CURL found - including PR resolution endpoint")
|
||||
endif()
|
||||
|
||||
add_executable(wizardmerge-cli ${CLI_SOURCES})
|
||||
|
||||
target_link_libraries(wizardmerge-cli PRIVATE wizardmerge Drogon::Drogon)
|
||||
|
||||
@@ -50,10 +66,15 @@ endif()
|
||||
# Tests (if GTest is available)
|
||||
if(GTest_FOUND)
|
||||
enable_testing()
|
||||
add_executable(wizardmerge-tests
|
||||
tests/test_three_way_merge.cpp
|
||||
tests/test_github_client.cpp
|
||||
)
|
||||
|
||||
set(TEST_SOURCES tests/test_three_way_merge.cpp)
|
||||
|
||||
# Add github client tests only if CURL is available
|
||||
if(CURL_FOUND)
|
||||
list(APPEND TEST_SOURCES tests/test_github_client.cpp)
|
||||
endif()
|
||||
|
||||
add_executable(wizardmerge-tests ${TEST_SOURCES})
|
||||
target_link_libraries(wizardmerge-tests PRIVATE wizardmerge GTest::gtest_main)
|
||||
|
||||
include(GoogleTest)
|
||||
|
||||
@@ -124,6 +124,8 @@ backend/
|
||||
- Auto-resolution of common patterns
|
||||
- HTTP API server using Drogon framework
|
||||
- JSON-based request/response
|
||||
- GitHub Pull Request integration (Phase 1.2)
|
||||
- Pull request conflict resolution via API
|
||||
|
||||
## API Usage
|
||||
|
||||
@@ -168,6 +170,58 @@ curl -X POST http://localhost:8080/api/merge \
|
||||
}'
|
||||
```
|
||||
|
||||
### POST /api/pr/resolve
|
||||
|
||||
Resolve conflicts in a GitHub pull request.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"pr_url": "https://github.com/owner/repo/pull/123",
|
||||
"github_token": "ghp_xxx",
|
||||
"create_branch": true,
|
||||
"branch_name": "wizardmerge-resolved-pr-123"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"pr_info": {
|
||||
"number": 123,
|
||||
"title": "Feature: Add new functionality",
|
||||
"base_ref": "main",
|
||||
"head_ref": "feature-branch",
|
||||
"mergeable": false
|
||||
},
|
||||
"resolved_files": [
|
||||
{
|
||||
"filename": "src/example.cpp",
|
||||
"status": "modified",
|
||||
"had_conflicts": true,
|
||||
"auto_resolved": true,
|
||||
"merged_content": ["line1", "line2", "..."]
|
||||
}
|
||||
],
|
||||
"total_files": 5,
|
||||
"resolved_count": 4,
|
||||
"failed_count": 0
|
||||
}
|
||||
```
|
||||
|
||||
**Example with curl:**
|
||||
```sh
|
||||
curl -X POST http://localhost:8080/api/pr/resolve \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"pr_url": "https://github.com/owner/repo/pull/123",
|
||||
"github_token": "ghp_xxx"
|
||||
}'
|
||||
```
|
||||
|
||||
**Note:** Requires libcurl to be installed. The GitHub token is optional for public repositories but required for private ones.
|
||||
|
||||
## Deployment
|
||||
|
||||
### Production Deployment with Docker
|
||||
|
||||
@@ -20,10 +20,16 @@ if ! pkg-config --exists drogon 2>/dev/null && ! ldconfig -p 2>/dev/null | grep
|
||||
echo " Option 2: Use Docker: docker-compose up --build"
|
||||
echo " Option 3: Use Conan: conan install . --output-folder=build --build=missing"
|
||||
echo
|
||||
read -p "Continue building without Drogon? (y/n) " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
exit 1
|
||||
|
||||
# Skip prompt if in non-interactive mode or CI
|
||||
if [[ -n "$CI" ]] || [[ -n "$WIZARDMERGE_AUTO_BUILD" ]] || [[ ! -t 0 ]]; then
|
||||
echo "Non-interactive mode detected, continuing without Drogon..."
|
||||
else
|
||||
read -p "Continue building without Drogon? (y/n) " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ class WizardMergeConan(ConanFile):
|
||||
exports_sources = "CMakeLists.txt", "src/*", "include/*"
|
||||
|
||||
# Dependencies
|
||||
requires = ["drogon/1.9.3"]
|
||||
requires = ["drogon/1.9.3", "libcurl/8.4.0"]
|
||||
|
||||
generators = "CMakeDeps", "CMakeToolchain"
|
||||
|
||||
|
||||
@@ -15,6 +15,11 @@ EXTENDS Naturals, FiniteSets
|
||||
* Identical changes from both sides
|
||||
* Whitespace-only differences
|
||||
- Command-line interface (wizardmerge-cli)
|
||||
- Pull request URL processing and conflict resolution:
|
||||
* Parse GitHub PR URLs
|
||||
* Fetch PR data via GitHub API
|
||||
* Apply merge algorithm to PR files
|
||||
* HTTP API endpoint for PR resolution
|
||||
|
||||
NOT YET IMPLEMENTED (Future phases):
|
||||
- Dependency graph construction (SDG analysis)
|
||||
@@ -22,11 +27,26 @@ EXTENDS Naturals, FiniteSets
|
||||
- Edge classification (safe vs. violated)
|
||||
- Fine-grained DCB (Definition-Code Block) tracking
|
||||
- Mirror mapping and matching
|
||||
- Git branch creation for resolved PRs
|
||||
|
||||
The current implementation in backend/src/merge/three_way_merge.cpp provides
|
||||
a foundation for the full dependency-aware algorithm specified here. Future
|
||||
phases will enhance it with the SDG analysis, edge classification, and
|
||||
dependency-aware conflict resolution described in this specification.
|
||||
|
||||
PR Resolution Workflow (Phase 1.2):
|
||||
The PR resolution feature extends the core merge algorithm to work with
|
||||
GitHub pull requests. The workflow is:
|
||||
1. Accept PR URL: Parse URL to extract owner, repo, and PR number
|
||||
2. Fetch PR metadata: Use GitHub API to retrieve PR information
|
||||
3. Fetch file versions: Retrieve base and head versions of modified files
|
||||
4. Apply merge algorithm: For each file, perform three-way merge
|
||||
5. Auto-resolve conflicts: Apply heuristic resolution where possible
|
||||
6. Return results: Provide merged content and conflict status
|
||||
|
||||
This workflow enables batch processing of PR conflicts using the same
|
||||
dependency-aware merge principles, with future integration planned for
|
||||
automatic branch creation and PR updates.
|
||||
*)
|
||||
|
||||
(*
|
||||
@@ -316,4 +336,98 @@ Inv ==
|
||||
|
||||
THEOREM Spec => []Inv
|
||||
|
||||
(***************************************************************************)
|
||||
(* Pull Request Resolution Specification (Phase 1.2) *)
|
||||
(***************************************************************************)
|
||||
|
||||
(*
|
||||
This section extends the core merge specification to model the PR resolution
|
||||
workflow. It describes how WizardMerge processes GitHub pull requests to
|
||||
identify and resolve conflicts across multiple files.
|
||||
*)
|
||||
|
||||
CONSTANTS
|
||||
(*
|
||||
PR_FILES: the set of all files in the pull request
|
||||
*)
|
||||
PR_FILES,
|
||||
|
||||
(*
|
||||
FileStatus: maps each file to its modification status in the PR
|
||||
Possible values: "modified", "added", "removed", "renamed"
|
||||
*)
|
||||
FileStatus,
|
||||
|
||||
(*
|
||||
BaseSHA, HeadSHA: commit identifiers for base and head of the PR
|
||||
*)
|
||||
BaseSHA, HeadSHA
|
||||
|
||||
(*
|
||||
A file is resolvable if it was modified (not removed) and we can fetch
|
||||
both its base and head versions.
|
||||
*)
|
||||
Resolvable(f) ==
|
||||
FileStatus[f] \in {"modified", "added"}
|
||||
|
||||
(*
|
||||
PR_MergeResult: for each file f in PR_FILES, we compute a merge result
|
||||
using the three-way merge algorithm. This is a function from PR_FILES
|
||||
to merge outcomes.
|
||||
|
||||
Possible outcomes:
|
||||
- "success": file merged without conflicts
|
||||
- "conflict": file has unresolved conflicts
|
||||
- "error": failed to fetch or process file
|
||||
- "skipped": file was removed or not applicable
|
||||
*)
|
||||
|
||||
VARIABLE PR_MergeResults
|
||||
|
||||
PR_Init ==
|
||||
PR_MergeResults = [f \in PR_FILES |-> "pending"]
|
||||
|
||||
(*
|
||||
Process a single file by applying the three-way merge algorithm.
|
||||
This abstracts the actual merge computation but captures the key decision:
|
||||
whether the file can be auto-resolved or requires manual intervention.
|
||||
*)
|
||||
ProcessFile(f) ==
|
||||
/\ PR_MergeResults[f] = "pending"
|
||||
/\ IF ~Resolvable(f)
|
||||
THEN PR_MergeResults' = [PR_MergeResults EXCEPT ![f] = "skipped"]
|
||||
ELSE \/ PR_MergeResults' = [PR_MergeResults EXCEPT ![f] = "success"]
|
||||
\/ PR_MergeResults' = [PR_MergeResults EXCEPT ![f] = "conflict"]
|
||||
\/ PR_MergeResults' = [PR_MergeResults EXCEPT ![f] = "error"]
|
||||
|
||||
(*
|
||||
PR completion: all files have been processed
|
||||
*)
|
||||
PR_Complete ==
|
||||
\A f \in PR_FILES : PR_MergeResults[f] # "pending"
|
||||
|
||||
(*
|
||||
PR success metric: percentage of files successfully merged
|
||||
*)
|
||||
PR_SuccessRate ==
|
||||
LET successful == {f \in PR_FILES : PR_MergeResults[f] = "success"}
|
||||
IN Cardinality(successful) * 100 \div Cardinality(PR_FILES)
|
||||
|
||||
(*
|
||||
PR resolution quality property: a "good" PR resolution is one where
|
||||
all resolvable files are either successfully merged or marked as conflicts
|
||||
(no errors in fetching or processing).
|
||||
*)
|
||||
GoodPRResolution ==
|
||||
\A f \in PR_FILES :
|
||||
Resolvable(f) => PR_MergeResults[f] \in {"success", "conflict"}
|
||||
|
||||
PR_Spec ==
|
||||
PR_Init /\ [][(\E f \in PR_FILES : ProcessFile(f))]_<<PR_MergeResults>>
|
||||
|
||||
PR_Invariant ==
|
||||
PR_Complete => GoodPRResolution
|
||||
|
||||
THEOREM PR_Spec => []PR_Invariant
|
||||
|
||||
=============================================================================
|
||||
|
||||
Reference in New Issue
Block a user