Compare commits
4
Commits
a8688302ac
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4675ebce6a | ||
|
|
e1ed8688f0 | ||
|
|
d00d195ac3 | ||
|
|
72a1ca284a |
No files matched your search
@@ -36,7 +36,7 @@
|
|||||||
{
|
{
|
||||||
"name": "redmine",
|
"name": "redmine",
|
||||||
"source": "./plugins/redmine",
|
"source": "./plugins/redmine",
|
||||||
"description": "Redmine via REST-API: Projekte, Tickets, Versionen und News auflisten, anzeigen, anlegen, aktualisieren und kommentieren via redmine.py (API-Key lokal)."
|
"description": "Redmine via REST-API: Projekte, Tickets, Versionen, News und Projekt-Wikis auflisten, anzeigen, anlegen, aktualisieren und kommentieren via redmine.py (API-Key lokal)."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "grill-me",
|
"name": "grill-me",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mediawiki",
|
"name": "mediawiki",
|
||||||
"version": "0.1.0",
|
"version": "0.1.1",
|
||||||
"description": "MediaWiki-Seiten/Templates lesen, rendern und schreiben via wiki.py (fetch/update/render/search, Instanzen wiki & devwiki).",
|
"description": "MediaWiki-Seiten/Templates lesen, rendern und schreiben via wiki.py (fetch/update/render/search, Instanzen wiki & devwiki).",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "inmedias.it"
|
"name": "inmedias.it"
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ def cmd_search(args: argparse.Namespace) -> None:
|
|||||||
sys.exit(f"Error: unknown namespace '{ns_key}'. "
|
sys.exit(f"Error: unknown namespace '{ns_key}'. "
|
||||||
f"Known: all, {', '.join(NAMESPACES)}")
|
f"Known: all, {', '.join(NAMESPACES)}")
|
||||||
|
|
||||||
|
try:
|
||||||
result = site.api(
|
result = site.api(
|
||||||
"query", list="search",
|
"query", list="search",
|
||||||
srsearch=args.query,
|
srsearch=args.query,
|
||||||
@@ -95,6 +96,12 @@ def cmd_search(args: argparse.Namespace) -> None:
|
|||||||
srlimit=50,
|
srlimit=50,
|
||||||
srprop="title|snippet",
|
srprop="title|snippet",
|
||||||
)
|
)
|
||||||
|
except mwclient.errors.APIError as exc:
|
||||||
|
if exc.code == "cirrussearch-parse-error":
|
||||||
|
sys.exit(f"Error: Suchanfrage nicht verstanden: {args.query!r}\n"
|
||||||
|
f"Hinweis: 'insource:wort' funktioniert, die Regex-Form "
|
||||||
|
f"'insource:/muster/' ist auf dieser Instanz nicht freigeschaltet.")
|
||||||
|
sys.exit(f"Error: Suche fehlgeschlagen ({exc.code}): {exc.info}")
|
||||||
hits = result["query"]["search"]
|
hits = result["query"]["search"]
|
||||||
if not hits:
|
if not hits:
|
||||||
print("(keine Ergebnisse)", file=sys.stderr)
|
print("(keine Ergebnisse)", file=sys.stderr)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "redmine",
|
"name": "redmine",
|
||||||
"version": "0.2.0",
|
"version": "0.3.0",
|
||||||
"description": "Redmine via REST-API: Projekte/Tickets/Versionen/News auflisten, anlegen, aktualisieren, kommentieren (redmine.py).",
|
"description": "Redmine via REST-API: Projekte/Tickets/Versionen/News/Wiki-Seiten auflisten, anlegen, aktualisieren, kommentieren (redmine.py).",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "inmedias.it"
|
"name": "inmedias.it"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
---
|
---
|
||||||
name: redmine
|
name: redmine
|
||||||
description: Redmine-Projekte, -Tickets, -Versionen und -News lesen/anlegen/aktualisieren via REST-API. Use when the user mentions "Redmine", "Ticket", "Issue in Redmine", "Meilenstein/Milestone/Version", "Projektstand/News" or die Projekte "pg-wissen"/"devops".
|
description: Redmine-Projekte, -Tickets, -Versionen, -News und Projekt-Wikis lesen/anlegen/aktualisieren via REST-API. Use when the user mentions "Redmine", "Ticket", "Issue in Redmine", "Meilenstein/Milestone/Version", "Projektstand/News", "Redmine-Wiki" or die Projekte "pg-wissen"/"devops".
|
||||||
version: 0.2.0
|
version: 0.3.0
|
||||||
---
|
---
|
||||||
|
|
||||||
# Redmine (redmine.py)
|
# Redmine (redmine.py)
|
||||||
|
|
||||||
Interagiert mit Redmine (https://redmine.inmedias.it) über die REST-API:
|
Interagiert mit Redmine (https://redmine.inmedias.it) über die REST-API:
|
||||||
Projekte, Tickets, Versionen und News auflisten, anzeigen, anlegen,
|
Projekte, Tickets, Versionen, News und Projekt-Wikis auflisten, anzeigen,
|
||||||
aktualisieren und kommentieren - über die mitgelieferte, self-contained
|
anlegen, aktualisieren und kommentieren - über die mitgelieferte, self-contained
|
||||||
`redmine.py`. Namen werden auf IDs aufgelöst (Projekt, Tracker, Status,
|
`redmine.py`. Namen werden auf IDs aufgelöst (Projekt, Tracker, Status,
|
||||||
Priorität, Version).
|
Priorität, Version).
|
||||||
|
|
||||||
@@ -94,6 +94,34 @@ Zwei Eigenheiten der Redmine-API:
|
|||||||
|
|
||||||
Format ist Markdown, wie bei Tickets.
|
Format ist Markdown, wie bei Tickets.
|
||||||
|
|
||||||
|
### Projekt-Wiki
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./redmine.py wiki --project devops # Seiten auflisten
|
||||||
|
./redmine.py wiki --project devops --title Wiki # Seite anzeigen
|
||||||
|
./redmine.py wiki --project devops --title Wiki --version 2
|
||||||
|
|
||||||
|
./redmine.py wiki --project devops --title "Bericht" \
|
||||||
|
--text-file bericht.md --comment "Erhebung vom 13.10."
|
||||||
|
|
||||||
|
./redmine.py wiki --project devops --title "Unterseite" \
|
||||||
|
--text-file u.md --parent "Bericht" # Seite einhängen
|
||||||
|
```
|
||||||
|
|
||||||
|
Drei Eigenheiten:
|
||||||
|
|
||||||
|
- **Anlegen und Ändern sind derselbe `PUT`.** Ein Tippfehler im Titel erzeugt
|
||||||
|
sonst stillschweigend eine neue Seite. `redmine.py` sieht deshalb vorher nach
|
||||||
|
und meldet „Angelegt" bzw. „Geändert".
|
||||||
|
- **Leerzeichen werden zu Unterstriche.** Redmine normalisiert den Titel; beide
|
||||||
|
Schreibweisen treffen dieselbe Seite.
|
||||||
|
- **Die Startseite heißt `Wiki`.** Existiert sie nicht, ist das Projekt-Wiki
|
||||||
|
leer und `/projects/<kennung>/wiki` läuft ins Leere. Eine Seite mit genau
|
||||||
|
diesem Titel legt die Startseite an.
|
||||||
|
|
||||||
|
Löschen deckt `redmine.py` bewusst nicht ab - dafür
|
||||||
|
`DELETE /projects/<kennung>/wiki/<Titel>.json`.
|
||||||
|
|
||||||
## Zugangsdaten
|
## Zugangsdaten
|
||||||
|
|
||||||
`redmine.py` bringt **keinen** Schlüssel mit. Jede/r hinterlegt einen eigenen
|
`redmine.py` bringt **keinen** Schlüssel mit. Jede/r hinterlegt einen eigenen
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ Beispiele:
|
|||||||
uv run redmine.py news --project devops
|
uv run redmine.py news --project devops
|
||||||
uv run redmine.py news --project devops --title "Kurz" --description-file text.md
|
uv run redmine.py news --project devops --title "Kurz" --description-file text.md
|
||||||
uv run redmine.py news --id 1 --description-file korrigiert.md
|
uv run redmine.py news --id 1 --description-file korrigiert.md
|
||||||
|
uv run redmine.py wiki --project devops
|
||||||
|
uv run redmine.py wiki --project devops --title Wiki
|
||||||
|
uv run redmine.py wiki --project devops --title Bericht --text-file bericht.md
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -32,6 +35,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from urllib.parse import quote
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
@@ -317,6 +321,64 @@ def cmd_news(s, a):
|
|||||||
print(f"Angelegt in Projekt {pid} -> {s.base}/projects/{pid}/news")
|
print(f"Angelegt in Projekt {pid} -> {s.base}/projects/{pid}/news")
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_wiki(s, a):
|
||||||
|
"""Wiki-Seiten eines Projekts auflisten, lesen oder schreiben.
|
||||||
|
|
||||||
|
Drei Betriebsarten, unterschieden an den Angaben:
|
||||||
|
ohne --title Seiten des Projekts auflisten
|
||||||
|
--title Seite anzeigen
|
||||||
|
--title mit --text/--text-file Seite schreiben (PUT legt an oder ändert)
|
||||||
|
|
||||||
|
Redmine nimmt zum Schreiben denselben PUT für Anlegen und Ändern. Damit ein
|
||||||
|
Tippfehler im Titel nicht unbemerkt eine neue Seite erzeugt, wird vorher
|
||||||
|
nachgesehen, ob die Seite schon existiert, und das Ergebnis entsprechend
|
||||||
|
gemeldet.
|
||||||
|
|
||||||
|
Die Startseite eines Projekt-Wikis heißt bei Redmine standardmäßig `Wiki`.
|
||||||
|
"""
|
||||||
|
pid = resolve_project(s, a.project)
|
||||||
|
base = f"/projects/{pid}/wiki"
|
||||||
|
|
||||||
|
if not a.title:
|
||||||
|
pages = api(s, "GET", f"{base}/index.json").get("wiki_pages", [])
|
||||||
|
if a.json:
|
||||||
|
return print(json.dumps(pages, ensure_ascii=False, indent=2))
|
||||||
|
if not pages:
|
||||||
|
return print("— keine Wiki-Seiten")
|
||||||
|
for w in sorted(pages, key=lambda x: x["title"]):
|
||||||
|
eltern = w.get("parent", {}).get("title")
|
||||||
|
print(f" v{w.get('version', '?'):<3} {str(w.get('updated_on', ''))[:10]} "
|
||||||
|
f"{w['title']}" + (f" (unter {eltern})" if eltern else ""))
|
||||||
|
return
|
||||||
|
|
||||||
|
titel = quote(a.title, safe="")
|
||||||
|
text = read_text(a.text, a.text_file)
|
||||||
|
|
||||||
|
if text is None:
|
||||||
|
pfad = f"{base}/{titel}" + (f"/{a.version}" if a.version else "") + ".json"
|
||||||
|
w = api(s, "GET", pfad).get("wiki_page", {})
|
||||||
|
if a.json:
|
||||||
|
return print(json.dumps(w, ensure_ascii=False, indent=2))
|
||||||
|
autor = w.get("author", {}).get("name", "?")
|
||||||
|
print(f"# {w.get('title')} (v{w.get('version')}, {autor}, "
|
||||||
|
f"{str(w.get('updated_on', ''))[:16]})")
|
||||||
|
print(f"# {s.base}/projects/{pid}/wiki/{titel}")
|
||||||
|
print("---")
|
||||||
|
return print(w.get("text", ""))
|
||||||
|
|
||||||
|
seite = {"text": text}
|
||||||
|
if a.comment:
|
||||||
|
seite["comments"] = a.comment
|
||||||
|
if a.parent:
|
||||||
|
seite["parent_title"] = a.parent
|
||||||
|
# Vorher nachsehen: 404 heißt anlegen, alles andere ändern.
|
||||||
|
r = s.request("GET", f"{s.base}{base}/{titel}.json")
|
||||||
|
neu = r.status_code == 404
|
||||||
|
api(s, "PUT", f"{base}/{titel}.json", data=json.dumps({"wiki_page": seite}))
|
||||||
|
print(f"{'Angelegt' if neu else 'Geändert'}: {a.title} "
|
||||||
|
f"-> {s.base}/projects/{pid}/wiki/{titel}")
|
||||||
|
|
||||||
|
|
||||||
def cmd_meta(s, a):
|
def cmd_meta(s, a):
|
||||||
spec = {
|
spec = {
|
||||||
"trackers": ("/trackers.json", "trackers"),
|
"trackers": ("/trackers.json", "trackers"),
|
||||||
@@ -387,6 +449,15 @@ def main():
|
|||||||
pv.add_argument("--due", help="Fälligkeitsdatum (YYYY-MM-DD)")
|
pv.add_argument("--due", help="Fälligkeitsdatum (YYYY-MM-DD)")
|
||||||
pv.add_argument("--description", help="Beschreibung")
|
pv.add_argument("--description", help="Beschreibung")
|
||||||
|
|
||||||
|
pw = sub.add_parser("wiki", help="Wiki-Seiten auflisten, lesen oder schreiben")
|
||||||
|
pw.add_argument("--project", required=True, help="Projekt (ID/Identifier/Name)")
|
||||||
|
pw.add_argument("--title", help="Seitentitel - ohne Angabe werden die Seiten aufgelistet")
|
||||||
|
pw.add_argument("--text", help="Seiteninhalt; gesetzt heißt: schreiben statt anzeigen")
|
||||||
|
pw.add_argument("--text-file", help="Datei oder '-' für stdin")
|
||||||
|
pw.add_argument("--comment", help="Änderungskommentar (erscheint in der Historie)")
|
||||||
|
pw.add_argument("--parent", help="Titel der übergeordneten Seite")
|
||||||
|
pw.add_argument("--version", help="alte Fassung anzeigen (Versionsnummer)")
|
||||||
|
|
||||||
pm = sub.add_parser("meta", help="Stammdaten auflisten")
|
pm = sub.add_parser("meta", help="Stammdaten auflisten")
|
||||||
pm.add_argument("kind", choices=["trackers", "statuses", "priorities"])
|
pm.add_argument("kind", choices=["trackers", "statuses", "priorities"])
|
||||||
|
|
||||||
@@ -395,7 +466,7 @@ def main():
|
|||||||
{
|
{
|
||||||
"me": cmd_me, "projects": cmd_projects, "issues": cmd_issues, "show": cmd_show,
|
"me": cmd_me, "projects": cmd_projects, "issues": cmd_issues, "show": cmd_show,
|
||||||
"create": cmd_create, "update": cmd_update, "comment": cmd_comment,
|
"create": cmd_create, "update": cmd_update, "comment": cmd_comment,
|
||||||
"news": cmd_news, "versions": cmd_versions, "meta": cmd_meta,
|
"news": cmd_news, "versions": cmd_versions, "wiki": cmd_wiki, "meta": cmd_meta,
|
||||||
}[a.cmd](s, a)
|
}[a.cmd](s, a)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user