Repository: kubesphere/ks-devops
Pull request #813 (2022-09-05 05:14:58)

Fix nil pointer issue when building helmchart
<!-- Thanks for sending a pull request! Here are some tips for you:

1. If you want **faster** PR reviews, read how: https://github.com/kubesphere/community/blob/master/developer-guide/development/the-pr-author-guide-to-getting-through-code-review.md
2. In case you want to know how your PR got reviewed, read: https://github.com/kubesphere/community/blob/master/developer-guide/development/code-review-guide.md
3. Here are some coding conventions followed by the KubeSphere community: https://github.com/kubesphere/community/blob/master/developer-guide/development/coding-conventions.md
4. Additional open-source best practice: https://github.com/LinuxSuRen/open-source-best-practice
-->

### What type of PR is this?

/kind bug

### What this PR does / why we need it:

We should provide the nil pointer check and set a default value (10m0s) to the HelmChart's Interval field.

### Which issue(s) this PR fixes:
<!--
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_*
Please leave it or change # to be None if there is no corresponding issue that exists
-->
Fixes #

### Special notes for reviewers:
<!--
You can use the following command to let the DevOps SIG members help you to review your PR.
/cc @kubesphere/sig-devops 
And please avoid cc any individual.
-->
Please check the following list before waiting reviewers:

- [ ] Already committed the CRD files to [the Helm Chart](https://github.com/kubesphere-sigs/ks-devops-helm-chart/) if you created some new CRDs
- [ ] Already [added the permission](https://github.com/kubesphere/ks-installer/blob/9e063b085a0e43fdb3d0d9e3e7f4149146f14b9c/roles/ks-core/prepare/files/ks-init/role-templates.yaml) for the new API
- [ ] Already added the RBAC markers for the new controllers

### Does this PR introduce a user-facing change??
<!--
If no, just write "None" in the release-note block below.
If yes, a release note is required:
Enter your extended-release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".

Please keep the note be same as your PR title if you believe it should be in the release notes.
-->
```release-note
None
```


ks-ci-bot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by:
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **linuxsuren** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @linuxsuren` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubesphere%2Fks-devops).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/kubesphere/ks-devops/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["linuxsuren"]} -->
codecov[bot]: # [Codecov](https://codecov.io/gh/kubesphere/ks-devops/pull/813?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere) Report
> Merging [#813](https://codecov.io/gh/kubesphere/ks-devops/pull/813?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere) (242a90f) into [master](https://codecov.io/gh/kubesphere/ks-devops/commit/625e29c72d3788b908a45d06692bb9c83b9d0689?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere) (625e29c) will **increase** coverage by `0.01%`.
> The diff coverage is `100.00%`.

```diff
@@            Coverage Diff             @@
##           master     #813      +/-   ##
==========================================
+ Coverage   56.29%   56.30%   +0.01%     
==========================================
  Files         183      183              
  Lines       10916    10919       +3     
==========================================
+ Hits         6145     6148       +3     
  Misses       4403     4403              
  Partials      368      368              
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `56.30% <100.00%> (+0.01%)` | :arrow_up: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/kubesphere/ks-devops/pull/813?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere) | Coverage Δ | |
|---|---|---|
| [controllers/fluxcd/application-controller.go](https://codecov.io/gh/kubesphere/ks-devops/pull/813/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-Y29udHJvbGxlcnMvZmx1eGNkL2FwcGxpY2F0aW9uLWNvbnRyb2xsZXIuZ28=) | `84.26% <100.00%> (+0.15%)` | :arrow_up: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere)


Patch:
diff --git a/controllers/fluxcd/application-controller.go b/controllers/fluxcd/application-controller.go
index e7780d0..4ff1eec 100644
--- a/controllers/fluxcd/application-controller.go
+++ b/controllers/fluxcd/application-controller.go
@@ -33,6 +33,7 @@ import (
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/manager"
+	"time"
 )
 
 //+kubebuilder:rbac:groups=gitops.kubesphere.io,resources=applications,verbs=watch;get;list
@@ -396,7 +397,7 @@ func buildTemplateFromApp(fluxApp *v1alpha1.FluxApplication) (*sourcev1.HelmChar
 			},
 			Chart:             c.Chart,
 			Version:           c.Version,
-			Interval:          *c.Interval,
+			Interval:          convertInterval(c.Interval),
 			ReconcileStrategy: c.ReconcileStrategy,
 			ValuesFiles:       c.ValuesFiles,
 		},
@@ -492,6 +493,13 @@ func convertKubeconfig(kubeconfig *helmv2.KubeConfig) *kusv1.KubeConfig {
 	return &kusv1.KubeConfig{SecretRef: kubeconfig.SecretRef}
 }
 
+func convertInterval(interval *metav1.Duration) metav1.Duration {
+	if interval == nil {
+		return metav1.Duration{Duration: 10 * time.Minute}
+	}
+	return *interval
+}
+
 func checkFluxApp(fluxApp *v1alpha1.FluxApplication) (err error) {
 	if fluxApp.Spec.Config == nil {
 		return fmt.Errorf("should provide FluxApplication Configuration (HelmRelease or Kustomization)")
diff --git a/go.mod b/go.mod
index 2dbca1f..740b02d 100644
--- a/go.mod
+++ b/go.mod
@@ -20,8 +20,8 @@ require (
 	github.com/google/go-cmp v0.5.5
 	github.com/h2non/gock v1.0.9
 	github.com/jenkins-x/go-scm v1.11.19
-	github.com/jenkins-zh/jenkins-client v0.0.14-0.20220902054515-a6af553a94b4
-	github.com/jenkins-zh/jenkins-client/pkg/k8s v0.0.0-20220811083317-bb6f87a3f866
+	github.com/jenkins-zh/jenkins-client v0.0.14-0.20220905100332-0c9041a612a1
+	github.com/jenkins-zh/jenkins-client/pkg/k8s v0.0.0-20220905100332-0c9041a612a1
 	github.com/kubesphere/sonargo v0.0.2
 	github.com/onsi/ginkgo v1.16.5
 	github.com/onsi/gomega v1.18.1
@@ -133,9 +133,4 @@ require (
 	sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
 )
 
-replace (
-	github.com/golang/example => github.com/golang/example v0.0.0-20170904185048-46695d81d1fa
-	github.com/googleapis/gnostic => github.com/googleapis/gnostic v0.4.0
-	github.com/kubesphere/sonargo => github.com/kubesphere/sonargo v0.0.2
-	golang.org/x/text => golang.org/x/text v0.3.7
-)
+replace github.com/googleapis/gnostic => github.com/googleapis/gnostic v0.4.0
diff --git a/go.sum b/go.sum
index defc357..d10c5c5 100644
--- a/go.sum
+++ b/go.sum
@@ -389,10 +389,11 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i
 github.com/jenkins-x/go-scm v1.11.19 h1:H4CzaM/C/0QcCVLDh603Q6Bv4hqU4G3De2yQntWubqg=
 github.com/jenkins-x/go-scm v1.11.19/go.mod h1:eIcty4+tf6E7ycGOg0cUqnaLP+1LH1Z8zncQFQqRa3E=
 github.com/jenkins-zh/jenkins-cli v0.0.32/go.mod h1:uE1mH9PNITrg0sugv6HXuM/CSddg0zxXoYu3w57I3JY=
-github.com/jenkins-zh/jenkins-client v0.0.14-0.20220902054515-a6af553a94b4 h1:OkOUTuHOxW6awhNNzUAAVz1NoZ/RA+xb4VXCkrVDQgU=
-github.com/jenkins-zh/jenkins-client v0.0.14-0.20220902054515-a6af553a94b4/go.mod h1:T8M/g0p7jjx0NBwN6gNqsAAmT1P3B70GBBJJgsX9kLw=
-github.com/jenkins-zh/jenkins-client/pkg/k8s v0.0.0-20220811083317-bb6f87a3f866 h1:MQwSe0z1hju5X9c5BEfQAvkb4Fub1ZoHLo+ZLJ7mAyo=
-github.com/jenkins-zh/jenkins-client/pkg/k8s v0.0.0-20220811083317-bb6f87a3f866/go.mod h1:zetE8JfNmxkot7OCNXJyS/QwxFnfcUFzrs/jg4U2gAw=
+github.com/jenkins-zh/jenkins-client v0.0.13/go.mod h1:ICBk7OOoTafVP//f/VfKZ34c0ff8vJwVnOsF9btiMYU=
+github.com/jenkins-zh/jenkins-client v0.0.14-0.20220905100332-0c9041a612a1 h1:FqiUegQ9pu3n4l7KtvX6uOBg6dV4BndXUkJeuDT896c=
+github.com/jenkins-zh/jenkins-client v0.0.14-0.20220905100332-0c9041a612a1/go.mod h1:T8M/g0p7jjx0NBwN6gNqsAAmT1P3B70GBBJJgsX9kLw=
+github.com/jenkins-zh/jenkins-client/pkg/k8s v0.0.0-20220905100332-0c9041a612a1 h1:ZfmezrO6f1VCUeP+f7skW6U11a5NmdIiFU6giMDqjB0=
+github.com/jenkins-zh/jenkins-client/pkg/k8s v0.0.0-20220905100332-0c9041a612a1/go.mod h1:Gfq/TcOliP3fB+kNBpv/Hrx8XGt0Bz0VPJ7BxdY/u2U=
 github.com/jenkins-zh/jenkins-formulas v0.0.5/go.mod h1:zS8fm8u5L6FcjZM0QznXsLV9T2UtSVK+hT6Sm76iUZ4=
 github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
 github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
@@ -929,6 +930,15 @@ golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=


Test patch:
diff --git a/controllers/fluxcd/application-controller_test.go b/controllers/fluxcd/application-controller_test.go
index ce01669..3cf84a9 100644
--- a/controllers/fluxcd/application-controller_test.go
+++ b/controllers/fluxcd/application-controller_test.go
@@ -402,6 +402,9 @@ func TestApplicationReconciler_reconcileApp(t *testing.T) {
 	helmAppWithTemplate.Spec.FluxApp.Spec.Config.HelmRelease.Chart = nil
 	helmAppWithTemplate.Spec.FluxApp.Spec.Config.HelmRelease.Template = "fake-app"
 
+	helmAppWithNoInterval := helmAppWithLabel.DeepCopy()
+	helmAppWithNoInterval.Spec.FluxApp.Spec.Config.HelmRelease.Chart.Interval = nil
+
 	kusApp := &v1alpha1.Application{
 		ObjectMeta: metav1.ObjectMeta{
 			Namespace: "fake-ns",
@@ -621,6 +624,36 @@ func TestApplicationReconciler_reconcileApp(t *testing.T) {
 				assert.Equal(t, "./helm-chart/values.yaml", chartValueFiles[0])
 			},
 		},
+		{
+			name: "create the Multi-Clusters FluxApp(HelmRelease) but with no Interval for HelmChart",
+			fields: fields{
+				Client: fake.NewFakeClientWithScheme(schema),
+			},
+			args: args{
+				app: helmAppWithNoInterval.DeepCopy(),
+			},
+			verify: func(t *testing.T, Client client.Client, err error) {
+				assert.Nil(t, err)
+				ctx := context.Background()
+				appNS, appName := helmApp.GetNamespace(), helmApp.GetName()
+
+				fluxChart := &sourcev1.HelmChart{}
+				err = Client.Get(ctx, types.NamespacedName{Namespace: appNS, Name: appName}, fluxChart)
+				assert.Nil(t, err)
+
+				assert.Equal(t, "source.toolkit.fluxcd.io/v1beta2", fluxChart.Spec.SourceRef.APIVersion)
+				assert.Equal(t, "GitRepository", fluxChart.Spec.SourceRef.Kind)
+				assert.Equal(t, "fake-repo", fluxChart.Spec.SourceRef.Name)
+				assert.Equal(t, "./helm-chart", fluxChart.Spec.Chart)
+				assert.Equal(t, "0.1.0", fluxChart.Spec.Version)
+				// The default interval is 10m0s
+				assert.Equal(t, 10*time.Minute, fluxChart.Spec.Interval.Duration)
+				assert.Equal(t, "Revision", fluxChart.Spec.ReconcileStrategy)
+				chartValueFiles := fluxChart.Spec.ValuesFiles
+				assert.Equal(t, 1, len(chartValueFiles))
+				assert.Equal(t, "./helm-chart/values.yaml", chartValueFiles[0])
+			},
+		},
 		{
 			name: "update the Multi-Clusters FluxApp(HelmRelease)",
 			fields: fields{
@@ -940,6 +973,31 @@ func TestApplicationReconciler_convertKubeconfig(t *testing.T) {
 	}
 }
 
+func TestApplicationReconciler_convertInterval(t *testing.T) {
+	tests := []struct {
+		name   string
+		args   *metav1.Duration
+		expect metav1.Duration
+	}{
+		{
+			name:   "did not set interval",
+			args:   nil,
+			expect: metav1.Duration{Duration: 10 * time.Minute},
+		},
+		{
+			name:   "set interval",
+			args:   &metav1.Duration{Duration: 5 * time.Minute},
+			expect: metav1.Duration{Duration: 5 * time.Minute},
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			assert.Equal(t, tt.expect.Duration, convertInterval(tt.args).Duration)
+		})
+	}
+}
+
 func TestApplicationReconciler_SetupWithManager(t *testing.T) {
 	schema, err := v1alpha1.SchemeBuilder.Register().Build()
 	assert.Nil(t, err)