fix: migrate env files before reading deprecated vars

Install steps run in alphabetical order of the enabled plugin directory, so `apps`, `builder`, and `checks` read an app's environment before the `config` plugin had moved the `ENV` file to its new location. The read came back empty, so their deprecated `DOKKU_*` variables were never migrated to the matching plugin property and were never unset, with nothing reported either way: `dokku config:show` kept listing the variable while the plugin behaved as though it were unset. The relocation now runs before any deprecated variable is read, whatever the install order, and each old file is removed as soon as it has been drained rather than on a later install, which also covers the global file that was never removed at all. A file that reappears at the old path can only have been written by hand, so it is merged in with a warning naming its keys instead of being discarded.
This commit is contained in:
Jose Diaz-Gonzalez
2026-08-07 16:43:56 -04:00
parent eedcb90e29
commit 70dc921967
11 changed files with 455 additions and 100 deletions

View File

@@ -668,6 +668,8 @@ type MigrateConfigEntry struct {
// across all apps and optionally globally. It is idempotent: if the property already
// exists, the migration is skipped for that app/entry.
func MigrateConfigToProperties(pluginName string, entries []MigrateConfigEntry) error {
migrateLegacyEnvFiles()
apps, err := UnfilteredDokkuApps()
if err != nil && !errors.Is(err, NoAppsExist) {
return nil
@@ -694,6 +696,24 @@ func MigrateConfigToProperties(pluginName string, entries []MigrateConfigEntry)
return nil
}
// migrateLegacyEnvFiles drains the pre-0.38 ENV files into the config property
// path before any config var is read.
//
// Install triggers fire in lexicographic order of the enabled-plugin directory
// names, so plugins sorting before "config" - apps, builder and checks among
// them - would otherwise read an environment the config plugin has not
// relocated yet, find it empty, and migrate nothing without reporting anything.
// A failure here is not fatal: the migration is retried on the next install, so
// an unavailable trigger degrades to the previous behavior rather than aborting
// every plugin's install.
func migrateLegacyEnvFiles() {
if _, err := CallPlugnTrigger(PlugnTriggerInput{
Trigger: "config-migrate-env",
}); err != nil {
LogWarn(fmt.Sprintf("Unable to migrate legacy env files: %s", err.Error()))
}
}
// migrateConfigEntry migrates a single config variable to a property for a given app
func migrateConfigEntry(pluginName string, appName string, configVar string, entry MigrateConfigEntry) error {
if entry.ListProperty {