github-sync-agent 0.1.4__tar.gz → 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {github_sync_agent-0.1.4/github_sync_agent.egg-info → github_sync_agent-0.2.1}/PKG-INFO +69 -5
- github_sync_agent-0.1.4/PKG-INFO → github_sync_agent-0.2.1/README.md +61 -19
- github_sync_agent-0.2.1/github_sync/__init__.py +1 -0
- github_sync_agent-0.2.1/github_sync/api.py +111 -0
- {github_sync_agent-0.1.4 → github_sync_agent-0.2.1}/github_sync/cli.py +35 -0
- {github_sync_agent-0.1.4 → github_sync_agent-0.2.1}/github_sync/config.py +3 -0
- {github_sync_agent-0.1.4 → github_sync_agent-0.2.1}/github_sync/setup.py +5 -0
- github_sync_agent-0.2.1/github_sync_agent.egg-info/PKG-INFO +175 -0
- {github_sync_agent-0.1.4 → github_sync_agent-0.2.1}/github_sync_agent.egg-info/SOURCES.txt +1 -0
- github_sync_agent-0.2.1/github_sync_agent.egg-info/requires.txt +6 -0
- {github_sync_agent-0.1.4 → github_sync_agent-0.2.1}/pyproject.toml +13 -6
- github_sync_agent-0.1.4/README.md +0 -92
- github_sync_agent-0.1.4/github_sync/__init__.py +0 -1
- github_sync_agent-0.1.4/github_sync_agent.egg-info/requires.txt +0 -2
- {github_sync_agent-0.1.4 → github_sync_agent-0.2.1}/github_sync/agent.py +0 -0
- {github_sync_agent-0.1.4 → github_sync_agent-0.2.1}/github_sync_agent.egg-info/dependency_links.txt +0 -0
- {github_sync_agent-0.1.4 → github_sync_agent-0.2.1}/github_sync_agent.egg-info/entry_points.txt +0 -0
- {github_sync_agent-0.1.4 → github_sync_agent-0.2.1}/github_sync_agent.egg-info/top_level.txt +0 -0
- {github_sync_agent-0.1.4 → github_sync_agent-0.2.1}/setup.cfg +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: github-sync-agent
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Sync all your local projects to GitHub automatically
|
|
5
|
-
|
|
5
|
+
Author-email: GitHub Sync Agent Maintainers <yuvalavni@users.noreply.github.com>
|
|
6
|
+
License-Expression: MIT
|
|
6
7
|
Project-URL: Homepage, https://github.com/yuvalavni/Agents
|
|
7
8
|
Project-URL: Repository, https://github.com/yuvalavni/Agents
|
|
8
|
-
Project-URL:
|
|
9
|
-
Keywords: github,git,sync,backup,automation,cli
|
|
9
|
+
Project-URL: Issues, https://github.com/yuvalavni/Agents/issues
|
|
10
|
+
Keywords: github,git,sync,backup,automation,cli,api
|
|
10
11
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
12
12
|
Classifier: Operating System :: POSIX :: Linux
|
|
13
13
|
Classifier: Environment :: Console
|
|
14
14
|
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
@@ -16,6 +16,9 @@ Requires-Python: >=3.10
|
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
Requires-Dist: pyyaml>=6.0
|
|
18
18
|
Requires-Dist: click>=8.0
|
|
19
|
+
Provides-Extra: api
|
|
20
|
+
Requires-Dist: fastapi>=0.100; extra == "api"
|
|
21
|
+
Requires-Dist: uvicorn>=0.23; extra == "api"
|
|
19
22
|
|
|
20
23
|
# GitHub Sync Agent
|
|
21
24
|
|
|
@@ -74,6 +77,64 @@ github-sync status
|
|
|
74
77
|
|
|
75
78
|
---
|
|
76
79
|
|
|
80
|
+
## HTTP API
|
|
81
|
+
|
|
82
|
+
Install API dependencies:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pip install 'github-sync-agent[api]'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Start the server:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
github-sync serve
|
|
92
|
+
# → http://127.0.0.1:8741
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Endpoints
|
|
96
|
+
|
|
97
|
+
| Method | Path | Description |
|
|
98
|
+
|--------|------|-------------|
|
|
99
|
+
| `GET` | `/health` | Health check (no auth) |
|
|
100
|
+
| `GET` | `/status` | Sync status for all projects |
|
|
101
|
+
| `POST` | `/sync` | Sync all projects |
|
|
102
|
+
| `POST` | `/sync/{project}` | Sync one project |
|
|
103
|
+
|
|
104
|
+
Optional body for POST: `{"dry_run": false}`
|
|
105
|
+
|
|
106
|
+
### Examples
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
curl http://127.0.0.1:8741/health
|
|
110
|
+
curl http://127.0.0.1:8741/status
|
|
111
|
+
curl -X POST http://127.0.0.1:8741/sync
|
|
112
|
+
curl -X POST http://127.0.0.1:8741/sync/Agents
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### API authentication (optional)
|
|
116
|
+
|
|
117
|
+
Add to `config.yaml`:
|
|
118
|
+
|
|
119
|
+
```yaml
|
|
120
|
+
api_key: "your-secret-key"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Then pass the key on every request (except `/health`):
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
curl -H "Authorization: Bearer your-secret-key" http://127.0.0.1:8741/status
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Run as a systemd service
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
cp systemd/github-sync-api.service ~/.config/systemd/user/
|
|
133
|
+
systemctl --user enable --now github-sync-api.service
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
77
138
|
## Configuration (`~/.config/github-sync/config.yaml`)
|
|
78
139
|
|
|
79
140
|
Generated by `github-sync init`. You can edit it at any time.
|
|
@@ -88,6 +149,9 @@ Generated by `github-sync init`. You can edit it at any time.
|
|
|
88
149
|
| `exclude` | `[]` | Directory names to skip |
|
|
89
150
|
| `log_file` | `~/.local/share/github-sync/github-sync.log` | Log file path |
|
|
90
151
|
| `log_level` | `INFO` | `DEBUG` / `INFO` / `WARNING` / `ERROR` |
|
|
152
|
+
| `api_host` | `127.0.0.1` | API bind address |
|
|
153
|
+
| `api_port` | `8741` | API port |
|
|
154
|
+
| `api_key` | _(empty)_ | Optional Bearer token for API auth |
|
|
91
155
|
|
|
92
156
|
### Excluding a project
|
|
93
157
|
|
|
@@ -1,22 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: github-sync-agent
|
|
3
|
-
Version: 0.1.4
|
|
4
|
-
Summary: Sync all your local projects to GitHub automatically
|
|
5
|
-
License: MIT
|
|
6
|
-
Project-URL: Homepage, https://github.com/yuvalavni/Agents
|
|
7
|
-
Project-URL: Repository, https://github.com/yuvalavni/Agents
|
|
8
|
-
Project-URL: Bug Tracker, https://github.com/yuvalavni/Agents/issues
|
|
9
|
-
Keywords: github,git,sync,backup,automation,cli
|
|
10
|
-
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
-
Classifier: Operating System :: POSIX :: Linux
|
|
13
|
-
Classifier: Environment :: Console
|
|
14
|
-
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
15
|
-
Requires-Python: >=3.10
|
|
16
|
-
Description-Content-Type: text/markdown
|
|
17
|
-
Requires-Dist: pyyaml>=6.0
|
|
18
|
-
Requires-Dist: click>=8.0
|
|
19
|
-
|
|
20
1
|
# GitHub Sync Agent
|
|
21
2
|
|
|
22
3
|
Automatically syncs every local project directory to its own GitHub repository.
|
|
@@ -74,6 +55,64 @@ github-sync status
|
|
|
74
55
|
|
|
75
56
|
---
|
|
76
57
|
|
|
58
|
+
## HTTP API
|
|
59
|
+
|
|
60
|
+
Install API dependencies:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install 'github-sync-agent[api]'
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Start the server:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
github-sync serve
|
|
70
|
+
# → http://127.0.0.1:8741
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Endpoints
|
|
74
|
+
|
|
75
|
+
| Method | Path | Description |
|
|
76
|
+
|--------|------|-------------|
|
|
77
|
+
| `GET` | `/health` | Health check (no auth) |
|
|
78
|
+
| `GET` | `/status` | Sync status for all projects |
|
|
79
|
+
| `POST` | `/sync` | Sync all projects |
|
|
80
|
+
| `POST` | `/sync/{project}` | Sync one project |
|
|
81
|
+
|
|
82
|
+
Optional body for POST: `{"dry_run": false}`
|
|
83
|
+
|
|
84
|
+
### Examples
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
curl http://127.0.0.1:8741/health
|
|
88
|
+
curl http://127.0.0.1:8741/status
|
|
89
|
+
curl -X POST http://127.0.0.1:8741/sync
|
|
90
|
+
curl -X POST http://127.0.0.1:8741/sync/Agents
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### API authentication (optional)
|
|
94
|
+
|
|
95
|
+
Add to `config.yaml`:
|
|
96
|
+
|
|
97
|
+
```yaml
|
|
98
|
+
api_key: "your-secret-key"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Then pass the key on every request (except `/health`):
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
curl -H "Authorization: Bearer your-secret-key" http://127.0.0.1:8741/status
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Run as a systemd service
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
cp systemd/github-sync-api.service ~/.config/systemd/user/
|
|
111
|
+
systemctl --user enable --now github-sync-api.service
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
77
116
|
## Configuration (`~/.config/github-sync/config.yaml`)
|
|
78
117
|
|
|
79
118
|
Generated by `github-sync init`. You can edit it at any time.
|
|
@@ -88,6 +127,9 @@ Generated by `github-sync init`. You can edit it at any time.
|
|
|
88
127
|
| `exclude` | `[]` | Directory names to skip |
|
|
89
128
|
| `log_file` | `~/.local/share/github-sync/github-sync.log` | Log file path |
|
|
90
129
|
| `log_level` | `INFO` | `DEBUG` / `INFO` / `WARNING` / `ERROR` |
|
|
130
|
+
| `api_host` | `127.0.0.1` | API bind address |
|
|
131
|
+
| `api_port` | `8741` | API port |
|
|
132
|
+
| `api_key` | _(empty)_ | Optional Bearer token for API auth |
|
|
91
133
|
|
|
92
134
|
### Excluding a project
|
|
93
135
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.1"
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""HTTP API for the GitHub Sync Agent."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import logging
|
|
7
|
+
|
|
8
|
+
from fastapi import Depends, FastAPI, HTTPException, Security
|
|
9
|
+
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
|
10
|
+
from pydantic import BaseModel, Field
|
|
11
|
+
|
|
12
|
+
from . import __version__
|
|
13
|
+
from . import agent
|
|
14
|
+
|
|
15
|
+
LOG = logging.getLogger(__name__)
|
|
16
|
+
_security = HTTPBearer(auto_error=False)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class SyncRequest(BaseModel):
|
|
20
|
+
dry_run: bool = False
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class SyncResult(BaseModel):
|
|
24
|
+
project: str
|
|
25
|
+
success: bool
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class SyncResponse(BaseModel):
|
|
29
|
+
success: bool
|
|
30
|
+
synced: int
|
|
31
|
+
failed: int
|
|
32
|
+
results: list[SyncResult]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class StatusRow(BaseModel):
|
|
36
|
+
project: str
|
|
37
|
+
root: str
|
|
38
|
+
git: bool
|
|
39
|
+
remote: bool
|
|
40
|
+
changes: bool
|
|
41
|
+
on_github: bool
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class StatusResponse(BaseModel):
|
|
45
|
+
github_user: str
|
|
46
|
+
projects_root: list[str]
|
|
47
|
+
projects: list[StatusRow]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def create_app(cfg: dict) -> FastAPI:
|
|
51
|
+
api_key: str = cfg.get("api_key") or ""
|
|
52
|
+
|
|
53
|
+
app = FastAPI(
|
|
54
|
+
title="GitHub Sync Agent API",
|
|
55
|
+
description="Trigger and inspect GitHub sync operations over HTTP.",
|
|
56
|
+
version=__version__,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
async def require_auth(
|
|
60
|
+
credentials: HTTPAuthorizationCredentials | None = Security(_security),
|
|
61
|
+
) -> None:
|
|
62
|
+
if not api_key:
|
|
63
|
+
return
|
|
64
|
+
if credentials is None or credentials.credentials != api_key:
|
|
65
|
+
raise HTTPException(status_code=401, detail="Invalid or missing API key")
|
|
66
|
+
|
|
67
|
+
@app.get("/health")
|
|
68
|
+
async def health() -> dict[str, str]:
|
|
69
|
+
return {"status": "ok", "version": __version__}
|
|
70
|
+
|
|
71
|
+
@app.get("/status", response_model=StatusResponse, dependencies=[Depends(require_auth)])
|
|
72
|
+
async def status() -> StatusResponse:
|
|
73
|
+
rows = await asyncio.to_thread(agent.get_status, cfg)
|
|
74
|
+
return StatusResponse(
|
|
75
|
+
github_user=cfg["github_user"],
|
|
76
|
+
projects_root=cfg["projects_root"],
|
|
77
|
+
projects=[StatusRow(**row) for row in rows],
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
@app.post("/sync", response_model=SyncResponse, dependencies=[Depends(require_auth)])
|
|
81
|
+
async def sync_all(body: SyncRequest = SyncRequest()) -> SyncResponse:
|
|
82
|
+
return await _run_sync(cfg, project=None, dry_run=body.dry_run)
|
|
83
|
+
|
|
84
|
+
@app.post("/sync/{project}", response_model=SyncResponse, dependencies=[Depends(require_auth)])
|
|
85
|
+
async def sync_one(project: str, body: SyncRequest = SyncRequest()) -> SyncResponse:
|
|
86
|
+
return await _run_sync(cfg, project=project, dry_run=body.dry_run)
|
|
87
|
+
|
|
88
|
+
return app
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
async def _run_sync(cfg: dict, project: str | None, dry_run: bool) -> SyncResponse:
|
|
92
|
+
try:
|
|
93
|
+
projects = await asyncio.to_thread(agent.discover_projects, cfg, project)
|
|
94
|
+
except ValueError as exc:
|
|
95
|
+
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
|
96
|
+
|
|
97
|
+
results: list[SyncResult] = []
|
|
98
|
+
for path in projects:
|
|
99
|
+
ok = await asyncio.to_thread(agent.sync_project, path, cfg, dry_run)
|
|
100
|
+
results.append(SyncResult(project=path.name, success=ok))
|
|
101
|
+
level = logging.INFO if ok else logging.ERROR
|
|
102
|
+
LOG.log(level, "%s %s", path.name, "synced" if ok else "FAILED")
|
|
103
|
+
|
|
104
|
+
synced = sum(1 for r in results if r.success)
|
|
105
|
+
failed = len(results) - synced
|
|
106
|
+
return SyncResponse(
|
|
107
|
+
success=failed == 0,
|
|
108
|
+
synced=synced,
|
|
109
|
+
failed=failed,
|
|
110
|
+
results=results,
|
|
111
|
+
)
|
|
@@ -253,9 +253,44 @@ def init() -> None:
|
|
|
253
253
|
click.echo(f" github-sync status # see all your projects")
|
|
254
254
|
click.echo(f" github-sync sync --dry-run # preview what will be synced")
|
|
255
255
|
click.echo(f" github-sync sync # sync everything to GitHub")
|
|
256
|
+
click.echo(f" github-sync serve # start HTTP API (requires [api] extra)")
|
|
256
257
|
click.echo()
|
|
257
258
|
|
|
258
259
|
|
|
260
|
+
# ---------------------------------------------------------------------------
|
|
261
|
+
# serve
|
|
262
|
+
# ---------------------------------------------------------------------------
|
|
263
|
+
|
|
264
|
+
@cli.command()
|
|
265
|
+
@click.option("--host", default=None, help="Bind address (default: api_host from config)")
|
|
266
|
+
@click.option("--port", default=None, type=int, help="Port (default: api_port from config)")
|
|
267
|
+
@click.pass_context
|
|
268
|
+
def serve(ctx: click.Context, host: str | None, port: int | None) -> None:
|
|
269
|
+
"""Start the HTTP API server."""
|
|
270
|
+
try:
|
|
271
|
+
import uvicorn
|
|
272
|
+
except ImportError:
|
|
273
|
+
click.echo("Error: API dependencies not installed.", err=True)
|
|
274
|
+
click.echo("Run: pip install 'github-sync-agent[api]'", err=True)
|
|
275
|
+
sys.exit(1)
|
|
276
|
+
|
|
277
|
+
cfg = ctx.obj["cfg"]
|
|
278
|
+
_setup_logging(cfg)
|
|
279
|
+
|
|
280
|
+
from .api import create_app
|
|
281
|
+
|
|
282
|
+
bind_host = host or cfg.get("api_host", "127.0.0.1")
|
|
283
|
+
bind_port = port or int(cfg.get("api_port", 8741))
|
|
284
|
+
app = create_app(cfg)
|
|
285
|
+
|
|
286
|
+
auth_note = "API key required" if cfg.get("api_key") else "no auth (localhost only recommended)"
|
|
287
|
+
click.echo(f"Starting GitHub Sync API on http://{bind_host}:{bind_port} ({auth_note})")
|
|
288
|
+
click.echo("Endpoints: GET /health GET /status POST /sync POST /sync/{project}")
|
|
289
|
+
click.echo()
|
|
290
|
+
|
|
291
|
+
uvicorn.run(app, host=bind_host, port=bind_port, log_level=cfg.get("log_level", "info").lower())
|
|
292
|
+
|
|
293
|
+
|
|
259
294
|
# ---------------------------------------------------------------------------
|
|
260
295
|
# Entry point
|
|
261
296
|
# ---------------------------------------------------------------------------
|
|
@@ -26,6 +26,9 @@ def _apply_defaults(cfg: dict) -> None:
|
|
|
26
26
|
cfg.setdefault("exclude", [])
|
|
27
27
|
cfg.setdefault("log_file", str(Path.home() / ".local" / "share" / "github-sync" / "github-sync.log"))
|
|
28
28
|
cfg.setdefault("log_level", "INFO")
|
|
29
|
+
cfg.setdefault("api_host", "127.0.0.1")
|
|
30
|
+
cfg.setdefault("api_port", 8741)
|
|
31
|
+
cfg.setdefault("api_key", "")
|
|
29
32
|
|
|
30
33
|
if not cfg.get("github_user"):
|
|
31
34
|
raise ValueError("Missing required config key: 'github_user'")
|
|
@@ -276,6 +276,11 @@ exclude: []
|
|
|
276
276
|
# Logging
|
|
277
277
|
log_file: {log_file}
|
|
278
278
|
log_level: INFO
|
|
279
|
+
|
|
280
|
+
# HTTP API (github-sync serve)
|
|
281
|
+
api_host: "127.0.0.1"
|
|
282
|
+
api_port: 8741
|
|
283
|
+
# api_key: "change-me" # uncomment to require: Authorization: Bearer <key>
|
|
279
284
|
"""
|
|
280
285
|
|
|
281
286
|
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: github-sync-agent
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Sync all your local projects to GitHub automatically
|
|
5
|
+
Author-email: GitHub Sync Agent Maintainers <yuvalavni@users.noreply.github.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/yuvalavni/Agents
|
|
8
|
+
Project-URL: Repository, https://github.com/yuvalavni/Agents
|
|
9
|
+
Project-URL: Issues, https://github.com/yuvalavni/Agents/issues
|
|
10
|
+
Keywords: github,git,sync,backup,automation,cli,api
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Requires-Dist: pyyaml>=6.0
|
|
18
|
+
Requires-Dist: click>=8.0
|
|
19
|
+
Provides-Extra: api
|
|
20
|
+
Requires-Dist: fastapi>=0.100; extra == "api"
|
|
21
|
+
Requires-Dist: uvicorn>=0.23; extra == "api"
|
|
22
|
+
|
|
23
|
+
# GitHub Sync Agent
|
|
24
|
+
|
|
25
|
+
Automatically syncs every local project directory to its own GitHub repository.
|
|
26
|
+
|
|
27
|
+
For each project it will:
|
|
28
|
+
1. `git init` if not already a repo
|
|
29
|
+
2. Create the GitHub repo if it doesn't exist yet
|
|
30
|
+
3. Ensure the remote uses SSH
|
|
31
|
+
4. Stage + commit any uncommitted changes
|
|
32
|
+
5. Push to `origin`
|
|
33
|
+
|
|
34
|
+
Runs daily via a systemd user timer, and on-demand via CLI.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install github-sync-agent
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## First-time setup
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
github-sync init
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The wizard will:
|
|
51
|
+
- Check `git` and `gh` are installed
|
|
52
|
+
- Authenticate with GitHub (`gh auth login`)
|
|
53
|
+
- Ask which folder to scan for projects
|
|
54
|
+
- Set up your SSH key automatically
|
|
55
|
+
- **Verify SSH works** (auto-fixes port 443 and ssh-agent if needed)
|
|
56
|
+
- Write a config file to `~/.config/github-sync/config.yaml`
|
|
57
|
+
|
|
58
|
+
Setup will **not** complete until `ssh -T git@github.com` succeeds.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Usage
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Sync all projects
|
|
66
|
+
github-sync sync
|
|
67
|
+
|
|
68
|
+
# Sync a single project
|
|
69
|
+
github-sync sync --project my-project
|
|
70
|
+
|
|
71
|
+
# Preview without making changes
|
|
72
|
+
github-sync sync --dry-run
|
|
73
|
+
|
|
74
|
+
# Show status of all projects
|
|
75
|
+
github-sync status
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## HTTP API
|
|
81
|
+
|
|
82
|
+
Install API dependencies:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pip install 'github-sync-agent[api]'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Start the server:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
github-sync serve
|
|
92
|
+
# → http://127.0.0.1:8741
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Endpoints
|
|
96
|
+
|
|
97
|
+
| Method | Path | Description |
|
|
98
|
+
|--------|------|-------------|
|
|
99
|
+
| `GET` | `/health` | Health check (no auth) |
|
|
100
|
+
| `GET` | `/status` | Sync status for all projects |
|
|
101
|
+
| `POST` | `/sync` | Sync all projects |
|
|
102
|
+
| `POST` | `/sync/{project}` | Sync one project |
|
|
103
|
+
|
|
104
|
+
Optional body for POST: `{"dry_run": false}`
|
|
105
|
+
|
|
106
|
+
### Examples
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
curl http://127.0.0.1:8741/health
|
|
110
|
+
curl http://127.0.0.1:8741/status
|
|
111
|
+
curl -X POST http://127.0.0.1:8741/sync
|
|
112
|
+
curl -X POST http://127.0.0.1:8741/sync/Agents
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### API authentication (optional)
|
|
116
|
+
|
|
117
|
+
Add to `config.yaml`:
|
|
118
|
+
|
|
119
|
+
```yaml
|
|
120
|
+
api_key: "your-secret-key"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Then pass the key on every request (except `/health`):
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
curl -H "Authorization: Bearer your-secret-key" http://127.0.0.1:8741/status
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Run as a systemd service
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
cp systemd/github-sync-api.service ~/.config/systemd/user/
|
|
133
|
+
systemctl --user enable --now github-sync-api.service
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Configuration (`~/.config/github-sync/config.yaml`)
|
|
139
|
+
|
|
140
|
+
Generated by `github-sync init`. You can edit it at any time.
|
|
141
|
+
|
|
142
|
+
| Key | Default | Description |
|
|
143
|
+
|-----|---------|-------------|
|
|
144
|
+
| `github_user` | _(detected from gh auth)_ | Your GitHub username |
|
|
145
|
+
| `projects_root` | `~/projects` | Scans all subdirectories here |
|
|
146
|
+
| `schedule_time` | `02:00` | Daily run time |
|
|
147
|
+
| `default_visibility` | `private` | `private` or `public` for new repos |
|
|
148
|
+
| `auto_commit_message` | `chore: auto-sync` | Commit message for auto-commits |
|
|
149
|
+
| `exclude` | `[]` | Directory names to skip |
|
|
150
|
+
| `log_file` | `~/.local/share/github-sync/github-sync.log` | Log file path |
|
|
151
|
+
| `log_level` | `INFO` | `DEBUG` / `INFO` / `WARNING` / `ERROR` |
|
|
152
|
+
| `api_host` | `127.0.0.1` | API bind address |
|
|
153
|
+
| `api_port` | `8741` | API port |
|
|
154
|
+
| `api_key` | _(empty)_ | Optional Bearer token for API auth |
|
|
155
|
+
|
|
156
|
+
### Excluding a project
|
|
157
|
+
|
|
158
|
+
```yaml
|
|
159
|
+
exclude:
|
|
160
|
+
- SomeProjectToSkip
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Requirements
|
|
166
|
+
|
|
167
|
+
- Python 3.10+
|
|
168
|
+
- `git` installed
|
|
169
|
+
- `gh` (GitHub CLI) installed — [installation guide](https://cli.github.com)
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## License
|
|
174
|
+
|
|
175
|
+
MIT
|
|
@@ -4,16 +4,17 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "github-sync-agent"
|
|
7
|
-
version = "0.1
|
|
7
|
+
version = "0.2.1"
|
|
8
8
|
description = "Sync all your local projects to GitHub automatically"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
11
|
-
license =
|
|
12
|
-
authors = [
|
|
13
|
-
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "GitHub Sync Agent Maintainers", email = "yuvalavni@users.noreply.github.com" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["github", "git", "sync", "backup", "automation", "cli", "api"]
|
|
14
16
|
classifiers = [
|
|
15
17
|
"Programming Language :: Python :: 3",
|
|
16
|
-
"License :: OSI Approved :: MIT License",
|
|
17
18
|
"Operating System :: POSIX :: Linux",
|
|
18
19
|
"Environment :: Console",
|
|
19
20
|
"Topic :: Software Development :: Version Control :: Git",
|
|
@@ -23,10 +24,16 @@ dependencies = [
|
|
|
23
24
|
"click>=8.0",
|
|
24
25
|
]
|
|
25
26
|
|
|
27
|
+
[project.optional-dependencies]
|
|
28
|
+
api = [
|
|
29
|
+
"fastapi>=0.100",
|
|
30
|
+
"uvicorn>=0.23",
|
|
31
|
+
]
|
|
32
|
+
|
|
26
33
|
[project.urls]
|
|
27
34
|
Homepage = "https://github.com/yuvalavni/Agents"
|
|
28
35
|
Repository = "https://github.com/yuvalavni/Agents"
|
|
29
|
-
|
|
36
|
+
Issues = "https://github.com/yuvalavni/Agents/issues"
|
|
30
37
|
|
|
31
38
|
[project.scripts]
|
|
32
39
|
github-sync = "github_sync.cli:main"
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
# GitHub Sync Agent
|
|
2
|
-
|
|
3
|
-
Automatically syncs every local project directory to its own GitHub repository.
|
|
4
|
-
|
|
5
|
-
For each project it will:
|
|
6
|
-
1. `git init` if not already a repo
|
|
7
|
-
2. Create the GitHub repo if it doesn't exist yet
|
|
8
|
-
3. Ensure the remote uses SSH
|
|
9
|
-
4. Stage + commit any uncommitted changes
|
|
10
|
-
5. Push to `origin`
|
|
11
|
-
|
|
12
|
-
Runs daily via a systemd user timer, and on-demand via CLI.
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
## Installation
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
pip install github-sync-agent
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## First-time setup
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
github-sync init
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
The wizard will:
|
|
29
|
-
- Check `git` and `gh` are installed
|
|
30
|
-
- Authenticate with GitHub (`gh auth login`)
|
|
31
|
-
- Ask which folder to scan for projects
|
|
32
|
-
- Set up your SSH key automatically
|
|
33
|
-
- **Verify SSH works** (auto-fixes port 443 and ssh-agent if needed)
|
|
34
|
-
- Write a config file to `~/.config/github-sync/config.yaml`
|
|
35
|
-
|
|
36
|
-
Setup will **not** complete until `ssh -T git@github.com` succeeds.
|
|
37
|
-
|
|
38
|
-
---
|
|
39
|
-
|
|
40
|
-
## Usage
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
# Sync all projects
|
|
44
|
-
github-sync sync
|
|
45
|
-
|
|
46
|
-
# Sync a single project
|
|
47
|
-
github-sync sync --project my-project
|
|
48
|
-
|
|
49
|
-
# Preview without making changes
|
|
50
|
-
github-sync sync --dry-run
|
|
51
|
-
|
|
52
|
-
# Show status of all projects
|
|
53
|
-
github-sync status
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
---
|
|
57
|
-
|
|
58
|
-
## Configuration (`~/.config/github-sync/config.yaml`)
|
|
59
|
-
|
|
60
|
-
Generated by `github-sync init`. You can edit it at any time.
|
|
61
|
-
|
|
62
|
-
| Key | Default | Description |
|
|
63
|
-
|-----|---------|-------------|
|
|
64
|
-
| `github_user` | _(detected from gh auth)_ | Your GitHub username |
|
|
65
|
-
| `projects_root` | `~/projects` | Scans all subdirectories here |
|
|
66
|
-
| `schedule_time` | `02:00` | Daily run time |
|
|
67
|
-
| `default_visibility` | `private` | `private` or `public` for new repos |
|
|
68
|
-
| `auto_commit_message` | `chore: auto-sync` | Commit message for auto-commits |
|
|
69
|
-
| `exclude` | `[]` | Directory names to skip |
|
|
70
|
-
| `log_file` | `~/.local/share/github-sync/github-sync.log` | Log file path |
|
|
71
|
-
| `log_level` | `INFO` | `DEBUG` / `INFO` / `WARNING` / `ERROR` |
|
|
72
|
-
|
|
73
|
-
### Excluding a project
|
|
74
|
-
|
|
75
|
-
```yaml
|
|
76
|
-
exclude:
|
|
77
|
-
- SomeProjectToSkip
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
|
|
82
|
-
## Requirements
|
|
83
|
-
|
|
84
|
-
- Python 3.10+
|
|
85
|
-
- `git` installed
|
|
86
|
-
- `gh` (GitHub CLI) installed — [installation guide](https://cli.github.com)
|
|
87
|
-
|
|
88
|
-
---
|
|
89
|
-
|
|
90
|
-
## License
|
|
91
|
-
|
|
92
|
-
MIT
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.1.4"
|
|
File without changes
|
{github_sync_agent-0.1.4 → github_sync_agent-0.2.1}/github_sync_agent.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{github_sync_agent-0.1.4 → github_sync_agent-0.2.1}/github_sync_agent.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{github_sync_agent-0.1.4 → github_sync_agent-0.2.1}/github_sync_agent.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|