Rename product to dockmv (container, image, module, env vars)

Container/image/service name, Go module path, CLI binary name, and
DOCKER_MIGRATE_* env vars still used the old working name; the project
is branded DockMV everywhere else (README, logo, Gitea repo).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-11 13:56:26 +02:00
co-authored by Claude Sonnet 5
parent 832af4aaae
commit 34e18987a0
32 changed files with 113 additions and 109 deletions
+2 -2
View File
@@ -1,8 +1,8 @@
.git .git
.gitignore .gitignore
dist/ dist/
docker-migrate dockmv
docker-migrate.exe dockmv.exe
web/node_modules web/node_modules
internal/webui/dist internal/webui/dist
*.test *.test
+2 -2
View File
@@ -1,6 +1,6 @@
# Binaries # Binaries
/docker-migrate /dockmv
/docker-migrate.exe /dockmv.exe
/dist/ /dist/
*.test *.test
*.test.exe *.test.exe
+4 -4
View File
@@ -18,22 +18,22 @@ COPY --from=ui /src/internal/webui/dist ./internal/webui/dist
# artifact be copied onto a bare-metal host. # artifact be copied onto a bare-metal host.
RUN CGO_ENABLED=0 go build -trimpath \ RUN CGO_ENABLED=0 go build -trimpath \
-ldflags "-s -w -X main.version=${VERSION}" \ -ldflags "-s -w -X main.version=${VERSION}" \
-o /out/docker-migrate . -o /out/dockmv .
FROM alpine:3.22 FROM alpine:3.22
RUN apk add --no-cache ca-certificates tzdata && \ RUN apk add --no-cache ca-certificates tzdata && \
adduser -D -u 10001 migrate adduser -D -u 10001 migrate
COPY --from=build /out/docker-migrate /usr/local/bin/docker-migrate COPY --from=build /out/dockmv /usr/local/bin/dockmv
# The container talks to the Docker socket mounted from the host, which is # The container talks to the Docker socket mounted from the host, which is
# owned by root:docker. It therefore runs as root by default; set --user to # owned by root:docker. It therefore runs as root by default; set --user to
# override when the socket permissions on your host allow it. # override when the socket permissions on your host allow it.
ENV DOCKER_MIGRATE_DATA=/data ENV DOCKMV_DATA=/data
VOLUME ["/data"] VOLUME ["/data"]
EXPOSE 8080 EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s \ HEALTHCHECK --interval=30s --timeout=5s --start-period=5s \
CMD wget -qO- http://127.0.0.1:8080/api/health >/dev/null || exit 1 CMD wget -qO- http://127.0.0.1:8080/api/health >/dev/null || exit 1
ENTRYPOINT ["docker-migrate"] ENTRYPOINT ["dockmv"]
CMD ["serve", "--addr", "0.0.0.0:8080"] CMD ["serve", "--addr", "0.0.0.0:8080"]
+2 -2
View File
@@ -1,6 +1,6 @@
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev) VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev)
LDFLAGS := -s -w -X main.version=$(VERSION) LDFLAGS := -s -w -X main.version=$(VERSION)
BIN := docker-migrate BIN := dockmv
OUT := dist OUT := dist
# PowerShell 7+. The publish path lives in scripts/*.ps1 because uploading a # PowerShell 7+. The publish path lives in scripts/*.ps1 because uploading a
@@ -47,7 +47,7 @@ fmt:
cd web && npx tsc -b --noEmit cd web && npx tsc -b --noEmit
docker: docker:
docker build --build-arg VERSION=$(VERSION) -t docker-migrate:$(VERSION) -t docker-migrate:latest . docker build --build-arg VERSION=$(VERSION) -t dockmv:$(VERSION) -t dockmv:latest .
release: ui release: ui
@mkdir -p $(OUT) @mkdir -p $(OUT)
+9 -9
View File
@@ -25,9 +25,9 @@ CLI, `bash` and `gzip`.
On the **source** host: On the **source** host:
```bash ```bash
git clone <this repo> docker-migrate && cd docker-migrate git clone <this repo> dockmv && cd dockmv
docker compose up -d --build docker compose up -d --build
docker compose logs docker-migrate # prints the URL, including the access token docker compose logs dockmv # prints the URL, including the access token
``` ```
Then open the printed URL. It binds to `127.0.0.1` only; reach it from your laptop with a tunnel: Then open the printed URL. It binds to `127.0.0.1` only; reach it from your laptop with a tunnel:
@@ -42,16 +42,16 @@ The binary is fully static and embeds the web UI, so there is nothing to install
```bash ```bash
make build # needs Go 1.25+ and Node 20+ ... or just `go build .` if you skip the UI rebuild make build # needs Go 1.25+ and Node 20+ ... or just `go build .` if you skip the UI rebuild
./docker-migrate serve ./dockmv serve
``` ```
Prebuilt for several platforms: Prebuilt for several platforms:
```bash ```bash
make release # dist/docker-migrate-linux-amd64, -linux-arm64, -darwin-arm64, -windows-amd64 make release # dist/dockmv-linux-amd64, -linux-arm64, -darwin-arm64, -windows-amd64
``` ```
`docker-migrate` needs access to the Docker socket on the source host, so run it as a user in the `dockmv` needs access to the Docker socket on the source host, so run it as a user in the
`docker` group (or as root). `docker` group (or as root).
--- ---
@@ -206,9 +206,9 @@ free disk space and architecture.
## Command line ## Command line
``` ```
docker-migrate [serve] [flags] start the web interface (default) dockmv [serve] [flags] start the web interface (default)
docker-migrate inspect [flags] print the source inventory as JSON dockmv inspect [flags] print the source inventory as JSON
docker-migrate version dockmv version
``` ```
`serve` flags: `serve` flags:
@@ -225,7 +225,7 @@ docker-migrate version
`inspect` is handy for scripting and for reporting bugs: `inspect` is handy for scripting and for reporting bugs:
```bash ```bash
docker-migrate inspect --sizes | jq '.containers[] | {name, image, mounts}' dockmv inspect --sizes | jq '.containers[] | {name, image, mounts}'
``` ```
--- ---
+6 -6
View File
@@ -1,20 +1,20 @@
# docker-migrate, running on the SOURCE host. # dockmv, running on the SOURCE host.
# #
# docker compose up -d # docker compose up -d
# docker compose logs docker-migrate # the URL and access token are printed here # docker compose logs dockmv # the URL and access token are printed here
# #
# The container needs the Docker socket to read containers and stream their # The container needs the Docker socket to read containers and stream their
# data. That is equivalent to root on this host, so the UI is protected by a # data. That is equivalent to root on this host, so the UI is protected by a
# generated token and should not be published to an untrusted network. # generated token and should not be published to an untrusted network.
services: services:
docker-migrate: dockmv:
build: build:
context: . context: .
args: args:
VERSION: ${VERSION:-dev} VERSION: ${VERSION:-dev}
image: docker-migrate:latest image: dockmv:latest
container_name: docker-migrate container_name: dockmv
restart: unless-stopped restart: unless-stopped
ports: ports:
# Bind to loopback only. Use an SSH tunnel to reach it from elsewhere: # Bind to loopback only. Use an SSH tunnel to reach it from elsewhere:
@@ -26,7 +26,7 @@ services:
- migrate-data:/data - migrate-data:/data
environment: environment:
# Set a fixed token to keep the same URL across restarts. # Set a fixed token to keep the same URL across restarts.
# DOCKER_MIGRATE_TOKEN: change-me # DOCKMV_TOKEN: change-me
TZ: ${TZ:-UTC} TZ: ${TZ:-UTC}
command: command:
- serve - serve
+1 -1
View File
@@ -1,4 +1,4 @@
module github.com/arescom/docker-migrate module github.com/arescom/dockmv
go 1.25.0 go 1.25.0
+6 -6
View File
@@ -12,12 +12,12 @@ import (
"strings" "strings"
"time" "time"
"github.com/arescom/docker-migrate/internal/dkr" "github.com/arescom/dockmv/internal/dkr"
"github.com/arescom/docker-migrate/internal/job" "github.com/arescom/dockmv/internal/job"
"github.com/arescom/docker-migrate/internal/migrate" "github.com/arescom/dockmv/internal/migrate"
"github.com/arescom/docker-migrate/internal/spec" "github.com/arescom/dockmv/internal/spec"
"github.com/arescom/docker-migrate/internal/sshx" "github.com/arescom/dockmv/internal/sshx"
"github.com/arescom/docker-migrate/internal/store" "github.com/arescom/dockmv/internal/store"
) )
func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) { func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) {
+4 -4
View File
@@ -13,10 +13,10 @@ import (
"strings" "strings"
"time" "time"
"github.com/arescom/docker-migrate/internal/dkr" "github.com/arescom/dockmv/internal/dkr"
"github.com/arescom/docker-migrate/internal/job" "github.com/arescom/dockmv/internal/job"
"github.com/arescom/docker-migrate/internal/sshx" "github.com/arescom/dockmv/internal/sshx"
"github.com/arescom/docker-migrate/internal/store" "github.com/arescom/dockmv/internal/store"
) )
// Config configures the HTTP server. // Config configures the HTTP server.
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/arescom/docker-migrate/internal/spec" "github.com/arescom/dockmv/internal/spec"
dockertypes "github.com/docker/docker/api/types" dockertypes "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/image" "github.com/docker/docker/api/types/image"
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"sort" "sort"
"strings" "strings"
"github.com/arescom/docker-migrate/internal/spec" "github.com/arescom/dockmv/internal/spec"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/image" "github.com/docker/docker/api/types/image"
imagetypes "github.com/docker/docker/api/types/image" imagetypes "github.com/docker/docker/api/types/image"
+4 -4
View File
@@ -7,15 +7,15 @@ import (
"testing" "testing"
"time" "time"
"github.com/arescom/docker-migrate/internal/spec" "github.com/arescom/dockmv/internal/spec"
) )
// TestLiveInventory is a smoke test against whatever daemon the environment // TestLiveInventory is a smoke test against whatever daemon the environment
// points at. It is skipped unless DOCKER_MIGRATE_LIVE_TEST is set, because it // points at. It is skipped unless DOCKMV_LIVE_TEST is set, because it
// needs a real Docker host. // needs a real Docker host.
func TestLiveInventory(t *testing.T) { func TestLiveInventory(t *testing.T) {
if os.Getenv("DOCKER_MIGRATE_LIVE_TEST") == "" { if os.Getenv("DOCKMV_LIVE_TEST") == "" {
t.Skip("set DOCKER_MIGRATE_LIVE_TEST=1 to run against the local daemon") t.Skip("set DOCKMV_LIVE_TEST=1 to run against the local daemon")
} }
c, err := New("") c, err := New("")
if err != nil { if err != nil {
+4 -4
View File
@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/arescom/docker-migrate/internal/spec" "github.com/arescom/dockmv/internal/spec"
) )
// renderInstaller generates the shell script shipped inside a migration // renderInstaller generates the shell script shipped inside a migration
@@ -451,14 +451,14 @@ seed_readonly() { # container image destination relpath compressed
store="$(resolve_mount "$1" "$3")" || { err "cannot resolve storage behind $3"; return 1; } store="$(resolve_mount "$1" "$3")" || { err "cannot resolve storage behind $3"; return 1; }
base="${3##*/}" base="${3##*/}"
stage="dm-stage-$$-${RANDOM}" stage="dm-stage-$$-${RANDOM}"
mountat="/__docker_migrate/$base" mountat="/__dockmv/$base"
$DOCKER create --name "$stage" --volume "$store:$mountat" "$2" >/dev/null \ $DOCKER create --name "$stage" --volume "$store:$mountat" "$2" >/dev/null \
|| { err "could not create staging container for $3"; return 1; } || { err "could not create staging container for $3"; return 1; }
local rc=0 local rc=0
if [ "$5" = 1 ]; then if [ "$5" = 1 ]; then
gzip -dc -- "$PKGDIR/$4" | $DOCKER cp -a - "$stage:/__docker_migrate" || rc=$? gzip -dc -- "$PKGDIR/$4" | $DOCKER cp -a - "$stage:/__dockmv" || rc=$?
else else
$DOCKER cp -a - "$stage:/__docker_migrate" < "$PKGDIR/$4" || rc=$? $DOCKER cp -a - "$stage:/__dockmv" < "$PKGDIR/$4" || rc=$?
fi fi
$DOCKER rm -f "$stage" >/dev/null 2>&1 || true $DOCKER rm -f "$stage" >/dev/null 2>&1 || true
if [ "$rc" != 0 ]; then if [ "$rc" != 0 ]; then
+1 -1
View File
@@ -11,7 +11,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/arescom/docker-migrate/internal/spec" "github.com/arescom/dockmv/internal/spec"
) )
func buildPrepared(t *testing.T, c *spec.Container, vols []spec.Volume, nets []spec.Network) *Prepared { func buildPrepared(t *testing.T, c *spec.Container, vols []spec.Volume, nets []spec.Network) *Prepared {
+4 -4
View File
@@ -15,9 +15,9 @@ import (
"strings" "strings"
"time" "time"
"github.com/arescom/docker-migrate/internal/dkr" "github.com/arescom/dockmv/internal/dkr"
"github.com/arescom/docker-migrate/internal/job" "github.com/arescom/dockmv/internal/job"
"github.com/arescom/docker-migrate/internal/spec" "github.com/arescom/dockmv/internal/spec"
) )
// PackageFormat selects how the finished package is laid out on disk. // PackageFormat selects how the finished package is laid out on disk.
@@ -102,7 +102,7 @@ func (p *Packager) Run(ctx context.Context, j *job.Job) (*Result, error) {
man := spec.Manifest{ man := spec.Manifest{
FormatVersion: 1, FormatVersion: 1,
CreatedAt: time.Now(), CreatedAt: time.Now(),
CreatedBy: "docker-migrate", CreatedBy: "dockmv",
SourceHost: p.SourceHost, SourceHost: p.SourceHost,
Options: opts, Options: opts,
Items: p.Plan.Items, Items: p.Plan.Items,
+2 -2
View File
@@ -8,7 +8,7 @@ import (
"path" "path"
"strings" "strings"
"github.com/arescom/docker-migrate/internal/spec" "github.com/arescom/dockmv/internal/spec"
) )
// Prepared is one container resolved against the user's selection: the spec as // Prepared is one container resolved against the user's selection: the spec as
@@ -189,7 +189,7 @@ func Prepare(
// StagingMountPath is where a read-only destination is mounted inside the // StagingMountPath is where a read-only destination is mounted inside the
// temporary staging container used to seed it. // temporary staging container used to seed it.
const stagingRoot = "/__docker_migrate" const stagingRoot = "/__dockmv"
// StagingPaths returns the mount point and the extraction directory used when // StagingPaths returns the mount point and the extraction directory used when
// seeding a read-only mount through a staging container. The volume is mounted // seeding a read-only mount through a staging container. The volume is mounted
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/arescom/docker-migrate/internal/spec" "github.com/arescom/dockmv/internal/spec"
) )
func sample() *spec.Container { func sample() *spec.Container {
+4 -4
View File
@@ -10,10 +10,10 @@ import (
"sync" "sync"
"time" "time"
"github.com/arescom/docker-migrate/internal/dkr" "github.com/arescom/dockmv/internal/dkr"
"github.com/arescom/docker-migrate/internal/job" "github.com/arescom/dockmv/internal/job"
"github.com/arescom/docker-migrate/internal/spec" "github.com/arescom/dockmv/internal/spec"
"github.com/arescom/docker-migrate/internal/sshx" "github.com/arescom/dockmv/internal/sshx"
) )
// SSHRunner migrates containers straight from the local daemon to a target // SSHRunner migrates containers straight from the local daemon to a target
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"io" "io"
"strings" "strings"
"github.com/arescom/docker-migrate/internal/spec" "github.com/arescom/dockmv/internal/spec"
) )
// RemoteDocker drives the docker CLI on a target host over SSH. It assumes // RemoteDocker drives the docker CLI on a target host over SSH. It assumes
+1 -1
View File
@@ -12,7 +12,7 @@ import (
"sort" "sort"
"sync" "sync"
"github.com/arescom/docker-migrate/internal/sshx" "github.com/arescom/dockmv/internal/sshx"
) )
// ErrNotFound is returned for an unknown connection id. // ErrNotFound is returned for an unknown connection id.
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -6,7 +6,7 @@
<meta name="color-scheme" content="dark light" /> <meta name="color-scheme" content="dark light" />
<link rel="icon" type="image/png" href="/favicon.png" /> <link rel="icon" type="image/png" href="/favicon.png" />
<title>DockMV</title> <title>DockMV</title>
<script type="module" crossorigin src="/assets/index-DJVzxyBi.js"></script> <script type="module" crossorigin src="/assets/index-2w4y0Lpg.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CKzWD9Xt.css"> <link rel="stylesheet" crossorigin href="/assets/index-CKzWD9Xt.css">
</head> </head>
<body> <body>
+17 -17
View File
@@ -1,4 +1,4 @@
// Command docker-migrate moves Docker containers, together with their volumes // Command dockmv moves Docker containers, together with their volumes
// and bind mounts, from one host to another. // and bind mounts, from one host to another.
// //
// It runs either as a web application (the default) or as a one-shot inventory // It runs either as a web application (the default) or as a one-shot inventory
@@ -26,9 +26,9 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/arescom/docker-migrate/internal/api" "github.com/arescom/dockmv/internal/api"
"github.com/arescom/docker-migrate/internal/dkr" "github.com/arescom/dockmv/internal/dkr"
"github.com/arescom/docker-migrate/internal/webui" "github.com/arescom/dockmv/internal/webui"
) )
// version is overridden at build time with -ldflags "-X main.version=...". // version is overridden at build time with -ldflags "-X main.version=...".
@@ -55,7 +55,7 @@ func run(args []string) error {
case "inspect": case "inspect":
return inspect(args) return inspect(args)
case "version": case "version":
fmt.Printf("docker-migrate %s (%s %s/%s)\n", version, runtime.Version(), runtime.GOOS, runtime.GOARCH) fmt.Printf("dockmv %s (%s %s/%s)\n", version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
return nil return nil
case "help", "-h", "--help": case "help", "-h", "--help":
usage() usage()
@@ -67,14 +67,14 @@ func run(args []string) error {
} }
func usage() { func usage() {
fmt.Fprint(os.Stderr, `docker-migrate - move Docker containers and their data between hosts fmt.Fprint(os.Stderr, `dockmv - move Docker containers and their data between hosts
Usage: Usage:
docker-migrate [serve] [flags] start the web interface (default) dockmv [serve] [flags] start the web interface (default)
docker-migrate inspect [flags] print the source inventory as JSON dockmv inspect [flags] print the source inventory as JSON
docker-migrate version print the version dockmv version print the version
Run "docker-migrate serve -h" for the server flags. Run "dockmv serve -h" for the server flags.
`) `)
} }
@@ -87,7 +87,7 @@ func serve(args []string) error {
dockerHost := fs.String("docker-host", "", "source docker daemon (default: the DOCKER_HOST environment)") dockerHost := fs.String("docker-host", "", "source docker daemon (default: the DOCKER_HOST environment)")
verbose := fs.Bool("v", false, "verbose logging") verbose := fs.Bool("v", false, "verbose logging")
fs.Usage = func() { fs.Usage = func() {
fmt.Fprintln(os.Stderr, "Usage: docker-migrate serve [flags]\n\nFlags:") fmt.Fprintln(os.Stderr, "Usage: dockmv serve [flags]\n\nFlags:")
fs.PrintDefaults() fs.PrintDefaults()
} }
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
@@ -148,7 +148,7 @@ func serve(args []string) error {
if authToken != "" { if authToken != "" {
url += "/?token=" + authToken url += "/?token=" + authToken
} }
fmt.Fprintf(os.Stderr, "\n docker-migrate %s\n open %s\n data: %s\n\n", version, url, *dataDir) fmt.Fprintf(os.Stderr, "\n dockmv %s\n open %s\n data: %s\n\n", version, url, *dataDir)
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop() defer stop()
@@ -176,7 +176,7 @@ func inspect(args []string) error {
dockerHost := fs.String("docker-host", "", "docker daemon to read (default: the DOCKER_HOST environment)") dockerHost := fs.String("docker-host", "", "docker daemon to read (default: the DOCKER_HOST environment)")
sizes := fs.Bool("sizes", false, "also measure volume sizes (slower)") sizes := fs.Bool("sizes", false, "also measure volume sizes (slower)")
fs.Usage = func() { fs.Usage = func() {
fmt.Fprintln(os.Stderr, "Usage: docker-migrate inspect [flags]\n\nFlags:") fmt.Fprintln(os.Stderr, "Usage: dockmv inspect [flags]\n\nFlags:")
fs.PrintDefaults() fs.PrintDefaults()
} }
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
@@ -207,15 +207,15 @@ func inspect(args []string) error {
} }
// defaultDataDir picks a per-user location, honouring the container-friendly // defaultDataDir picks a per-user location, honouring the container-friendly
// DOCKER_MIGRATE_DATA override. // DOCKMV_DATA override.
func defaultDataDir() string { func defaultDataDir() string {
if v := os.Getenv("DOCKER_MIGRATE_DATA"); v != "" { if v := os.Getenv("DOCKMV_DATA"); v != "" {
return v return v
} }
if dir, err := os.UserConfigDir(); err == nil { if dir, err := os.UserConfigDir(); err == nil {
return filepath.Join(dir, "docker-migrate") return filepath.Join(dir, "dockmv")
} }
return ".docker-migrate" return ".dockmv"
} }
func randomToken() string { func randomToken() string {
+11 -7
View File
@@ -1,10 +1,10 @@
#requires -Version 5.1 #requires -Version 5.1
<# <#
.SYNOPSIS .SYNOPSIS
Build the docker-migrate web UI and cross-compile release binaries. Build the dockmv web UI and cross-compile release binaries.
.DESCRIPTION .DESCRIPTION
Produces dist/docker-migrate-<os>-<arch>[.exe] for every target, one archive Produces dist/dockmv-<os>-<arch>[.exe] for every target, one archive
per binary (.zip for Windows, .tar.gz elsewhere) and dist/SHA256SUMS.txt. per binary (.zip for Windows, .tar.gz elsewhere) and dist/SHA256SUMS.txt.
The PowerShell equivalent of `make release`, so a Windows host without make The PowerShell equivalent of `make release`, so a Windows host without make
@@ -130,11 +130,11 @@ try {
if (-not $Tag) { $Tag = "dev" } if (-not $Tag) { $Tag = "dev" }
} }
$bin = "docker-migrate" $bin = "dockmv"
$distDir = Join-Path $repoRoot "dist" $distDir = Join-Path $repoRoot "dist"
$ldflags = "-s -w -X main.version=$Tag" $ldflags = "-s -w -X main.version=$Tag"
Write-Host "docker-migrate release build" -ForegroundColor Cyan Write-Host "dockmv release build" -ForegroundColor Cyan
Write-Host " go : $Go" Write-Host " go : $Go"
Write-Host " tag : $Tag" Write-Host " tag : $Tag"
Write-Host " targets : $($Targets -join ', ')" Write-Host " targets : $($Targets -join ', ')"
@@ -152,13 +152,17 @@ try {
# run before the compile — not after, and not in parallel with it. # run before the compile — not after, and not in parallel with it.
if (-not $SkipUi) { if (-not $SkipUi) {
Write-Host "Building web UI..." -ForegroundColor Cyan Write-Host "Building web UI..." -ForegroundColor Cyan
if (-not (Get-Command npm -ErrorAction SilentlyContinue)) { # npm.cmd, not npm(.ps1): the ps1 shim reparses $MyInvocation.Line as text
# when called via `& $Exe @Args`, which mangles splatted args into a bogus
# single token and makes npm print usage instead of running the command.
$npmCmd = (Get-Command npm.cmd -ErrorAction SilentlyContinue).Source
if (-not $npmCmd) {
throw "npm not found — install Node 22+, or pass -SkipUi to reuse the committed internal/webui/dist." throw "npm not found — install Node 22+, or pass -SkipUi to reuse the committed internal/webui/dist."
} }
Push-Location (Join-Path $repoRoot "web") Push-Location (Join-Path $repoRoot "web")
try { try {
Invoke-Checked npm @("ci", "--no-audit", "--no-fund") Invoke-Checked $npmCmd @("ci", "--no-audit", "--no-fund")
Invoke-Checked npm @("run", "build") Invoke-Checked $npmCmd @("run", "build")
} }
finally { Pop-Location } finally { Pop-Location }
Write-Host "" Write-Host ""
+7 -7
View File
@@ -1,7 +1,7 @@
#requires -Version 5.1 #requires -Version 5.1
<# <#
.SYNOPSIS .SYNOPSIS
Build the docker-migrate container image + release binaries; push the image to Build the dockmv container image + release binaries; push the image to
the Gitea registry and attach the binaries to a Gitea release. the Gitea registry and attach the binaries to a Gitea release.
.DESCRIPTION .DESCRIPTION
@@ -58,7 +58,7 @@ param(
[string]$Owner = "kawa", [string]$Owner = "kawa",
# Image name. # Image name.
[string]$Image = "docker-migrate", [string]$Image = "dockmv",
# Repository name holding the releases. The image and the repo are not named # Repository name holding the releases. The image and the repo are not named
# the same here, so this is separate from -Image. # the same here, so this is separate from -Image.
@@ -242,7 +242,7 @@ function Publish-BinaryRelease {
Write-Host " creating release $Tag in $RepoPath..." -ForegroundColor DarkGray Write-Host " creating release $Tag in $RepoPath..." -ForegroundColor DarkGray
$release = Invoke-GiteaApi -Method POST -Uri $releasesUri -Token $Token -Body @{ $release = Invoke-GiteaApi -Method POST -Uri $releasesUri -Token $Token -Body @{
tag_name = $Tag tag_name = $Tag
name = "docker-migrate $Tag" name = "dockmv $Tag"
body = "Standalone binaries for linux, macOS and Windows. Container image: see the package registry." body = "Standalone binaries for linux, macOS and Windows. Container image: see the package registry."
draft = $false draft = $false
} }
@@ -311,7 +311,7 @@ try {
$tags = @("$base`:$Tag") $tags = @("$base`:$Tag")
if (-not $NoLatest -and $Tag -ne "latest") { $tags += "$base`:latest" } if (-not $NoLatest -and $Tag -ne "latest") { $tags += "$base`:latest" }
Write-Host "docker-migrate publish" -ForegroundColor Cyan Write-Host "dockmv publish" -ForegroundColor Cyan
Write-Host " registry : $Registry" Write-Host " registry : $Registry"
if ($pushImage) { if ($pushImage) {
Write-Host " image : $base" Write-Host " image : $base"
@@ -358,10 +358,10 @@ try {
# Uploading a binary older than the code it claims to be is the one way # Uploading a binary older than the code it claims to be is the one way
# this flag can quietly go wrong, so say so rather than assume. # this flag can quietly go wrong, so say so rather than assume.
$oldest = (Get-ChildItem $distDir -Filter "docker-migrate-$Tag-*" -File | $oldest = (Get-ChildItem $distDir -Filter "dockmv-$Tag-*" -File |
Sort-Object LastWriteTime | Select-Object -First 1) Sort-Object LastWriteTime | Select-Object -First 1)
if (-not $oldest) { if (-not $oldest) {
throw "no archives named docker-migrate-$Tag-* in $distDir — the exe on disk was built under a different tag. Drop -NoBinaryBuild." throw "no archives named dockmv-$Tag-* in $distDir — the exe on disk was built under a different tag. Drop -NoBinaryBuild."
} }
$newer = Get-ChildItem $repoRoot -Recurse -Include *.go, *.ts, *.tsx, *.css, *.html -File | $newer = Get-ChildItem $repoRoot -Recurse -Include *.go, *.ts, *.tsx, *.css, *.html -File |
Where-Object { Where-Object {
@@ -383,7 +383,7 @@ try {
& (Join-Path $PSScriptRoot "build-release.ps1") -Tag $Tag -Targets $Targets -SkipUi:$SkipUi & (Join-Path $PSScriptRoot "build-release.ps1") -Tag $Tag -Targets $Targets -SkipUi:$SkipUi
} }
$artifacts = @(Get-ChildItem $distDir -Filter "docker-migrate-$Tag-*" -File | ForEach-Object FullName) $artifacts = @(Get-ChildItem $distDir -Filter "dockmv-$Tag-*" -File | ForEach-Object FullName)
if (-not $artifacts.Count) { throw "no release archives for $Tag found in $distDir." } if (-not $artifacts.Count) { throw "no release archives for $Tag found in $distDir." }
$sums = Join-Path $distDir "SHA256SUMS.txt" $sums = Join-Path $distDir "SHA256SUMS.txt"
if (Test-Path $sums) { $artifacts += $sums } if (Test-Path $sums) { $artifacts += $sums }
+4 -4
View File
@@ -20,10 +20,10 @@ import (
"testing" "testing"
"time" "time"
"github.com/arescom/docker-migrate/internal/dkr" "github.com/arescom/dockmv/internal/dkr"
"github.com/arescom/docker-migrate/internal/job" "github.com/arescom/dockmv/internal/job"
"github.com/arescom/docker-migrate/internal/migrate" "github.com/arescom/dockmv/internal/migrate"
"github.com/arescom/docker-migrate/internal/spec" "github.com/arescom/dockmv/internal/spec"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/image" "github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/mount" "github.com/docker/docker/api/types/mount"
+1 -1
View File
@@ -5,7 +5,7 @@ package e2e
import ( import (
"errors" "errors"
"github.com/arescom/docker-migrate/internal/sshx" "github.com/arescom/dockmv/internal/sshx"
) )
// asHostKeyError unwraps err into a *sshx.HostKeyError if it is one. // asHostKeyError unwraps err into a *sshx.HostKeyError if it is one.
+5 -5
View File
@@ -10,11 +10,11 @@ import (
"testing" "testing"
"time" "time"
"github.com/arescom/docker-migrate/internal/dkr" "github.com/arescom/dockmv/internal/dkr"
"github.com/arescom/docker-migrate/internal/job" "github.com/arescom/dockmv/internal/job"
"github.com/arescom/docker-migrate/internal/migrate" "github.com/arescom/dockmv/internal/migrate"
"github.com/arescom/docker-migrate/internal/spec" "github.com/arescom/dockmv/internal/spec"
"github.com/arescom/docker-migrate/internal/sshx" "github.com/arescom/dockmv/internal/sshx"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/mount" "github.com/docker/docker/api/types/mount"
"github.com/docker/docker/api/types/volume" "github.com/docker/docker/api/types/volume"
+2 -2
View File
@@ -1,11 +1,11 @@
{ {
"name": "docker-migrate-ui", "name": "dockmv-ui",
"version": "1.0.0", "version": "1.0.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "docker-migrate-ui", "name": "dockmv-ui",
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"react": "^19.2.0", "react": "^19.2.0",
+1 -1
View File
@@ -1,5 +1,5 @@
{ {
"name": "docker-migrate-ui", "name": "dockmv-ui",
"private": true, "private": true,
"version": "1.0.0", "version": "1.0.0",
"type": "module", "type": "module",
+2 -2
View File
@@ -425,7 +425,7 @@ function ConnectionDialog({
{c.auth === 'agent' && ( {c.auth === 'agent' && (
<div className="small muted"> <div className="small muted">
Uses the agent at <span className="mono">$SSH_AUTH_SOCK</span> of the process running docker-migrate. Uses the agent at <span className="mono">$SSH_AUTH_SOCK</span> of the process running dockmv.
</div> </div>
)} )}
@@ -452,7 +452,7 @@ function ConnectionDialog({
</Notice> </Notice>
) : ( ) : (
<div className="small faint"> <div className="small faint">
Credentials stay in memory and are lost when docker-migrate restarts. Credentials stay in memory and are lost when dockmv restarts.
</div> </div>
)} )}
</div> </div>
+1 -1
View File
@@ -1,4 +1,4 @@
/* docker-migrate UI. /* dockmv UI.
An operations tool: dense, monospace-leaning, dark by default. Colour is An operations tool: dense, monospace-leaning, dark by default. Colour is
reserved for state, never for decoration. */ reserved for state, never for decoration. */