• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sapslaj / mid / 16253111942

13 Jul 2025 08:22PM UTC coverage: 60.02% (+1.0%) from 59.031%
16253111942

push

github

sapslaj
feat: AnsibleTaskList

This is a hack. A backdoor. An escape hatch. Avoid using it if you can,
but it's here if you _really_ need it.

I will probably end up removing it at some point but there's just too
many missing "first-class" resources that I think this has to exist
otherwise this project is not really usable.

178 of 207 new or added lines in 2 files covered. (85.99%)

4 existing lines in 1 file now uncovered.

4702 of 7834 relevant lines covered (60.02%)

337.04 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.96
/pkg/pdiff/pdiff.go
1
package pdiff
2

3
import (
4
        "maps"
5
        "reflect"
6
        "slices"
7
        "strings"
8

9
        p "github.com/pulumi/pulumi-go-provider"
10
        "github.com/pulumi/pulumi/sdk/v3/go/common/resource"
11
        "github.com/pulumi/pulumi/sdk/v3/go/common/resource/plugin"
12
        "github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
13

14
        "github.com/sapslaj/mid/pkg/pulumi-go-provider/ende"
15
        "github.com/sapslaj/mid/pkg/pulumi-go-provider/introspect"
16
)
17

18
// DiffAttributes performs deep equality on two structs only for the attributes
19
// provided and returns a DiffResponse
20
func DiffAttributes(inputs any, state any, attributes []string) p.DiffResponse {
39✔
21
        inputProps, err := introspect.FindProperties(reflect.TypeOf(inputs))
39✔
22
        contract.AssertNoErrorf(err, "could not get properties")
39✔
23

39✔
24
        encoder := &ende.Encoder{}
39✔
25

39✔
26
        inputsMap, err := encoder.Encode(inputs)
39✔
27
        contract.AssertNoErrorf(err, "could not diff inputs")
39✔
28

39✔
29
        stateMap, err := encoder.Encode(state)
39✔
30
        contract.AssertNoErrorf(err, "could not diff state")
39✔
31

39✔
32
        // Olds is an Output, but news is an Input. Output should be a superset of
39✔
33
        // Input, so we need to filter out fields that are in Output but not Input.
39✔
34
        oldInputsMap := resource.PropertyMap{}
39✔
35
        for k := range inputsMap {
162✔
36
                oldInputsMap[k] = stateMap[k]
123✔
37
        }
123✔
38

39
        objDiff := oldInputsMap.Diff(inputsMap)
39✔
40
        pluginDiff := plugin.NewDetailedDiffFromObjectDiff(objDiff, true)
39✔
41
        diff := map[string]p.PropertyDiff{}
39✔
42

39✔
43
        for k, v := range pluginDiff {
81✔
44
                selected := false
42✔
45
                for i := range attributes {
497✔
46
                        // FIXME: this has the potential to be too greedy and match things it
455✔
47
                        // shouldn't. It should be breaking down the components of the key and
455✔
48
                        // ensuring there is a full match for all the components but i ain't got
455✔
49
                        // time to write that.
455✔
50
                        if strings.HasPrefix(k, attributes[i]) {
481✔
51
                                selected = true
26✔
52
                        }
26✔
53
                }
54
                if !selected {
58✔
55
                        continue
16✔
56
                }
57

58
                set := func(kind p.DiffKind) {
52✔
59
                        diff[k] = p.PropertyDiff{
26✔
60
                                Kind:      kind,
26✔
61
                                InputDiff: v.InputDiff,
26✔
62
                        }
26✔
63
                }
26✔
64

65
                fieldTag := inputProps[k]
26✔
66
                if fieldTag.ReplaceOnChanges {
30✔
67
                        v.Kind = v.Kind.AsReplace()
4✔
68
                }
4✔
69

70
                switch v.Kind {
26✔
71
                case plugin.DiffAdd:
1✔
72
                        set(p.Add)
1✔
UNCOV
73
                case plugin.DiffAddReplace:
×
UNCOV
74
                        set(p.AddReplace)
×
75
                case plugin.DiffDelete:
3✔
76
                        set(p.Delete)
3✔
UNCOV
77
                case plugin.DiffDeleteReplace:
×
UNCOV
78
                        set(p.DeleteReplace)
×
79
                case plugin.DiffUpdate:
18✔
80
                        set(p.Update)
18✔
81
                case plugin.DiffUpdateReplace:
4✔
82
                        set(p.UpdateReplace)
4✔
83
                }
84
        }
85
        return p.DiffResponse{
39✔
86
                HasChanges:   len(diff) > 0,
39✔
87
                DetailedDiff: diff,
39✔
88
        }
39✔
89
}
90

91
// DiffAllAttributesExcept performs a deep equality on two structs for all
92
// attributes except the list provided and returns a diff response.
93
func DiffAllAttributesExcept(inputs any, state any, exceptAttributes []string) p.DiffResponse {
33✔
94
        inputProps, err := introspect.FindProperties(reflect.TypeOf(inputs))
33✔
95
        contract.AssertNoErrorf(err, "could not get properties")
33✔
96

33✔
97
        attributes := []string{}
33✔
98
        for prop := range inputProps {
569✔
99
                if !slices.Contains(exceptAttributes, prop) {
1,045✔
100
                        attributes = append(attributes, prop)
509✔
101
                }
509✔
102
        }
103

104
        return DiffAttributes(inputs, state, attributes)
33✔
105
}
106

107
// DiffAllAttributes performs a deep equality on two structs for all attributes
108
func DiffAllAttributes(inputs any, state any) p.DiffResponse {
6✔
109
        return DiffAllAttributesExcept(inputs, state, []string{})
6✔
110
}
6✔
111

112
// ForceDiffReplace changes all of the properties in the DiffResponse to be the
113
// "-replace" equivalent to trigger a resource replacement.
114
func ForceDiffReplace(diff p.DiffResponse) p.DiffResponse {
1✔
115
        for key, propdiff := range diff.DetailedDiff {
8✔
116
                switch propdiff.Kind {
7✔
117
                case p.Add:
1✔
118
                        propdiff.Kind = p.AddReplace
1✔
119
                case p.Delete:
1✔
120
                        propdiff.Kind = p.DeleteReplace
1✔
121
                case p.Update:
1✔
122
                        propdiff.Kind = p.UpdateReplace
1✔
123
                }
124
                diff.DetailedDiff[key] = propdiff
7✔
125
        }
126
        return diff
1✔
127
}
128

129
// MergeDiffResponses will merge an arbitrary number of DiffResponses together
130
// with the last taking the highest precedence. Any DiffResponse that has
131
// `HasChanges` or `DeleteBeforeReplace` set will result in the returned
132
// DiffResponse to have those set as well.
133
func MergeDiffResponses(drs ...p.DiffResponse) p.DiffResponse {
25✔
134
        diff := p.DiffResponse{
25✔
135
                HasChanges:   false,
25✔
136
                DetailedDiff: map[string]p.PropertyDiff{},
25✔
137
        }
25✔
138
        for _, dr := range drs {
101✔
139
                if dr.HasChanges {
91✔
140
                        diff.HasChanges = true
15✔
141
                }
15✔
142
                if dr.DeleteBeforeReplace {
87✔
143
                        diff.DeleteBeforeReplace = true
11✔
144
                }
11✔
145
                maps.Copy(diff.DetailedDiff, dr.DetailedDiff)
76✔
146
        }
147
        return diff
25✔
148
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc