Clean docs of host-specific release and contact details.
Describe releases generically and use the same git credentials as push.
This commit is contained in:
1 parent
2c02038e8c
commit
7d71ae8dde
7 files changed
+56
-64
No files matched your search
+9
-33
@@ -55,7 +55,7 @@ skills/<name>/
|
|||||||
git push origin main <name>/v<version>
|
git push origin main <name>/v<version>
|
||||||
```
|
```
|
||||||
|
|
||||||
7. Release vom eigenen Rechner anlegen (siehe unten). Auf git.gundel.dev läuft kein Actions-Runner.
|
7. Release anlegen (siehe unten): Pakete bauen und dem Tag als Anhänge hinzufügen.
|
||||||
|
|
||||||
## Update eines Skills
|
## Update eines Skills
|
||||||
|
|
||||||
@@ -91,50 +91,26 @@ powershell -ExecutionPolicy Bypass -File scripts\package-mcpb.ps1 -Name <name>
|
|||||||
powershell -ExecutionPolicy Bypass -File scripts\package-all.ps1
|
powershell -ExecutionPolicy Bypass -File scripts\package-all.ps1
|
||||||
```
|
```
|
||||||
|
|
||||||
### Vom eigenen Rechner
|
### Release veröffentlichen
|
||||||
|
|
||||||
Auf git.gundel.dev ist kein Actions-Runner registriert. Das Release legt deshalb ein Skript auf dem Rechner an, der das ZIP schon gebaut hat. Es spricht die Gitea-API an ([Release anlegen](https://docs.gitea.com/enterprise/api/21/operations/repo-create-release/), [Anhang hochladen](https://docs.gitea.com/api/operations/repo-create-release-attachment/)):
|
Der Tag `<name>/v<version>` muss lokal und remote existieren. Danach entweder:
|
||||||
|
|
||||||
- `POST /api/v1/repos/dg/claude-skills/releases`
|
**Skript** (baut ZIP/`.mcpb` und hängt sie ans Release; nutzt dieselbe Anmeldung wie `git push`):
|
||||||
- `POST /api/v1/repos/dg/claude-skills/releases/{id}/assets`
|
|
||||||
|
|
||||||
Dafür braucht es ein persönliches Zugangs-Token mit Schreibrecht auf dieses Repository (`write:repository`). Anlegen unter Profil → Einstellungen → Applications. Authentifizierung: [`Authorization: token …`](https://docs.gitea.com/development/api-usage/). Das Token nur in die Umgebung legen, nicht ins Repository.
|
|
||||||
|
|
||||||
Der Tag `<name>/v<version>` muss lokal existieren und schon auf dem Server liegen. Das Skript verschiebt keine Tags und pusht nichts.
|
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
$env:GITEA_TOKEN = '<Token>'
|
|
||||||
powershell -ExecutionPolicy Bypass -File scripts\release.ps1 -Name <name>
|
powershell -ExecutionPolicy Bypass -File scripts\release.ps1 -Name <name>
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
GITEA_TOKEN='<Token>' scripts/release.sh <name>
|
scripts/release.sh <name>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Manuell, ohne Token
|
**Oder manuell** in der Release-Oberfläche des Remotes:
|
||||||
|
|
||||||
1. Paket bauen (Befehle oben). Prüfen, dass `dist/<name>-v<version>.zip` die Einträge `<name>/` und `<name>/SKILL.md` enthält und weder `README.md` noch `CHANGELOG.md`.
|
1. Paket bauen (Befehle oben). Prüfen, dass `dist/<name>-v<version>.zip` die Einträge `<name>/` und `<name>/SKILL.md` enthält und weder `README.md` noch `CHANGELOG.md`.
|
||||||
2. Unter [Releases](https://git.gundel.dev/dg/claude-skills/releases) ein neues Release anlegen.
|
2. Neues Release zum Tag `<name>/v<version>` anlegen, Titel `<name> <version>`.
|
||||||
3. Tag: `<name>/v<version>` (der Tag muss schon auf dem Server liegen). Titel: `<name> <version>`.
|
3. Als Text den Abschnitt dieser Version aus `skills/<name>/CHANGELOG.md` einfügen.
|
||||||
4. Als Text den Abschnitt dieser Version aus `skills/<name>/CHANGELOG.md` einfügen.
|
4. `dist/<name>-v<version>.zip` und – falls vorhanden – `dist/<name>-v<version>.mcpb` anhängen.
|
||||||
5. `dist/<name>-v<version>.zip` als Anhang hochladen.
|
|
||||||
6. Falls vorhanden: `dist/<name>-v<version>.mcpb` ebenfalls hochladen (oder `scripts/release.ps1` nutzen – hängt beides an).
|
|
||||||
|
|
||||||
Nur die `.mcpb` nachträglich an ein bestehendes Release hängen (Token nur in der Umgebung):
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
$env:GITEA_TOKEN = '<Token>'
|
|
||||||
$id = <Release-ID>
|
|
||||||
$name = 'wordcraft-mcp-v0.2.0.mcpb'
|
|
||||||
$bytes = [IO.File]::ReadAllBytes("dist\$name")
|
|
||||||
$req = [Net.HttpWebRequest]::Create("https://git.gundel.dev/api/v1/repos/dg/claude-skills/releases/$id/assets?name=$name")
|
|
||||||
$req.Method = 'POST'
|
|
||||||
$req.Headers.Add('Authorization', "token $env:GITEA_TOKEN")
|
|
||||||
$req.ContentType = 'application/octet-stream'
|
|
||||||
$req.ContentLength = $bytes.LongLength
|
|
||||||
$s = $req.GetRequestStream(); $s.Write($bytes, 0, $bytes.Length); $s.Close()
|
|
||||||
$resp = $req.GetResponse(); (New-Object IO.StreamReader($resp.GetResponseStream())).ReadToEnd()
|
|
||||||
```
|
|
||||||
|
|
||||||
## Hinweise zu den Skripten
|
## Hinweise zu den Skripten
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# claude-skills
|
# claude-skills
|
||||||
|
|
||||||
Sammlung von Skills für Claude. Jeder Skill ist ein abgeschlossener Ordner: `SKILL.md` für Claude, `README.md` für Menschen. Die fertigen Pakete liegen als ZIP in den [Releases](https://git.gundel.dev/dg/claude-skills/releases) auf [git.gundel.dev/dg/claude-skills](https://git.gundel.dev/dg/claude-skills).
|
Sammlung von Skills für Claude. Jeder Skill ist ein abgeschlossener Ordner: `SKILL.md` für Claude, `README.md` für Menschen. Fertige Pakete liegen unter [Releases](https://git.gundel.dev/dg/claude-skills/releases).
|
||||||
|
|
||||||
Schritt-für-Schritt-Installation: [docs/INSTALLATION.md](docs/INSTALLATION.md).
|
Schritt-für-Schritt-Installation: [docs/INSTALLATION.md](docs/INSTALLATION.md).
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ Für jede `.mcpb`-Datei:
|
|||||||
5. Installieren. Die Erweiterung erscheint unter Einstellungen → Erweiterungen und muss **eingeschaltet** sein.
|
5. Installieren. Die Erweiterung erscheint unter Einstellungen → Erweiterungen und muss **eingeschaltet** sein.
|
||||||
|
|
||||||
> **Windows meldet „Der Computer wurde durch Windows geschützt“ oder Defender schlägt an?**
|
> **Windows meldet „Der Computer wurde durch Windows geschützt“ oder Defender schlägt an?**
|
||||||
> Die Erweiterungen sind nicht signiert. Wende dich an Dominic, bevor du die Warnung übergehst.
|
> Die Erweiterungen sind nicht signiert. Nur installieren, wenn du der Quelle vertraust.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+17
-16
@@ -1,17 +1,19 @@
|
|||||||
# Baut das ZIP eines Skills und legt damit ein Gitea-Release an.
|
# Builds the skill ZIP (and .mcpb if extension/) and creates a remote release with those assets.
|
||||||
# Kein Actions-Runner. Der Tag <name>/v<version> muss lokal und auf dem Server liegen.
|
# Auth: same as git push (credential helper), or env RELEASE_TOKEN if set.
|
||||||
# Token: Umgebungsvariable GITEA_TOKEN (persoenliches Zugangs-Token, nicht ins Repo).
|
# The tag <name>/v<version> must exist locally and on the remote. Does not push tags.
|
||||||
# Aufruf: scripts\release.ps1 -Name <skill-name>
|
# Usage: scripts\release.ps1 -Name <skill-name>
|
||||||
param([Parameter(Mandatory = $true)][string]$Name)
|
param([Parameter(Mandatory = $true)][string]$Name)
|
||||||
. (Join-Path $PSScriptRoot 'lib.ps1')
|
. (Join-Path $PSScriptRoot 'lib.ps1')
|
||||||
|
|
||||||
# Prefer GITEA_TOKEN; otherwise reuse git credential helper (same auth as git push).
|
$RepoApi = 'https://git.gundel.dev/api/v1/repos/dg/claude-skills'
|
||||||
|
$RepoHost = 'git.gundel.dev'
|
||||||
|
|
||||||
$AuthHeader = $null
|
$AuthHeader = $null
|
||||||
if ($env:GITEA_TOKEN) {
|
if ($env:RELEASE_TOKEN) {
|
||||||
$AuthHeader = "token $($env:GITEA_TOKEN)"
|
$AuthHeader = "token $($env:RELEASE_TOKEN)"
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$credRaw = "protocol=https`nhost=git.gundel.dev`n`n" | git credential fill 2>$null
|
$credRaw = "protocol=https`nhost=$RepoHost`n`n" | git credential fill 2>$null
|
||||||
$user = $null; $pass = $null
|
$user = $null; $pass = $null
|
||||||
foreach ($line in $credRaw) {
|
foreach ($line in $credRaw) {
|
||||||
if ($line -match '^username=(.*)$') { $user = $Matches[1] }
|
if ($line -match '^username=(.*)$') { $user = $Matches[1] }
|
||||||
@@ -23,7 +25,7 @@ else {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (-not $AuthHeader) {
|
if (-not $AuthHeader) {
|
||||||
Write-Host 'Keine Auth: GITEA_TOKEN setzen oder git credential fuer git.gundel.dev hinterlegen.'
|
Write-Host 'Keine Auth fuer das Release (git credential oder RELEASE_TOKEN).'
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,10 +70,9 @@ foreach ($l in ((Read-Text (Join-Path $dir 'CHANGELOG.md')) -split "`n")) {
|
|||||||
}
|
}
|
||||||
$notes = (($acc -join "`n").Trim())
|
$notes = (($acc -join "`n").Trim())
|
||||||
|
|
||||||
$api = 'https://git.gundel.dev/api/v1/repos/dg/claude-skills'
|
|
||||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||||
|
|
||||||
function Invoke-Gitea([string]$Method, [string]$Url, [byte[]]$Body, [string]$ContentType) {
|
function Invoke-ReleaseApi([string]$Method, [string]$Url, [byte[]]$Body, [string]$ContentType) {
|
||||||
$req = [Net.HttpWebRequest]::Create($Url)
|
$req = [Net.HttpWebRequest]::Create($Url)
|
||||||
$req.Method = $Method
|
$req.Method = $Method
|
||||||
$req.Headers.Add('Authorization', $AuthHeader)
|
$req.Headers.Add('Authorization', $AuthHeader)
|
||||||
@@ -109,7 +110,7 @@ $payload = @{
|
|||||||
body = $notes
|
body = $notes
|
||||||
} | ConvertTo-Json -Compress
|
} | ConvertTo-Json -Compress
|
||||||
try {
|
try {
|
||||||
$created = Invoke-Gitea 'POST' "$api/releases" $Utf8NoBom.GetBytes($payload) 'application/json; charset=utf-8' | ConvertFrom-Json
|
$created = Invoke-ReleaseApi 'POST' "$RepoApi/releases" $Utf8NoBom.GetBytes($payload) 'application/json; charset=utf-8' | ConvertFrom-Json
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
Write-Host $_
|
Write-Host $_
|
||||||
@@ -117,8 +118,8 @@ catch {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
$assetUrl = "$api/releases/$($created.id)/assets?name=$([Uri]::EscapeDataString($zipName))"
|
$assetUrl = "$RepoApi/releases/$($created.id)/assets?name=$([Uri]::EscapeDataString($zipName))"
|
||||||
$asset = Invoke-Gitea 'POST' $assetUrl ([IO.File]::ReadAllBytes($zipPath)) 'application/octet-stream' | ConvertFrom-Json
|
$asset = Invoke-ReleaseApi 'POST' $assetUrl ([IO.File]::ReadAllBytes($zipPath)) 'application/octet-stream' | ConvertFrom-Json
|
||||||
|
|
||||||
$mcpbName = "$Name-v$ver.mcpb"
|
$mcpbName = "$Name-v$ver.mcpb"
|
||||||
$mcpbPath = Join-Path $DistDir $mcpbName
|
$mcpbPath = Join-Path $DistDir $mcpbName
|
||||||
@@ -129,8 +130,8 @@ if (Test-Path (Join-Path (Join-Path $dir 'extension') 'manifest.json')) {
|
|||||||
if ($LASTEXITCODE -ne 0) { exit 1 }
|
if ($LASTEXITCODE -ne 0) { exit 1 }
|
||||||
}
|
}
|
||||||
if (Test-Path $mcpbPath) {
|
if (Test-Path $mcpbPath) {
|
||||||
$mcpbUrl = "$api/releases/$($created.id)/assets?name=$([Uri]::EscapeDataString($mcpbName))"
|
$mcpbUrl = "$RepoApi/releases/$($created.id)/assets?name=$([Uri]::EscapeDataString($mcpbName))"
|
||||||
$mcpbAsset = Invoke-Gitea 'POST' $mcpbUrl ([IO.File]::ReadAllBytes($mcpbPath)) 'application/octet-stream' | ConvertFrom-Json
|
$mcpbAsset = Invoke-ReleaseApi 'POST' $mcpbUrl ([IO.File]::ReadAllBytes($mcpbPath)) 'application/octet-stream' | ConvertFrom-Json
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+26
-11
@@ -1,8 +1,8 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Baut das ZIP eines Skills und legt damit ein Gitea-Release an.
|
# Builds the skill ZIP (and .mcpb if extension/) and creates a remote release with those assets.
|
||||||
# Kein Actions-Runner. Der Tag <name>/v<version> muss lokal und auf dem Server liegen.
|
# Auth: git credential helper, or env RELEASE_TOKEN if set.
|
||||||
# Token: Umgebungsvariable GITEA_TOKEN (persönliches Zugangs-Token, nicht ins Repo).
|
# The tag <name>/v<version> must exist locally and on the remote. Does not push tags.
|
||||||
# Aufruf: scripts/release.sh <skill-name>
|
# Usage: scripts/release.sh <skill-name>
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
source "$(dirname "$0")/lib.sh"
|
source "$(dirname "$0")/lib.sh"
|
||||||
|
|
||||||
@@ -11,15 +11,31 @@ if [[ -z "$name" ]]; then
|
|||||||
echo "Aufruf: scripts/release.sh <skill-name>" >&2
|
echo "Aufruf: scripts/release.sh <skill-name>" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if [[ -z "${GITEA_TOKEN:-}" ]]; then
|
|
||||||
echo "GITEA_TOKEN fehlt. Persönliches Zugangs-Token mit Schreibrecht (write:repository), nur in der Umgebung." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if ! command -v python3 >/dev/null 2>&1 || ! command -v curl >/dev/null 2>&1; then
|
if ! command -v python3 >/dev/null 2>&1 || ! command -v curl >/dev/null 2>&1; then
|
||||||
echo "release.sh braucht curl und python3. Unter Windows: scripts\\release.ps1" >&2
|
echo "release.sh braucht curl und python3. Unter Windows: scripts\\release.ps1" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
REPO_HOST=git.gundel.dev
|
||||||
|
api="https://$REPO_HOST/api/v1/repos/dg/claude-skills"
|
||||||
|
|
||||||
|
auth_header=""
|
||||||
|
if [[ -n "${RELEASE_TOKEN:-}" ]]; then
|
||||||
|
auth_header="Authorization: token $RELEASE_TOKEN"
|
||||||
|
else
|
||||||
|
cred="$(printf 'protocol=https\nhost=%s\n\n' "$REPO_HOST" | git credential fill 2>/dev/null || true)"
|
||||||
|
user="$(printf '%s\n' "$cred" | sed -n 's/^username=//p' | head -n1)"
|
||||||
|
pass="$(printf '%s\n' "$cred" | sed -n 's/^password=//p' | head -n1)"
|
||||||
|
if [[ -n "$user" && -n "$pass" ]]; then
|
||||||
|
basic="$(printf '%s:%s' "$user" "$pass" | base64 | tr -d '\n')"
|
||||||
|
auth_header="Authorization: Basic $basic"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [[ -z "$auth_header" ]]; then
|
||||||
|
echo "Keine Auth fuer das Release (git credential oder RELEASE_TOKEN)." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
dir="$SKILLS_DIR/$name"
|
dir="$SKILLS_DIR/$name"
|
||||||
version="$(skill_version "$dir")"
|
version="$(skill_version "$dir")"
|
||||||
if [[ -z "$version" ]]; then
|
if [[ -z "$version" ]]; then
|
||||||
@@ -55,10 +71,9 @@ print(json.dumps({
|
|||||||
"body": open(os.environ["NOTES"], encoding="utf-8").read().strip(),
|
"body": open(os.environ["NOTES"], encoding="utf-8").read().strip(),
|
||||||
}))' > "$payload"
|
}))' > "$payload"
|
||||||
|
|
||||||
api="https://git.gundel.dev/api/v1/repos/dg/claude-skills"
|
|
||||||
resp="$(mktemp)"
|
resp="$(mktemp)"
|
||||||
code="$(curl -sS -o "$resp" -w '%{http_code}' -X POST "$api/releases" \
|
code="$(curl -sS -o "$resp" -w '%{http_code}' -X POST "$api/releases" \
|
||||||
-H "Authorization: token $GITEA_TOKEN" \
|
-H "$auth_header" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
--data-binary @"$payload")"
|
--data-binary @"$payload")"
|
||||||
if [[ "$code" != "201" ]]; then
|
if [[ "$code" != "201" ]]; then
|
||||||
@@ -78,7 +93,7 @@ upload_asset() {
|
|||||||
local asset_resp code asset download
|
local asset_resp code asset download
|
||||||
asset_resp="$(mktemp)"
|
asset_resp="$(mktemp)"
|
||||||
code="$(curl -sS -o "$asset_resp" -w '%{http_code}' -X POST "$api/releases/$rel_id/assets?name=$file_name" \
|
code="$(curl -sS -o "$asset_resp" -w '%{http_code}' -X POST "$api/releases/$rel_id/assets?name=$file_name" \
|
||||||
-H "Authorization: token $GITEA_TOKEN" \
|
-H "$auth_header" \
|
||||||
-H "Content-Type: application/octet-stream" \
|
-H "Content-Type: application/octet-stream" \
|
||||||
--data-binary @"$file_path")"
|
--data-binary @"$file_path")"
|
||||||
if [[ "$code" != "201" ]]; then
|
if [[ "$code" != "201" ]]; then
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ Fehlen die Tools: Einstellungen → Erweiterungen – ist die Erweiterung einges
|
|||||||
|
|
||||||
## Stolpersteine
|
## Stolpersteine
|
||||||
|
|
||||||
- Erweiterungen sind nicht signiert; bei Defender-Warnung an Dominic wenden.
|
- Erweiterungen sind nicht signiert; nur installieren, wenn du der Quelle vertraust.
|
||||||
- Formeln mit deutschen Namen ergeben `#NAME?` – englische Funktionsnamen verlangen.
|
- Formeln mit deutschen Namen ergeben `#NAME?` – englische Funktionsnamen verlangen.
|
||||||
|
|
||||||
## Deinstallation/Update
|
## Deinstallation/Update
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ Fehlen die Tools: Einstellungen → Erweiterungen – ist die Erweiterung einges
|
|||||||
## Stolpersteine
|
## Stolpersteine
|
||||||
|
|
||||||
- Speichern mit „path rejected“: Ziel lag außerhalb des Schreib-Ordners. Einstellungen → Erweiterungen → WordCraft für Claude → Einstellungen prüfen.
|
- Speichern mit „path rejected“: Ziel lag außerhalb des Schreib-Ordners. Einstellungen → Erweiterungen → WordCraft für Claude → Einstellungen prüfen.
|
||||||
- Erweiterungen sind nicht signiert; bei Defender-Warnung an Dominic wenden.
|
- Erweiterungen sind nicht signiert; nur installieren, wenn du der Quelle vertraust.
|
||||||
|
|
||||||
## Deinstallation/Update
|
## Deinstallation/Update
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user