Skip to content

Commit

Permalink
Merge pull request #43 from ulucinar/fix-42
Browse files Browse the repository at this point in the history
Support reference extractor function calls containing arguments with dots
  • Loading branch information
muvaf authored Aug 26, 2022
2 parents 1f43fc1 + 2a99ce6 commit 6bcdd63
Show file tree
Hide file tree
Showing 11 changed files with 131 additions and 42 deletions.
35 changes: 20 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ on:

env:
# Common versions
GO_VERSION: '1.17'
GOLANGCI_VERSION: 'v1.31'
DOCKER_BUILDX_VERSION: 'v0.4.2'
GO_VERSION: '1.18'
GOLANGCI_VERSION: 'v1.47.3'
DOCKER_BUILDX_VERSION: 'v0.8.2'

# Common users. We can't run a step 'if secrets.AWS_USR != ""' but we can run
# a step 'if env.AWS_USR' != ""', so we copy these to succinctly test whether
Expand All @@ -22,7 +22,7 @@ env:

jobs:
detect-noop:
runs-on: ubuntu-18.04
runs-on: ubuntu-22.04
outputs:
noop: ${{ steps.noop.outputs.should_skip }}
steps:
Expand All @@ -36,7 +36,7 @@ jobs:


lint:
runs-on: ubuntu-18.04
runs-on: ubuntu-22.04
needs: detect-noop
if: needs.detect-noop.outputs.noop != 'true'

Expand All @@ -46,9 +46,14 @@ jobs:
with:
submodules: true

- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}

- name: Find the Go Build Cache
id: go
run: echo "::set-output name=cache::$(go env GOCACHE)"
run: echo "::set-output name=cache::$(make go.cachedir)"

- name: Cache the Go Build Cache
uses: actions/cache@v2
Expand All @@ -75,9 +80,10 @@ jobs:
uses: golangci/golangci-lint-action@v2
with:
version: ${{ env.GOLANGCI_VERSION }}
skip-go-installation: true

check-diff:
runs-on: ubuntu-18.04
runs-on: ubuntu-22.04
needs: detect-noop
if: needs.detect-noop.outputs.noop != 'true'

Expand All @@ -94,7 +100,7 @@ jobs:

- name: Find the Go Build Cache
id: go
run: echo "::set-output name=cache::$(go env GOCACHE)"
run: echo "::set-output name=cache::$(make go.cachedir)"

- name: Cache the Go Build Cache
uses: actions/cache@v2
Expand All @@ -117,7 +123,7 @@ jobs:
run: make check-diff

unit-tests:
runs-on: ubuntu-18.04
runs-on: ubuntu-22.04
needs: detect-noop
if: needs.detect-noop.outputs.noop != 'true'

Expand All @@ -137,7 +143,7 @@ jobs:

- name: Find the Go Build Cache
id: go
run: echo "::set-output name=cache::$(go env GOCACHE)"
run: echo "::set-output name=cache::$(make go.cachedir)"

- name: Cache the Go Build Cache
uses: actions/cache@v2
Expand Down Expand Up @@ -166,7 +172,7 @@ jobs:
file: _output/tests/linux_amd64/coverage.txt

e2e-tests:
runs-on: ubuntu-18.04
runs-on: ubuntu-22.04
needs: detect-noop
if: needs.detect-noop.outputs.noop != 'true'

Expand Down Expand Up @@ -197,7 +203,7 @@ jobs:

- name: Find the Go Build Cache
id: go
run: echo "::set-output name=cache::$(go env GOCACHE)"
run: echo "::set-output name=cache::$(make go.cachedir)"

- name: Cache the Go Build Cache
uses: actions/cache@v2
Expand Down Expand Up @@ -228,7 +234,7 @@ jobs:
run: make e2e USE_HELM3=true

publish-artifacts:
runs-on: ubuntu-18.04
runs-on: ubuntu-22.04
needs: detect-noop
if: needs.detect-noop.outputs.noop != 'true'

Expand Down Expand Up @@ -259,7 +265,7 @@ jobs:

- name: Find the Go Build Cache
id: go
run: echo "::set-output name=cache::$(go env GOCACHE)"
run: echo "::set-output name=cache::$(make go.cachedir)"

- name: Cache the Go Build Cache
uses: actions/cache@v2
Expand Down Expand Up @@ -314,4 +320,3 @@ jobs:
CHANNEL: master
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_USR }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_PSW }}

2 changes: 1 addition & 1 deletion .github/workflows/promote.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ env:

jobs:
promote-artifacts:
runs-on: ubuntu-18.04
runs-on: ubuntu-22.04

steps:
- name: Checkout
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:

jobs:
create-tag:
runs-on: ubuntu-18.04
runs-on: ubuntu-22.04

steps:
- name: Checkout
Expand Down
8 changes: 4 additions & 4 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ linters-settings:
# report about shadowed variables
check-shadowing: false

golint:
# minimal confidence for issues, default is 0.8
min-confidence: 0.8
revive:
# confidence for issues, default is 0.8
confidence: 0.8

gofmt:
# simplify code: gofmt with `-s` option, true by default
Expand Down Expand Up @@ -110,7 +110,7 @@ linters:
- goimports
- gofmt # We enable this as well as goimports for its simplify mode.
- prealloc
- golint
- revive
- unconvert
- misspell
- nakedret
Expand Down
14 changes: 13 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,16 @@ crossplane-tools.help:

help-special: crossplane-tools.help

.PHONY: crossplane-tools.help help-special
# NOTE(hasheddan): the build submodule currently overrides XDG_CACHE_HOME in
# order to force the Helm 3 to use the .work/helm directory. This causes Go on
# Linux machines to use that directory as the build cache as well. We should
# adjust this behavior in the build submodule because it is also causing Linux
# users to duplicate their build cache, but for now we just make it easier to
# identify its location in CI so that we cache between builds.
go.cachedir:
@go env GOCACHE

go.mod.cachedir:
@go env GOMODCACHE

.PHONY: cobertura reviewable submodules fallthrough go.mod.cachedir go.cachedir
2 changes: 1 addition & 1 deletion build
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/crossplane/crossplane-tools

go 1.17
go 1.18

require (
github.com/dave/jennifer v1.4.1
Expand Down
8 changes: 0 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,18 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
Expand Down
34 changes: 26 additions & 8 deletions internal/method/reference_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ package method

import (
"go/types"
"regexp"
"strings"

"github.com/dave/jennifer/jen"
"github.com/pkg/errors"

"github.com/crossplane/crossplane-tools/internal/comments"
)
Expand All @@ -33,6 +35,10 @@ const (
ReferenceSelectorFieldNameMarker = "crossplane:generate:reference:selectorFieldName"
)

var (
regexFunctionCall = regexp.MustCompile(`((.+)\.)?([^.]+\(.*\))`)
)

// Reference is the internal representation that has enough information to let
// us generate the resolver.
type Reference struct {
Expand Down Expand Up @@ -125,7 +131,11 @@ func (rp *ReferenceProcessor) Process(_ *types.Named, f *types.Var, _, comment s

extractorPath := rp.DefaultExtractor
if values, ok := markers[ReferenceExtractorMarker]; ok {
extractorPath = getFuncCodeFromPath(values[0])
var err error
extractorPath, err = getFuncCodeFromPath(values[0])
if err != nil {
return errors.Wrapf(err, "cannot get extractor function")
}
}

refFieldName := f.Name() + "Ref"
Expand Down Expand Up @@ -169,12 +179,20 @@ func getTypeCodeFromPath(path string, nameSuffix ...string) *jen.Statement {
return jen.Op("&").Qual(pkg, name).Values()
}

func getFuncCodeFromPath(path string) *jen.Statement {
words := strings.Split(path, ".")
if len(words) == 1 {
return jen.Id(path)
func getFuncCodeFromPath(path string) (*jen.Statement, error) {
parts := regexFunctionCall.FindStringSubmatch(path)
// we have a total of four groups in the regular expression so if
// we do not have four parts, then we cannot handle the reference expression
// Examples paths are:
// github.com/upbound/upjet/pkg/resource.ExtractParamPath("a.b.c",true)
// ExtractParamPath("a.b.c",true)
// ExtractParamPath("a", false)
// ExtractParamPath()
if len(parts) != 4 {
return nil, errors.Errorf("path %q is not a valid function code", path)
}
name := words[len(words)-1]
pkg := strings.TrimSuffix(path, "."+words[len(words)-1])
return jen.Qual(pkg, name)
if len(parts[1]) == 0 {
return jen.Id(parts[3]), nil
}
return jen.Qual(parts[2], parts[3]), nil
}
4 changes: 3 additions & 1 deletion internal/method/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
"go/types"
"strings"

"github.com/pkg/errors"

xptypes "github.com/crossplane/crossplane-tools/internal/types"

"github.com/dave/jennifer/jen"
Expand All @@ -42,7 +44,7 @@ func NewResolveReferences(traverser *xptypes.Traverser, receiver, clientPath, re
Named: xptypes.NamedProcessorChain{},
}
if err := traverser.Traverse(n, cfg); err != nil {
panic(fmt.Sprintf("cannot traverse the type tree of %s", n.Obj().Name()))
panic(errors.Wrapf(err, "cannot traverse the type tree of %s", n.Obj().Name()))
}
refs := refProcessor.GetReferences()
if len(refs) == 0 {
Expand Down
62 changes: 61 additions & 1 deletion internal/method/resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ type ModelParameters struct {
// +crossplane:generate:reference:extractor=github.com/crossplane/provider-aws/apis/identity/v1beta1.IAMRoleARN()
IAMRoleARN *string
// +crossplane:generate:reference:type=github.com/crossplane/provider-aws/apis/identity/v1beta1.IAM
// +crossplane:generate:reference:extractor=github.com/crossplane/provider-aws/apis/identity/v1beta1.IAMRoleARN("a.b.c")
NestedTargetWithPath *string
// +crossplane:generate:reference:type=github.com/crossplane/provider-aws/apis/identity/v1beta1.IAM
// +crossplane:generate:reference:extractor=IAMRoleARN("a.b.c")
NestedTargetNoPath *string
// +crossplane:generate:reference:type=github.com/crossplane/provider-aws/apis/identity/v1beta1.IAM
// +crossplane:generate:reference:extractor=IAMRoleARN()
NoArgNoPath *string
Network *NetworkSpec
OtherSetting []OtherSpec
Expand Down Expand Up @@ -156,6 +168,54 @@ func (mg *Model) ResolveReferences(ctx context.Context, c client.Reader) error {
mg.Spec.ForProvider.IAMRoleARN = reference.ToPtrValue(rsp.ResolvedValue)
mg.Spec.ForProvider.IAMRoleARNRef = rsp.ResolvedReference
rsp, err = r.Resolve(ctx, reference.ResolutionRequest{
CurrentValue: reference.FromPtrValue(mg.Spec.ForProvider.NestedTargetWithPath),
Extract: v1beta1.IAMRoleARN("a.b.c"),
Reference: mg.Spec.ForProvider.NestedTargetWithPathRef,
Selector: mg.Spec.ForProvider.NestedTargetWithPathSelector,
To: reference.To{
List: &v1beta1.IAMList{},
Managed: &v1beta1.IAM{},
},
})
if err != nil {
return errors.Wrap(err, "mg.Spec.ForProvider.NestedTargetWithPath")
}
mg.Spec.ForProvider.NestedTargetWithPath = reference.ToPtrValue(rsp.ResolvedValue)
mg.Spec.ForProvider.NestedTargetWithPathRef = rsp.ResolvedReference
rsp, err = r.Resolve(ctx, reference.ResolutionRequest{
CurrentValue: reference.FromPtrValue(mg.Spec.ForProvider.NestedTargetNoPath),
Extract: IAMRoleARN("a.b.c"),
Reference: mg.Spec.ForProvider.NestedTargetNoPathRef,
Selector: mg.Spec.ForProvider.NestedTargetNoPathSelector,
To: reference.To{
List: &v1beta1.IAMList{},
Managed: &v1beta1.IAM{},
},
})
if err != nil {
return errors.Wrap(err, "mg.Spec.ForProvider.NestedTargetNoPath")
}
mg.Spec.ForProvider.NestedTargetNoPath = reference.ToPtrValue(rsp.ResolvedValue)
mg.Spec.ForProvider.NestedTargetNoPathRef = rsp.ResolvedReference
rsp, err = r.Resolve(ctx, reference.ResolutionRequest{
CurrentValue: reference.FromPtrValue(mg.Spec.ForProvider.NoArgNoPath),
Extract: IAMRoleARN(),
Reference: mg.Spec.ForProvider.NoArgNoPathRef,
Selector: mg.Spec.ForProvider.NoArgNoPathSelector,
To: reference.To{
List: &v1beta1.IAMList{},
Managed: &v1beta1.IAM{},
},
})
if err != nil {
return errors.Wrap(err, "mg.Spec.ForProvider.NoArgNoPath")
}
mg.Spec.ForProvider.NoArgNoPath = reference.ToPtrValue(rsp.ResolvedValue)
mg.Spec.ForProvider.NoArgNoPathRef = rsp.ResolvedReference
if mg.Spec.ForProvider.Network != nil {
rsp, err = r.Resolve(ctx, reference.ResolutionRequest{
CurrentValue: mg.Spec.ForProvider.Network.VPCID,
Expand Down Expand Up @@ -248,7 +308,7 @@ func (mg *Model) ResolveReferences(ctx context.Context, c client.Reader) error {
func TestNewResolveReferences(t *testing.T) {
exported := packagestest.Export(t, packagestest.Modules, []packagestest.Module{{
Name: "golang.org/fake",
Files: map[string]interface{}{
Files: map[string]any{
"v1alpha1/model.go": source,
},
}})
Expand Down

0 comments on commit 6bcdd63

Please sign in to comment.