Préparation pour la chaîne d'outils a2m
- Manifest : Blender 5.1 minimum, maintainer Ange-Marie MAURIN, website (fiche a2msystemes.org), .a2m/ exclu du paquet - CHANGELOG.md (en) et CHANGELOG.fr.md (fr) : historique 1.0.0 → 1.4.0 repris du CLAUDE.md, mise au format a2m dans la section non publiée - tools/Build-Package.ps1 et tools/New-GiteaRelease.ps1 retirés : remplacés par a2m build et a2m release - README, CLAUDE.md, .gitignore : commandes a2m, historique dans le CHANGELOG, note « dépôt d'extensions » rattachée à APC Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ec3ed21b1e
commit
bc01a01e09
8 files changed
+125
-295
No files matched your search
+1
-1
@@ -2,7 +2,7 @@
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
|
||||
# Paquets d'extension (construits par tools/Build-Package.ps1)
|
||||
# Paquets d'extension (construits par a2m build)
|
||||
dist/
|
||||
*.zip
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Journal des modifications
|
||||
|
||||
Format : [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/) ; versions : [SemVer](https://semver.org/lang/fr/).
|
||||
La section « Non publié » est reprise par `a2m release` sous le numéro de la nouvelle version
|
||||
(version anglaise : [CHANGELOG.md](CHANGELOG.md)).
|
||||
|
||||
## [Non publié]
|
||||
|
||||
### Modifié
|
||||
|
||||
- Version minimale de Blender : 5.1.
|
||||
- Publication par la chaîne d'outils a2m, pour le dépôt d'extensions d'a2msystemes.org (mises à jour proposées
|
||||
directement dans Blender) ; fiche du projet : https://a2msystemes.org/projets/slice_wrap.
|
||||
|
||||
## [1.4.0] - 2026-10-17
|
||||
|
||||
### Modifié
|
||||
|
||||
- Réglage Target supprimé : l'objet sélectionné est utilisé.
|
||||
- Confirmation avant les calculs longs, barre de progression (barre d'état et panneau) ; Blender n'est plus bloqué,
|
||||
Échap annule sans rien laisser.
|
||||
|
||||
## [1.3.0]
|
||||
|
||||
### Ajouté
|
||||
|
||||
- Suffix (`_slicewrapped`), numérotation automatique (plus aucun objet écrasé), collection optionnelle.
|
||||
|
||||
## [1.2.0]
|
||||
|
||||
### Ajouté
|
||||
|
||||
- Analyze (carte de détail, tags, direction des plis), Show Detail / Shapes, Protect Detail.
|
||||
|
||||
## [1.1.0]
|
||||
|
||||
### Ajouté
|
||||
|
||||
- Bouton unique « Slice Wrap » et Despike After ; Steps en sous-panneau.
|
||||
- Despike : Distance, Strength, Iterations, filtres par groupes de sommets ; réparation des ratés au Freeze.
|
||||
|
||||
## [1.0.0]
|
||||
|
||||
### Ajouté
|
||||
|
||||
- Envelope, Regenerate, Wrap Setup, Freeze (Reshape), Despike.
|
||||
@@ -0,0 +1,46 @@
|
||||
# Changelog
|
||||
|
||||
Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions: [SemVer](https://semver.org/).
|
||||
The "Unreleased" section is taken by `a2m release` under the number of the new version
|
||||
(French version: [CHANGELOG.fr.md](CHANGELOG.fr.md)).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
|
||||
- Minimum Blender version: 5.1.
|
||||
- Published by the a2m toolchain, for the a2msystemes.org extension repository (updates offered directly in
|
||||
Blender); project page: https://a2msystemes.org/en/projects/slice_wrap.
|
||||
|
||||
## [1.4.0] - 2026-10-17
|
||||
|
||||
### Changed
|
||||
|
||||
- Target setting removed: the selected object is used.
|
||||
- Confirmation before long computations, progress bar (status bar and panel); Blender is no longer blocked, Esc
|
||||
cancels without leaving anything behind.
|
||||
|
||||
## [1.3.0]
|
||||
|
||||
### Added
|
||||
|
||||
- Suffix (`_slicewrapped`), automatic numbering (no object is ever overwritten), optional collection.
|
||||
|
||||
## [1.2.0]
|
||||
|
||||
### Added
|
||||
|
||||
- Analyze (detail map, tags, fold direction), Show Detail / Shapes, Protect Detail.
|
||||
|
||||
## [1.1.0]
|
||||
|
||||
### Added
|
||||
|
||||
- Single "Slice Wrap" button and Despike After; Steps as a sub-panel.
|
||||
- Despike: Distance, Strength, Iterations, vertex group filters; missed rays repaired at Freeze.
|
||||
|
||||
## [1.0.0]
|
||||
|
||||
### Added
|
||||
|
||||
- Envelope, Regenerate, Wrap Setup, Freeze (Reshape), Despike.
|
||||
@@ -79,52 +79,39 @@ flow ici : la retopologie guidée est un projet séparé, **Slice Retopo**
|
||||
`voxelize`, `blocky_mesh`), nettoyage (`taubin`, `keep_largest_island`, `despike`, `group_weights`,
|
||||
`fix_missed_rays`), analyse (`analyze_shape`, `write_analysis`), `unique_object_name`, `build_envelope`.
|
||||
- `tests/run_tests.py` : suite (sphère trouée bruitée ; `--head` = tête réelle + rendus). Exclu du paquet.
|
||||
- `blender_manifest.toml` : extension 4.2+ ; `[build]` exclut `__pycache__/`, zips, `.claude/`, `.git/`, `CLAUDE.md`,
|
||||
`tests/`, `tools/`, `dist/`.
|
||||
- `tools/Build-Package.ps1` (paquet), `tools/New-GiteaRelease.ps1` (release Gitea). Exclus du paquet.
|
||||
- `blender_manifest.toml` : extension **5.1+** (décidé le 2026-10-20) ; `[build]` exclut `__pycache__/`, zips,
|
||||
`.a2m/`, `.claude/`, `.git/`, `.gitignore`, `CLAUDE.md`, `tests/`, `dist/`.
|
||||
- `.a2m/project.toml` : données du projet pour la chaîne d'outils a2m et le site (écrit par `a2m adopt`).
|
||||
- `CHANGELOG.md` (en) / `CHANGELOG.fr.md` (fr) : historique ; la section « Unreleased » / « Non publié » donne les
|
||||
notes de la prochaine release.
|
||||
|
||||
## Commandes
|
||||
- Tests : `"C:\Program Files\Blender Foundation\Blender 5.2\blender.exe" -b -P tests/run_tests.py -- <dossier> [--head]`
|
||||
→ `RESULTAT : TOUT OK` (~1 min, 29 contrôles dont annulations) ; avec `--head`, regarder `slice_wrap_head_face.png` / `_cote.png`.
|
||||
- Paquet : `.\tools\Build-Package.ps1 [-RunTests]` → `dist\slice_wrap-<version>.zip` (validate + build + contrôle
|
||||
du contenu). **Monter `version`** à chaque livraison. L'utilisateur installe lui-même le zip.
|
||||
- Release : `.\tools\New-GiteaRelease.ps1 [-DryRun]` — Gitea `https://a2msystemes-git.duckdns.org`, dépôt
|
||||
`ange/slice_wrap_addon` (déduit de `origin`), jeton `GITEA_TOKEN`. Exige un dépôt propre et poussé ; crée le tag
|
||||
`v<version>`, la release (notes = entrée de l'Historique ci-dessous) et joint le zip. Publication = action
|
||||
externe : ne la lancer qu'à la demande de l'utilisateur.
|
||||
- `.gitignore` : `__pycache__/`, `dist/`, `*.zip`, rendus de test. Le manifeste exclut aussi `tools/`, `dist/`, `.git/`.
|
||||
**À lancer avant chaque release** (la chaîne a2m ne lance pas encore les tests de l'addon).
|
||||
- Construction et publication : chaîne d'outils **a2m** (repo `ange/apc-toolchain`, remplace les anciens
|
||||
`tools/Build-Package.ps1` et `tools/New-GiteaRelease.ps1`, retirés le 2026-10-20) :
|
||||
`a2m validate --load` (manifest validé et addon chargé dans Blender 5.1 et 5.2, profil temporaire),
|
||||
`a2m build` → `dist\slice_wrap-<version>.zip`, `a2m release [patch|minor|major]` (version du manifest, CHANGELOG,
|
||||
commit, tag `v<version>`, release Gitea avec le zip et `publication.json`), `a2m release --dev` (pré-release de
|
||||
test, réservée aux membres). Publication = action externe : ne la lancer qu'à la demande de l'utilisateur.
|
||||
- `.gitignore` : `__pycache__/`, `dist/`, `*.zip`, rendus de test.
|
||||
|
||||
## Historique
|
||||
- 1.0.0 Envelope / Regenerate / Wrap Setup / Freeze (Reshape) / Despike.
|
||||
- 1.1.0 Bouton unique « Slice Wrap » + Despike After ; Steps en sous-panneau ; Despike : Distance, Strength,
|
||||
Iterations, filtres par groupes de sommets ; réparation des ratés au Freeze.
|
||||
- 1.2.0 Analyze (carte de détail, tags, direction des plis), Show Detail / Shapes, Protect Detail.
|
||||
- 1.3.0 Suffix (`_slicewrapped`), numérotation automatique (plus d'écrasement), collection optionnelle.
|
||||
- 1.4.0 Réglage Target supprimé (objet sélectionné uniquement) ; confirmation avant les calculs longs, barre de
|
||||
progression (barre d'état + panneau), Blender non bloqué, Échap annule sans rien laisser.
|
||||
Voir [CHANGELOG.fr.md](CHANGELOG.fr.md) (une entrée par version ; les changements à venir dans « Non publié »).
|
||||
|
||||
## Mesures de référence (Blender 5.2.1, tête Pixal3D brute 11,8 M faces)
|
||||
Enveloppe 70 k faces en 11 s ; chaîne complète ~1,5–2 min ; ~93 k ratés réparés au Freeze ; Despike filtré
|
||||
« Oreilles » 683 corrections vs 4 749 global ; Analyze 9 s (Flat 86 %, Ridge 5 %, Bulge 3 %, Fold 3 %, Hollow 2 %,
|
||||
Saddle 1 % — hélice des oreilles et lèvres en Ridge, paupières et commissures en Fold).
|
||||
|
||||
## À faire : dépôt d'extensions Blender sur a2msystemes.org (prévu, 2026-10-17)
|
||||
## Dépôt d'extensions Blender sur a2msystemes.org (idée du 2026-10-17, prise en charge par APC)
|
||||
But : les addons de l'utilisateur (Slice Wrap, Slice Retopo, suivants) installables et mis à jour via
|
||||
*Preferences > Get Extensions > Repositories > Add Remote Repository* (`https://a2msystemes.org/blender/index.json`,
|
||||
dossier à confirmer), au lieu d'*Install from Disk*.
|
||||
- **Prérequis en cours (autre projet)** : mise en ligne du site par git. Site réel `https://a2msystemes.org`
|
||||
(une page « en construction »), code `https://a2msystemes-git.duckdns.org/ange/site-a2msystemes-org`. Reprendre ici
|
||||
une fois ce déploiement en place.
|
||||
- **Principe** : dossier statique HTTPS = `index.json` + zips (+ `index.html`), généré par
|
||||
`blender --command extension server-generate --repo-dir=<dossier> --html`. Une seule version par addon
|
||||
(id unique) ; Blender détecte les mises à jour au démarrage (« Check for Updates on Startup ») d'après `version`
|
||||
du manifeste, l'installation reste un clic (*Update*).
|
||||
- **À écrire** : `tools/Publish-ExtensionRepo.ps1` (ou étape de `New-GiteaRelease.ps1`) : Build-Package → copier
|
||||
le zip dans le dossier `blender/` du dépôt du site (retirer l'ancienne version du même id) → `server-generate` →
|
||||
commit + push du dépôt du site (déploiement git).
|
||||
- **Questions encore ouvertes** : dossier exact sur le site ; dépôt public (probable, GPL) ou privé (jeton
|
||||
*Requires Access Token* + contrôle côté serveur) ; liste des addons (Slice Retopo doit avoir un
|
||||
`blender_manifest.toml`).
|
||||
*Preferences > Get Extensions > Repositories > Add Remote Repository*, au lieu d'*Install from Disk*.
|
||||
Cette note est à l'origine du projet **APC** (*A2M Publication Contract*) : le dépôt n'est plus à écrire ici.
|
||||
- **Publication** : `a2m release` (chaîne d'outils `ange/apc-toolchain`) joint à chaque release Gitea le zip et un
|
||||
`publication.json` (contrat `ange/apc-spec`) ; le script de déploiement du site (`ange/site-a2msystemes-org`)
|
||||
en fabrique `blender-addons/index.json` et les pages du projet. Adresse du dépôt et pages : voir le site.
|
||||
- **À rappeler à l'utilisateur** : les addons déjà installés par *Install from Disk* (dépôt `user_default`) ne
|
||||
reçoivent pas les mises à jour → les désinstaller puis réinstaller une fois depuis le nouveau dépôt.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Slice Wrap — add-on Blender (4.2 → 5.x)
|
||||
# Slice Wrap — add-on Blender (5.1 → 5.x)
|
||||
|
||||
Transforme un maillage **troué, à doubles parois ou bruité** (scan, génération IA type Pixal3D / Trellis)
|
||||
en une **surface propre, fermée et détaillée**, prête à sculpter. Aucune dépendance : numpy seulement
|
||||
@@ -105,14 +105,14 @@ Les couleurs portent le suffixe `_Color` car groupes de sommets et attributs par
|
||||
- Après Freeze, l'objet garde une **base légère** + niveaux Multires : sculptez, ou bakez les détails.
|
||||
|
||||
## Installation
|
||||
- **Paquet** : `slice_wrap-1.4.0.zip` (page *Releases* du dépôt Gitea, ou `dist\` après construction) →
|
||||
- **Depuis le dépôt d'extensions d'a2msystemes.org** (à venir) : les mises à jour seront proposées directement dans
|
||||
Blender. Voir https://a2msystemes.org/projets/slice_wrap.
|
||||
- **Paquet** : `slice_wrap-<version>.zip` (page *Releases* du dépôt Gitea, ou `dist\` après construction) →
|
||||
*Edit > Preferences > Get Extensions > ⌄ > Install from Disk…*
|
||||
- **Construire le paquet** : `.\tools\Build-Package.ps1` (→ `dist\slice_wrap-<version>.zip` ; `-RunTests` lance
|
||||
d'abord les tests ; Blender trouvé automatiquement, ou `-Blender <chemin>` / variable `BLENDER_EXE`).
|
||||
- **Publier une release Gitea** : monter `version` dans `blender_manifest.toml`, commiter et pousser, puis
|
||||
`.\tools\New-GiteaRelease.ps1` (tests, paquet, tag `v<version>`, release avec le zip en pièce jointe).
|
||||
Jeton : variable `GITEA_TOKEN` (sinon demandé). `-DryRun` montre ce qui serait fait sans rien publier ;
|
||||
`-Prerelease`, `-Draft`, `-Notes "…"` (par défaut : l'entrée de la version dans l'historique).
|
||||
- **Construire et publier** : chaîne d'outils `a2m` (repo `ange/apc-toolchain`) — `a2m validate --load`,
|
||||
`a2m build` (→ `dist\slice_wrap-<version>.zip`), `a2m release [patch|minor|major]` (version, CHANGELOG, tag,
|
||||
release Gitea avec le zip et `publication.json`), `a2m release --dev` (pré-release de test).
|
||||
Historique des versions : [CHANGELOG.fr.md](CHANGELOG.fr.md).
|
||||
- **Développement** : copier / lier ce dossier dans
|
||||
`%APPDATA%\Blender Foundation\Blender\<version>\extensions\user_default\slice_wrap`.
|
||||
|
||||
|
||||
@@ -4,12 +4,13 @@ id = "slice_wrap"
|
||||
version = "1.4.0"
|
||||
name = "Slice Wrap"
|
||||
tagline = "Closed envelope of holey meshes, then wrap, freeze and despike"
|
||||
maintainer = "a-mma"
|
||||
maintainer = "Ange-Marie MAURIN"
|
||||
type = "add-on"
|
||||
website = "https://a2msystemes.org/projets/slice_wrap"
|
||||
|
||||
tags = ["Mesh", "Modeling", "Sculpt"]
|
||||
|
||||
blender_version_min = "4.2.0"
|
||||
blender_version_min = "5.1.0"
|
||||
|
||||
license = [
|
||||
"SPDX:GPL-3.0-or-later",
|
||||
@@ -19,11 +20,11 @@ license = [
|
||||
paths_exclude_pattern = [
|
||||
"__pycache__/",
|
||||
"/*.zip",
|
||||
"/.a2m/",
|
||||
"/.claude/",
|
||||
"/.git/",
|
||||
"/.gitignore",
|
||||
"/CLAUDE.md",
|
||||
"/tests/",
|
||||
"/tools/",
|
||||
"/dist/",
|
||||
]
|
||||
@@ -1,78 +0,0 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Construit le paquet d'extension Blender de Slice Wrap dans dist\.
|
||||
|
||||
.DESCRIPTION
|
||||
Valide blender_manifest.toml, construit slice_wrap-<version>.zip avec « blender --command extension build »
|
||||
(exclusions : section [build] du manifeste), puis vérifie que le zip ne contient ni tests, ni .claude, ni
|
||||
CLAUDE.md, ni .git. Renvoie le chemin du zip.
|
||||
|
||||
.EXAMPLE
|
||||
.\tools\Build-Package.ps1
|
||||
.EXAMPLE
|
||||
.\tools\Build-Package.ps1 -RunTests -Blender "C:\Program Files\Blender Foundation\Blender 5.2\blender.exe"
|
||||
#>
|
||||
param(
|
||||
# Exécutable Blender (défaut : variable BLENDER_EXE, sinon le Blender 5.x le plus récent installé)
|
||||
[string]$Blender = $env:BLENDER_EXE,
|
||||
# Dossier de sortie
|
||||
[string]$OutDir = (Join-Path (Split-Path $PSScriptRoot -Parent) 'dist'),
|
||||
# Lance d'abord la suite de tests en arrière-plan (exige « RESULTAT : TOUT OK »)
|
||||
[switch]$RunTests
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$root = Split-Path $PSScriptRoot -Parent
|
||||
|
||||
function Find-Blender {
|
||||
$base = 'C:\Program Files\Blender Foundation'
|
||||
$exe = Get-ChildItem $base -Directory -Filter 'Blender *' -ErrorAction SilentlyContinue |
|
||||
Sort-Object { [version]($_.Name -replace '^Blender\s+', '') } -Descending |
|
||||
ForEach-Object { Join-Path $_.FullName 'blender.exe' } |
|
||||
Where-Object { Test-Path $_ } |
|
||||
Select-Object -First 1
|
||||
if (-not $exe) { throw "Blender introuvable : passez -Blender <chemin\blender.exe> ou définissez BLENDER_EXE" }
|
||||
return $exe
|
||||
}
|
||||
|
||||
if (-not $Blender) { $Blender = Find-Blender }
|
||||
if (-not (Test-Path $Blender)) { throw "Blender introuvable : $Blender" }
|
||||
|
||||
$manifest = Get-Content (Join-Path $root 'blender_manifest.toml') -Raw
|
||||
if ($manifest -notmatch '(?m)^\s*version\s*=\s*"([^"]+)"') { throw "version introuvable dans blender_manifest.toml" }
|
||||
$version = $Matches[1]
|
||||
if ($manifest -notmatch '(?m)^\s*id\s*=\s*"([^"]+)"') { throw "id introuvable dans blender_manifest.toml" }
|
||||
$id = $Matches[1]
|
||||
Write-Host "Slice Wrap $version — $Blender" -ForegroundColor Cyan
|
||||
|
||||
if ($RunTests) {
|
||||
$testOut = Join-Path ([IO.Path]::GetTempPath()) 'slice_wrap_tests'
|
||||
New-Item -ItemType Directory -Force $testOut | Out-Null
|
||||
Write-Host "Tests (~1 min)…"
|
||||
$log = & $Blender -b --factory-startup -P (Join-Path $root 'tests\run_tests.py') -- $testOut 2>&1
|
||||
$log | Where-Object { $_ -match '^(OK|FAIL|RESULTAT)' } | ForEach-Object { Write-Host $_ }
|
||||
if (-not ($log -match 'RESULTAT : TOUT OK')) { throw "Les tests ont échoué : paquet non construit" }
|
||||
}
|
||||
|
||||
Write-Host "Validation du manifeste…"
|
||||
$out = & $Blender --command extension validate $root 2>&1
|
||||
if ($LASTEXITCODE -ne 0) { $out | Write-Host; throw "Manifeste invalide" }
|
||||
|
||||
New-Item -ItemType Directory -Force $OutDir | Out-Null
|
||||
$zip = Join-Path $OutDir "$id-$version.zip"
|
||||
if (Test-Path $zip) { Remove-Item $zip -Force }
|
||||
|
||||
Write-Host "Construction…"
|
||||
$out = & $Blender --command extension build --source-dir $root --output-dir $OutDir 2>&1
|
||||
if ($LASTEXITCODE -ne 0 -or -not (Test-Path $zip)) { $out | Write-Host; throw "Échec de la construction" }
|
||||
|
||||
# Contrôle du contenu : rien de privé ni de développement dans le paquet
|
||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||
$archive = [IO.Compression.ZipFile]::OpenRead($zip)
|
||||
try { $entries = $archive.Entries | ForEach-Object FullName } finally { $archive.Dispose() }
|
||||
$bad = $entries | Where-Object { $_ -match '^(tests|tools|dist|\.claude|\.git)/|^CLAUDE\.md$|__pycache__|\.zip$' }
|
||||
if ($bad) { throw "Fichiers indésirables dans le paquet : $($bad -join ', ')" }
|
||||
|
||||
Write-Host "Paquet : $zip ($([math]::Round((Get-Item $zip).Length / 1KB)) Ko)" -ForegroundColor Green
|
||||
$entries | ForEach-Object { Write-Host " $_" }
|
||||
return $zip
|
||||
@@ -1,172 +0,0 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Publie une release de Slice Wrap sur Gitea : tag v<version>, release et paquet zip en pièce jointe.
|
||||
|
||||
.DESCRIPTION
|
||||
1. Lit la version dans blender_manifest.toml.
|
||||
2. Vérifie que le dépôt est propre (tout est commité) et que HEAD est poussé sur origin.
|
||||
3. Construit le paquet (tools\Build-Package.ps1, tests compris sauf -SkipTests).
|
||||
4. Crée le tag annoté v<version> sur HEAD et le pousse (s'il existe déjà, il doit pointer sur HEAD).
|
||||
5. Crée la release via l'API Gitea (ou réutilise celle du tag) et y joint slice_wrap-<version>.zip
|
||||
(une pièce jointe du même nom est remplacée).
|
||||
Notes de version : -Notes, sinon l'entrée de la version dans la section « Historique » de CLAUDE.md.
|
||||
|
||||
Jeton (Gitea > Paramètres > Applications, portée « repository : lecture et écriture »), cherché dans l'ordre :
|
||||
1. variable d'environnement GITEA_TOKEN ;
|
||||
2. %APPDATA%\Gitea\token.xml, chiffré par Windows (DPAPI) : seul votre compte, sur ce PC, peut le lire.
|
||||
Pour le créer : Read-Host "Jeton Gitea" -AsSecureString | Export-Clixml "$env:APPDATA\Gitea\token.xml"
|
||||
3. sinon il est demandé (saisie masquée), avec proposition de l'enregistrer dans ce fichier.
|
||||
|
||||
.EXAMPLE
|
||||
.\tools\New-GiteaRelease.ps1 -DryRun # montre ce qui serait fait, ne publie rien
|
||||
.EXAMPLE
|
||||
$env:GITEA_TOKEN = '...'; .\tools\New-GiteaRelease.ps1
|
||||
.EXAMPLE
|
||||
.\tools\New-GiteaRelease.ps1 -Prerelease -Notes "Version de test"
|
||||
#>
|
||||
param(
|
||||
[string]$Server = 'https://a2msystemes-git.duckdns.org',
|
||||
# Propriétaire et dépôt : déduits de l'URL du remote « origin » si absents
|
||||
[string]$Owner,
|
||||
[string]$Repo,
|
||||
[string]$Notes,
|
||||
[switch]$Prerelease,
|
||||
[switch]$Draft,
|
||||
[switch]$SkipTests,
|
||||
# Publier même si le dépôt contient des modifications non commitées
|
||||
[switch]$AllowDirty,
|
||||
[switch]$DryRun,
|
||||
[string]$Blender = $env:BLENDER_EXE
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$root = Split-Path $PSScriptRoot -Parent
|
||||
|
||||
function Invoke-Git {
|
||||
$out = & git -C $root @args 2>&1
|
||||
if ($LASTEXITCODE -ne 0) { throw "git $($args -join ' ') : $out" }
|
||||
return $out
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------ version, dépôt, notes
|
||||
$manifest = Get-Content (Join-Path $root 'blender_manifest.toml') -Raw
|
||||
if ($manifest -notmatch '(?m)^\s*version\s*=\s*"([^"]+)"') { throw "version introuvable dans blender_manifest.toml" }
|
||||
$version = $Matches[1]
|
||||
$tag = "v$version"
|
||||
|
||||
if (-not $Owner -or -not $Repo) {
|
||||
$url = (& git -C $root remote get-url origin 2>$null)
|
||||
if (-not $url) { throw "Aucun remote « origin » : ajoutez-le (git remote add origin $Server/<owner>/<repo>.git) ou passez -Owner / -Repo" }
|
||||
if ($url -notmatch '[:/]([^/:]+)/([^/]+?)(\.git)?/?$') { throw "URL du remote non reconnue : $url" }
|
||||
if (-not $Owner) { $Owner = $Matches[1] }
|
||||
if (-not $Repo) { $Repo = $Matches[2] }
|
||||
}
|
||||
|
||||
if (-not $Notes) {
|
||||
# Entrée « - <version> … » de la section Historique de CLAUDE.md (lignes de continuation indentées comprises)
|
||||
$claude = Join-Path $root 'CLAUDE.md'
|
||||
if (Test-Path $claude) {
|
||||
$lines = Get-Content $claude -Encoding utf8
|
||||
$i = [array]::FindIndex($lines, [Predicate[string]] { param($l) $l -match "^- $([regex]::Escape($version))\b" })
|
||||
if ($i -ge 0) {
|
||||
$entry = @($lines[$i] -replace "^- $([regex]::Escape($version))\s*", '')
|
||||
for ($j = $i + 1; $j -lt $lines.Count -and $lines[$j] -match '^\s{2,}\S'; $j++) { $entry += $lines[$j].Trim() }
|
||||
$Notes = $entry -join ' '
|
||||
}
|
||||
}
|
||||
if (-not $Notes) { $Notes = "Slice Wrap $version" }
|
||||
}
|
||||
$body = @"
|
||||
$Notes
|
||||
|
||||
**Installation** : Blender 4.2+ > *Edit > Preferences > Get Extensions > ⌄ > Install from Disk…* > ``slice_wrap-$version.zip``
|
||||
"@
|
||||
|
||||
# ------------------------------------------------------------------ état du dépôt
|
||||
& git -C $root rev-parse --verify --quiet HEAD *> $null
|
||||
if ($LASTEXITCODE -ne 0) { throw "Le dépôt n'a encore aucun commit : commitez et poussez avant de publier une release." }
|
||||
$dirty = Invoke-Git status --porcelain
|
||||
if ($dirty -and -not $AllowDirty) { throw "Modifications non commitées :`n$($dirty -join "`n")`nCommitez-les (ou -AllowDirty)." }
|
||||
$head = (Invoke-Git rev-parse HEAD).Trim()
|
||||
$branch = (Invoke-Git rev-parse --abbrev-ref HEAD).Trim()
|
||||
& git -C $root fetch origin --tags --quiet 2>$null
|
||||
$remoteHead = (& git -C $root rev-parse "origin/$branch" 2>$null)
|
||||
if ($remoteHead -ne $head -and -not $DryRun) { throw "HEAD ($($head.Substring(0,8))) n'est pas poussé sur origin/$branch : faites git push d'abord." }
|
||||
$tagCommit = (& git -C $root rev-list -n 1 $tag 2>$null)
|
||||
if ($tagCommit -and $tagCommit.Trim() -ne $head) { throw "Le tag $tag existe déjà sur un autre commit ($($tagCommit.Substring(0,8))) : montez la version dans blender_manifest.toml." }
|
||||
|
||||
Write-Host "Release $tag de $Owner/$Repo sur $Server (commit $($head.Substring(0,8)), branche $branch)" -ForegroundColor Cyan
|
||||
Write-Host "Notes : $Notes"
|
||||
|
||||
# ------------------------------------------------------------------ paquet
|
||||
$buildArgs = @{}
|
||||
if ($Blender) { $buildArgs.Blender = $Blender }
|
||||
if (-not $SkipTests) { $buildArgs.RunTests = $true }
|
||||
$zip = & (Join-Path $PSScriptRoot 'Build-Package.ps1') @buildArgs | Select-Object -Last 1
|
||||
$zipName = Split-Path $zip -Leaf
|
||||
|
||||
if ($DryRun) {
|
||||
Write-Host "`n[DryRun] Rien n'est publié. Seraient faits :" -ForegroundColor Yellow
|
||||
if (-not $tagCommit) { Write-Host " git tag -a $tag $($head.Substring(0,8)) ; git push origin $tag" }
|
||||
Write-Host " POST $Server/api/v1/repos/$Owner/$Repo/releases (tag $tag$(if ($Prerelease) {', préversion'})$(if ($Draft) {', brouillon'}))"
|
||||
Write-Host " pièce jointe $zipName"
|
||||
return
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------ jeton
|
||||
# Ordre : variable GITEA_TOKEN, puis fichier chiffré par Windows (DPAPI), sinon saisie masquée
|
||||
$tokenFile = Join-Path $env:APPDATA 'Gitea\token.xml'
|
||||
$token = $env:GITEA_TOKEN
|
||||
if (-not $token -and (Test-Path $tokenFile)) {
|
||||
$token = [Net.NetworkCredential]::new('', (Import-Clixml $tokenFile)).Password
|
||||
}
|
||||
if (-not $token) {
|
||||
$sec = Read-Host "Jeton Gitea (portée repository, lecture/écriture)" -AsSecureString
|
||||
$token = [Net.NetworkCredential]::new('', $sec).Password
|
||||
if ($token -and (Read-Host "L'enregistrer chiffré dans $tokenFile ? (o/N)") -match '^[oOyY]') {
|
||||
New-Item -ItemType Directory -Force (Split-Path $tokenFile) | Out-Null
|
||||
$sec | Export-Clixml $tokenFile
|
||||
Write-Host "Jeton enregistré (lisible seulement par votre compte Windows sur ce PC)"
|
||||
}
|
||||
}
|
||||
if (-not $token) { throw "Jeton Gitea manquant" }
|
||||
$headers = @{ Authorization = "token $token"; Accept = 'application/json' }
|
||||
$api = "$Server/api/v1/repos/$Owner/$Repo"
|
||||
|
||||
# ------------------------------------------------------------------ tag
|
||||
if (-not $tagCommit) {
|
||||
Invoke-Git tag -a $tag -m "Slice Wrap $version" | Out-Null
|
||||
Invoke-Git push origin $tag | Out-Null
|
||||
Write-Host "Tag $tag créé et poussé"
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------ release
|
||||
$release = $null
|
||||
try {
|
||||
$release = Invoke-RestMethod -Method Get -Uri "$api/releases/tags/$tag" -Headers $headers
|
||||
Write-Host "Release $tag existante (id $($release.id)) : réutilisée"
|
||||
} catch {
|
||||
if ($_.Exception.Response.StatusCode.value__ -ne 404) { throw }
|
||||
}
|
||||
if (-not $release) {
|
||||
$payload = @{
|
||||
tag_name = $tag
|
||||
name = "Slice Wrap $version"
|
||||
body = $body
|
||||
draft = [bool]$Draft
|
||||
prerelease = [bool]$Prerelease
|
||||
} | ConvertTo-Json
|
||||
$release = Invoke-RestMethod -Method Post -Uri "$api/releases" -Headers $headers `
|
||||
-ContentType 'application/json; charset=utf-8' -Body ([Text.Encoding]::UTF8.GetBytes($payload))
|
||||
Write-Host "Release créée (id $($release.id))"
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------ pièce jointe (remplacée si elle existe)
|
||||
foreach ($a in @($release.assets) | Where-Object { $_ -and $_.name -eq $zipName }) {
|
||||
Invoke-RestMethod -Method Delete -Uri "$api/releases/$($release.id)/assets/$($a.id)" -Headers $headers | Out-Null
|
||||
Write-Host "Ancienne pièce jointe $zipName supprimée"
|
||||
}
|
||||
Invoke-RestMethod -Method Post -Uri "$api/releases/$($release.id)/assets?name=$zipName" -Headers $headers `
|
||||
-Form @{ attachment = Get-Item $zip } | Out-Null
|
||||
|
||||
Write-Host "Publié : $($release.html_url)" -ForegroundColor Green
|
||||
Reference in new issue
Block a user