@@ -102,11 +102,6 @@ var exampleIntegrationPolicy = map[string]exampleReq{
102102 // be created first.
103103 "dokku_storage_mount" : {ensureApps : []string {"node-js-app" }, setup : setupStorageMountExample },
104104
105- // network_property references a network that must exist for a build to
106- // attach to it, and its global example sets a property that would otherwise
107- // make every later app build attach to that network.
108- "dokku_network_property" : {setup : setupNetworkPropertyExample },
109-
110105 // Tasks whose documented value is a placeholder the driver must provision
111106 // (a real inline PEM / cert path, a registry secret, or a maintenance
112107 // tarball) because it cannot be published in the docs.
@@ -195,6 +190,7 @@ func TestIntegrationTaskExamples(t *testing.T) {
195190 task = transform (task )
196191 }
197192 applyExample (t , example .Name , task )
193+ registerGlobalPropertyRevert (t , task )
198194 })
199195 }
200196 })
@@ -413,23 +409,6 @@ func enableHttpAuthExampleApp(t *testing.T) {
413409 }
414410}
415411
416- // setupNetworkPropertyExample creates the network the examples reference and,
417- // on cleanup, clears the global attach-post-create property the global example
418- // sets and removes the network. Without the cleanup, that global property
419- // persists and makes every subsequent app build fail attaching to a network the
420- // build environment no longer has.
421- func setupNetworkPropertyExample (t * testing.T ) (func (Task ) Task , func ()) {
422- t .Helper ()
423- result := NetworkTask {Name : "example-network" , State : StatePresent }.Execute ()
424- if result .Error != nil {
425- t .Fatalf ("failed to create example network: %v" , result .Error )
426- }
427- return nil , func () {
428- NetworkPropertyTask {Global : true , Property : "attach-post-create" , State : StateAbsent }.Execute ()
429- NetworkTask {Name : "example-network" , State : StateAbsent }.Execute ()
430- }
431- }
432-
433412// setupStorageMountExample creates the named storage entry the storage_mount
434413// named-entry examples attach, and removes it afterward.
435414func setupStorageMountExample (t * testing.T ) (func (Task ) Task , func ()) {
@@ -516,6 +495,46 @@ func clearChalltestsrvA(host string) {
516495 })
517496}
518497
498+ // registerGlobalPropertyRevert clears a global property an example just set, so
499+ // the setting does not persist and break later app builds or deploys. Property
500+ // tasks' "Setting a global X" examples have no global-clear counterpart (their
501+ // clear example targets the per-app scope), and a leftover global registry
502+ // server, network attachment, or similar makes every subsequent deploy fail.
503+ // It is a no-op for any task that is not a present/set of a global property.
504+ func registerGlobalPropertyRevert (t * testing.T , task Task ) {
505+ t .Helper ()
506+ v := reflect .Indirect (reflect .ValueOf (taskAsPointer (task )))
507+ if v .Kind () != reflect .Struct {
508+ return
509+ }
510+ global := v .FieldByName ("Global" )
511+ property := v .FieldByName ("Property" )
512+ state := v .FieldByName ("State" )
513+ if ! global .IsValid () || global .Kind () != reflect .Bool || ! global .Bool () {
514+ return
515+ }
516+ if ! property .IsValid () || property .Kind () != reflect .String || property .String () == "" {
517+ return
518+ }
519+ if ! state .IsValid () || state .Kind () != reflect .String {
520+ return
521+ }
522+ if s := State (state .String ()); s != StatePresent && s != StateSet {
523+ return
524+ }
525+ clear := reflect .New (v .Type ())
526+ clear .Elem ().Set (v )
527+ clear .Elem ().FieldByName ("State" ).Set (reflect .ValueOf (StateAbsent ))
528+ if value := clear .Elem ().FieldByName ("Value" ); value .IsValid () && value .Kind () == reflect .String {
529+ value .SetString ("" )
530+ }
531+ clearTask , ok := clear .Interface ().(Task )
532+ if ! ok {
533+ return
534+ }
535+ t .Cleanup (func () { clearTask .Execute () })
536+ }
537+
519538// taskStringField returns the value of a string field on a task struct, or ""
520539// when the field is absent or not a string. It reads through a pointer so it
521540// works whether the loader returned a value or pointer task.
0 commit comments