Add tool to setup notes repo

This commit is contained in:
Daniel O'Connell 2025-06-03 20:24:07 +02:00
parent c7aa50347c
commit 69cf2844f9
4 changed files with 61 additions and 5 deletions

View File

@ -54,6 +54,8 @@ The API will be available at `http://localhost:8000`
The is also an admin interface at `http://localhost:8000/admin` where you can see what the database The is also an admin interface at `http://localhost:8000/admin` where you can see what the database
contains. contains.
Because of how MCP can't yet handle basic auth,
## User Management ## User Management
### Create a User ### Create a User
@ -66,6 +68,18 @@ pip install -e ".[all]"
python tools/add_user.py --email user@example.com --password yourpassword --name "Your Name" python tools/add_user.py --email user@example.com --password yourpassword --name "Your Name"
``` ```
### Notes synchronisation
You can set up notes to be automatically pushed to a git repo whenever they are modified.
Run the following job to do so:
```bash
python tools/run_celery_task.py notes setup-git-notes --origin ssh://git@github.com/some/repo.git --email bla@ble.com --name <user to send commits>
```
For this to work you need to make sure you have set up the ssh keys in `secrets` (see the README.md
in that folder), and you will need to add the public key that is generated there to your git server.
### Authentication ### Authentication
The API uses session-based authentication. Login via: The API uses session-based authentication. Login via:

View File

@ -14,6 +14,7 @@ OBSERVATIONS_ROOT = "memory.workers.tasks.observations"
SYNC_NOTES = f"{NOTES_ROOT}.sync_notes" SYNC_NOTES = f"{NOTES_ROOT}.sync_notes"
SYNC_NOTE = f"{NOTES_ROOT}.sync_note" SYNC_NOTE = f"{NOTES_ROOT}.sync_note"
SETUP_GIT_NOTES = f"{NOTES_ROOT}.setup_git_notes"
SYNC_OBSERVATION = f"{OBSERVATIONS_ROOT}.sync_observation" SYNC_OBSERVATION = f"{OBSERVATIONS_ROOT}.sync_observation"
SYNC_ALL_COMICS = f"{COMIC_ROOT}.sync_all_comics" SYNC_ALL_COMICS = f"{COMIC_ROOT}.sync_all_comics"
SYNC_SMBC = f"{COMIC_ROOT}.sync_smbc" SYNC_SMBC = f"{COMIC_ROOT}.sync_smbc"

View File

@ -7,7 +7,7 @@ import shlex
from memory.common import settings from memory.common import settings
from memory.common.db.connection import make_session from memory.common.db.connection import make_session
from memory.common.db.models import Note from memory.common.db.models import Note
from memory.common.celery_app import app, SYNC_NOTE, SYNC_NOTES from memory.common.celery_app import app, SYNC_NOTE, SYNC_NOTES, SETUP_GIT_NOTES
from memory.workers.tasks.content_processing import ( from memory.workers.tasks.content_processing import (
check_content_exists, check_content_exists,
create_content_hash, create_content_hash,
@ -19,15 +19,14 @@ from memory.workers.tasks.content_processing import (
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def git_command(repo_root: pathlib.Path, *args: str): def git_command(repo_root: pathlib.Path, *args: str, force: bool = False):
if not (repo_root / ".git").exists(): if not (repo_root / ".git").exists() and not force:
return return
# Properly escape arguments for shell execution # Properly escape arguments for shell execution
escaped_args = [shlex.quote(arg) for arg in args] escaped_args = [shlex.quote(arg) for arg in args]
cmd = f"git -C {shlex.quote(repo_root.as_posix())} {' '.join(escaped_args)}" cmd = f"git -C {shlex.quote(repo_root.as_posix())} {' '.join(escaped_args)}"
logger.info(f"Running git command: {cmd}")
res = subprocess.run( res = subprocess.run(
cmd, cmd,
shell=True, shell=True,
@ -131,3 +130,21 @@ def sync_notes(folder: str):
"notes_num": len(all_files), "notes_num": len(all_files),
"new_notes": new_notes, "new_notes": new_notes,
} }
@app.task(name=SETUP_GIT_NOTES)
@safe_task_execution
def setup_git_notes(origin: str, email: str, name: str):
logger.info(f"Setting up git notes in {origin}")
if (settings.NOTES_STORAGE_DIR / ".git").exists():
logger.info("Git notes already setup")
return {"status": "already_setup"}
git_command(settings.NOTES_STORAGE_DIR, "init", "-b", "main", force=True)
git_command(settings.NOTES_STORAGE_DIR, "config", "user.email", email)
git_command(settings.NOTES_STORAGE_DIR, "config", "user.name", name)
git_command(settings.NOTES_STORAGE_DIR, "remote", "add", "origin", origin)
git_command(settings.NOTES_STORAGE_DIR, "add", ".")
git_command(settings.NOTES_STORAGE_DIR, "commit", "-m", "Initial commit")
git_command(settings.NOTES_STORAGE_DIR, "push", "-u", "origin", "main")
return {"status": "success"}

View File

@ -23,6 +23,7 @@ from typing import Any
import click import click
from celery import Celery from celery import Celery
from memory.common import settings
from memory.common.celery_app import ( from memory.common.celery_app import (
SYNC_ALL_ARTICLE_FEEDS, SYNC_ALL_ARTICLE_FEEDS,
SYNC_ARTICLE_FEED, SYNC_ARTICLE_FEED,
@ -47,6 +48,7 @@ from memory.common.celery_app import (
REINGEST_MISSING_CHUNKS, REINGEST_MISSING_CHUNKS,
UPDATE_METADATA_FOR_ITEM, UPDATE_METADATA_FOR_ITEM,
UPDATE_METADATA_FOR_SOURCE_ITEMS, UPDATE_METADATA_FOR_SOURCE_ITEMS,
SETUP_GIT_NOTES,
app, app,
) )
@ -87,6 +89,9 @@ TASK_MAPPINGS = {
"sync_lesswrong": SYNC_LESSWRONG, "sync_lesswrong": SYNC_LESSWRONG,
"sync_lesswrong_post": SYNC_LESSWRONG_POST, "sync_lesswrong_post": SYNC_LESSWRONG_POST,
}, },
"notes": {
"setup_git_notes": SETUP_GIT_NOTES,
},
} }
QUEUE_MAPPINGS = { QUEUE_MAPPINGS = {
"email": "email", "email": "email",
@ -106,7 +111,9 @@ def run_task(app: Celery, category: str, task_name: str, **kwargs) -> str:
task_path = TASK_MAPPINGS[category][task_name] task_path = TASK_MAPPINGS[category][task_name]
queue_name = QUEUE_MAPPINGS.get(category) or category queue_name = QUEUE_MAPPINGS.get(category) or category
result = app.send_task(task_path, kwargs=kwargs, queue=queue_name) result = app.send_task(
task_path, kwargs=kwargs, queue=f"{settings.CELERY_QUEUE_PREFIX}-{queue_name}"
)
return result.id return result.id
@ -224,6 +231,23 @@ def ebook_sync_book(ctx, file_path, tags):
execute_task(ctx, "ebook", "sync_book", file_path=file_path, tags=tags) execute_task(ctx, "ebook", "sync_book", file_path=file_path, tags=tags)
@cli.group()
@click.pass_context
def notes(ctx):
"""Notes-related tasks."""
pass
@notes.command("setup-git-notes")
@click.option("--origin", required=True, help="Git origin")
@click.option("--email", required=True, help="Git email")
@click.option("--name", required=True, help="Git name")
@click.pass_context
def notes_setup_git_notes(ctx, origin, email, name):
"""Setup git notes."""
execute_task(ctx, "notes", "setup_git_notes", origin=origin, email=email, name=name)
@cli.group() @cli.group()
@click.pass_context @click.pass_context
def maintenance(ctx): def maintenance(ctx):