diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8d04241 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +# Local dev compose overrides (personal / per-machine) +docker-compose.override.yml + +# Python +__pycache__/ +*.py[cod] +.pytest_cache/ +.mypy_cache/ +.ruff_cache/ +*.egg-info/ +.venv/ +venv/ + +# Local data / build artifacts +/data/ +imptune_data/ +*.intunewin diff --git a/README.md b/README.md index 0832718..d38d103 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,54 @@ # ImpTune +Build printer deploy packages (`.intunewin` for Intune, `.zip` for NinjaRMM) from Windows driver ZIPs via a web UI. +## Run + +### Local development + +```bash +docker compose up +``` + +`docker-compose.override.yml` is merged automatically: it mounts your working +copy into the container and runs uvicorn with `--reload`, so code edits are +picked up live. The override is gitignored (personal / per-machine). + +### Run the published image + +To run the image from the registry instead of building locally, skip the +override: + +```bash +docker compose -f docker-compose.yml pull +docker compose -f docker-compose.yml up +``` + +Then open http://localhost:8000 + +## Publishing + +`scripts/publish.ps1` builds the image and pushes it to the Gitea container +registry at `git.azuze.fr/kawa/imptune`. + +```powershell +# build + push : and :latest (prompts for a Gitea token) +./scripts/publish.ps1 + +# tag an explicit version +./scripts/publish.ps1 -Tag v1.2.0 +``` + +Use a Gitea access token (Settings → Applications, with package read/write +scope) as the password. For non-interactive runs set `GITEA_USER` / +`GITEA_TOKEN` env vars. Run `Get-Help ./scripts/publish.ps1 -Detailed` for all +parameters (`-Registry`, `-Owner`, `-Image`, `-NoBuild`, `-SkipLogin`, …). + +## Environment variables + +Set these under `environment:` in `docker-compose.yml`. + +| Variable | Default | Purpose | +|------------|---------|--------------------------------------------------| +| `DATA_DIR` | `/data` | Storage root for the SQLite DB, drivers and icons. Should map to the `imptune_data` volume. | +| `PORT` | `8000` | Port the server listens on inside the container. | diff --git a/docker-compose.yml b/docker-compose.yml index 9d07aa8..a5f2316 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,14 +1,17 @@ services: imptune: + # Pull the published image by default (docker compose pull / up). + # `build` is kept so `docker compose build` still produces a correctly + # tagged local image; scripts/publish.ps1 pushes it to the registry. + image: git.azuze.fr/kawa/imptune:latest build: . ports: - "8000:8000" volumes: - imptune_data:/data - - ./imptune:/app/imptune restart: unless-stopped environment: - DATA_DIR=/data volumes: - imptune_data: + imptune_data: \ No newline at end of file diff --git a/scripts/publish.ps1 b/scripts/publish.ps1 new file mode 100644 index 0000000..dc9faf5 --- /dev/null +++ b/scripts/publish.ps1 @@ -0,0 +1,128 @@ +#requires -Version 5.1 +<# +.SYNOPSIS + Build the ImpTune container locally and push it to the Gitea container registry. + +.DESCRIPTION + Builds the Docker image from the repo Dockerfile, tags it for the Gitea + registry (git.arescom.fr by default), logs in, and pushes one or more tags. + + Login credentials are read, in order of precedence: + 1. -Username / -Password parameters + 2. $env:GITEA_USER / $env:GITEA_TOKEN + 3. Interactive prompt (token is read as a SecureString) + + Use a Gitea access token (Settings -> Applications) with package read/write + scope as the password — not your account password. + +.EXAMPLE + ./scripts/publish.ps1 + Build and push :latest plus the short git SHA. + +.EXAMPLE + ./scripts/publish.ps1 -Tag v1.2.0 + Build and push :v1.2.0 (and :latest unless -NoLatest). + +.EXAMPLE + $env:GITEA_USER = "kawa"; $env:GITEA_TOKEN = "xxxx"; ./scripts/publish.ps1 -SkipLogin:$false +#> +[CmdletBinding()] +param( + # Registry host (Gitea instance). + [string]$Registry = "git.azuze.fr", + + # Owner / organisation that holds the package. + [string]$Owner = "kawa", + + # Image name. + [string]$Image = "imptune", + + # Primary tag. Defaults to the short git SHA. + [string]$Tag, + + # Also push :latest. On by default. + [switch]$NoLatest, + + # Registry username. Falls back to $env:GITEA_USER then a prompt. + [string]$Username, + + # Registry token/password. Falls back to $env:GITEA_TOKEN then a prompt. + [string]$Password, + + # Skip the build step and only push existing local tags. + [switch]$NoBuild, + + # Skip docker login (assume already authenticated). + [switch]$SkipLogin +) + +$ErrorActionPreference = "Stop" + +function Invoke-Checked { + param([Parameter(Mandatory)][string]$Exe, [Parameter(Mandatory)][string[]]$Args) + Write-Host " > $Exe $($Args -join ' ')" -ForegroundColor DarkGray + & $Exe @Args + if ($LASTEXITCODE -ne 0) { + throw "'$Exe $($Args -join ' ')' failed with exit code $LASTEXITCODE." + } +} + +# Resolve repo root (parent of this script's folder) so the script works from anywhere. +$repoRoot = Split-Path -Parent $PSScriptRoot +Push-Location $repoRoot +try { + # --- Tag resolution ------------------------------------------------------- + if (-not $Tag) { + try { $Tag = (git rev-parse --short HEAD).Trim() } catch { } + if (-not $Tag) { $Tag = "latest" } + } + + $base = "$Registry/$Owner/$Image" + $tags = @("$base`:$Tag") + if (-not $NoLatest -and $Tag -ne "latest") { $tags += "$base`:latest" } + + Write-Host "ImpTune container publish" -ForegroundColor Cyan + Write-Host " registry : $Registry" + Write-Host " image : $base" + Write-Host " tags : $($tags -join ', ')" + Write-Host "" + + # --- Build ---------------------------------------------------------------- + if (-not $NoBuild) { + Write-Host "Building image..." -ForegroundColor Cyan + $buildArgs = @("build") + foreach ($t in $tags) { $buildArgs += @("-t", $t) } + $buildArgs += "." + Invoke-Checked docker $buildArgs + Write-Host "" + } + + # --- Login ---------------------------------------------------------------- + if (-not $SkipLogin) { + if (-not $Username) { $Username = $env:GITEA_USER } + if (-not $Username) { $Username = Read-Host "Gitea username for $Registry" } + + if (-not $Password) { $Password = $env:GITEA_TOKEN } + if (-not $Password) { + $secure = Read-Host "Gitea token/password for $Username" -AsSecureString + $Password = [System.Net.NetworkCredential]::new("", $secure).Password + } + + Write-Host "Logging in to $Registry as $Username..." -ForegroundColor Cyan + # Pass the token via stdin so it never lands in process args or history. + $Password | docker login $Registry --username $Username --password-stdin + if ($LASTEXITCODE -ne 0) { throw "docker login failed (exit $LASTEXITCODE)." } + Write-Host "" + } + + # --- Push ----------------------------------------------------------------- + Write-Host "Pushing..." -ForegroundColor Cyan + foreach ($t in $tags) { Invoke-Checked docker @("push", $t) } + + Write-Host "" + Write-Host "Done. Pushed:" -ForegroundColor Green + foreach ($t in $tags) { Write-Host " $t" -ForegroundColor Green } +} +finally { + Pop-Location +}