Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support trigger a parameterized Pipeline in PipelineRun reconciler #210

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions config/samples/devops_v1alpha4_pipelinerun_with_parameters.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
apiVersion: devops.kubesphere.io/v1alpha3
kind: DevOpsProject
metadata:
annotations:
kubesphere.io/creator: admin
name: demo-devopsproject
status:
adminNamespace: default
---
apiVersion: devops.kubesphere.io/v1alpha3
kind: Pipeline
metadata:
annotations:
kubesphere.io/creator: admin
name: demo-pipeline
namespace: default
spec:
pipeline:
disable_concurrent: true
discarder:
days_to_keep: "7"
num_to_keep: "10"
jenkinsfile: |
pipeline {
agent any

parameters {
string defaultValue: 'rick', description: 'just for testing', name: 'name', trim: true
booleanParam defaultValue: false, description: 'You can use this flag to debug your Pipeline', name: 'debug'
choice choices: ['v1.18.8', 'v1.18.9'], description: 'Please choose the target Kubernetes version', name: 'kubernetesVersion'
}

stages{
stage('simple'){
steps{
echo "My name is ${params.name}."
echo "Target Kubernetes version is " + params.kubernetesVersion

script {
if ("${params.debug}" == "true") {
echo "You can put some debug info at here."
echo "Another way to use param: " + params.name
}
}
}
}

stage('debug stage') {
when {
equals expected: true, actual: params.debug
}
steps {
echo "It's joke, there're debug info here."
}
}
}
}
name: good
type: pipeline

---
apiVersion: devops.kubesphere.io/v1alpha4
kind: PipelineRun
metadata:
name: demo-pipelinerun
namespace: default
spec:
pipelineRef:
name: demo-pipeline
parameters:
- name: "debug"
value: "true"
- name: "name"
value: "devops"
13 changes: 8 additions & 5 deletions controllers/jenkins/pipelinerun/pipelinerun_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
}

// first run
pipelineBuild, err := r.triggerJenkinsJob(devopsProjectName, pipelineName)
pipelineBuild, err := r.triggerJenkinsJob(devopsProjectName, pipelineName, &pr.Spec)
if err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please consider adding a condition for this case.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean, if an error is returned, add a condition into status.conditions, is that right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can skip this error handling since the handling won't block this PR. And I'll fire another PR to handle it. What do you reckon?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK.

log.Error(err, "unable to run pipeline", "devopsProjectName", devopsProjectName, "pipeline", pipeline.Name)
return ctrl.Result{}, err
Expand Down Expand Up @@ -165,9 +165,12 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
return ctrl.Result{RequeueAfter: 1 * time.Second}, nil
}

func (r *Reconciler) triggerJenkinsJob(projectName, pipelineName string) (*job.PipelineBuild, error) {
boClient := job.BlueOceanClient{JenkinsCore: r.JenkinsCore, Organization: ""}
return boClient.Build("jenkins", projectName, pipelineName)
func (r *Reconciler) triggerJenkinsJob(devopsProjectName, pipelineName string, prSpec *devopsv1alpha4.PipelineRunSpec) (*job.PipelineBuild, error) {
boClient := job.BlueOceanClient{JenkinsCore: r.JenkinsCore, Organization: "jenkins"}
return boClient.Build(job.BuildOption{
Pipelines: []string{devopsProjectName, pipelineName},
Parameters: parameterConverter{parameters: prSpec.Parameters}.convert(),
})
}

func (r *Reconciler) getPipelineRunResult(projectName, pipelineName string, pr *devopsv1alpha4.PipelineRun) (*job.PipelineBuild, error) {
Expand All @@ -176,7 +179,7 @@ func (r *Reconciler) getPipelineRunResult(projectName, pipelineName string, pr *
return nil, fmt.Errorf("unable to get PipelineRun result due to not found run ID")
}
boClient := job.BlueOceanClient{JenkinsCore: r.JenkinsCore, Organization: "jenkins"}
return boClient.GetBuild("jenkins", runIDStr, projectName, pipelineName)
return boClient.GetBuild(runIDStr, projectName, pipelineName)
}

func (r *Reconciler) updateLabelsAndAnnotations(ctx context.Context, pr *devopsv1alpha4.PipelineRun) error {
Expand Down
20 changes: 18 additions & 2 deletions controllers/jenkins/pipelinerun/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ type pipelineBuildApplier struct {
*job.PipelineBuild
}

func (pbApplier *pipelineBuildApplier) apply(prStatus *devopsv1alpha4.PipelineRunStatus) {
func (pbApplier pipelineBuildApplier) apply(prStatus *devopsv1alpha4.PipelineRunStatus) {
condition := devopsv1alpha4.Condition{
Type: devopsv1alpha4.ConditionReady,
Status: devopsv1alpha4.ConditionUnknown,
Expand Down Expand Up @@ -76,7 +76,7 @@ func (pbApplier *pipelineBuildApplier) apply(prStatus *devopsv1alpha4.PipelineRu
prStatus.UpdateTime = &v1.Time{Time: time.Now()}
}

func (pbApplier *pipelineBuildApplier) whenPipelineRunFinished(condition *devopsv1alpha4.Condition, prStatus *devopsv1alpha4.PipelineRunStatus) {
func (pbApplier pipelineBuildApplier) whenPipelineRunFinished(condition *devopsv1alpha4.Condition, prStatus *devopsv1alpha4.PipelineRunStatus) {
// mark as completed
if !pbApplier.EndTime.IsZero() {
prStatus.CompletionTime = &v1.Time{Time: pbApplier.EndTime.Time}
Expand Down Expand Up @@ -107,3 +107,19 @@ func (pbApplier *pipelineBuildApplier) whenPipelineRunFinished(condition *devops
prStatus.Phase = devopsv1alpha4.Failed
}
}

// parameterConverter is responsible to convert Parameter slice of PipelineRun into job.Parameter slice.
type parameterConverter struct {
parameters []devopsv1alpha4.Parameter
}

func (converter parameterConverter) convert() []job.Parameter {
var params []job.Parameter
for _, param := range converter.parameters {
params = append(params, job.Parameter{
Name: param.Name,
Value: param.Value,
})
}
return params
}
51 changes: 51 additions & 0 deletions controllers/jenkins/pipelinerun/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
devopsv1alpha4 "kubesphere.io/devops/pkg/api/devops/v1alpha4"
"reflect"
"testing"
"time"
)
Expand Down Expand Up @@ -280,3 +281,53 @@ func Test_pipelineBuildApplier_apply(t *testing.T) {
})
}
}

func Test_parameterConverter_convert(t *testing.T) {
type fields struct {
parameters []devopsv1alpha4.Parameter
}
tests := []struct {
name string
fields fields
want []job.Parameter
}{{
name: "Nil parameters",
fields: fields{
parameters: nil,
},
want: nil,
}, {
name: "Single parameter",
fields: fields{
parameters: []devopsv1alpha4.Parameter{
{Name: "fake_name", Value: "fake_value"},
},
},
want: []job.Parameter{
{Name: "fake_name", Value: "fake_value"},
},
}, {
name: "Two parameters",
fields: fields{
parameters: []devopsv1alpha4.Parameter{
{Name: "fake_name_1", Value: "fake_value_1"},
{Name: "fake_name_2", Value: "fake_value_2"},
},
},
want: []job.Parameter{
{Name: "fake_name_1", Value: "fake_value_1"},
{Name: "fake_name_2", Value: "fake_value_2"},
},
}}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
converter := parameterConverter{
parameters: tt.fields.parameters,
}
if got := converter.convert(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("convert() = %v, want %v", got, tt.want)
}
})
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ require (
github.com/golang/mock v1.6.0
github.com/google/go-cmp v0.5.5
github.com/google/go-querystring v1.1.0 // indirect
github.com/jenkins-zh/jenkins-client v0.0.2
github.com/jenkins-zh/jenkins-client v0.0.3-0.20210830140903-1ae131e1f28b
github.com/kubesphere/sonargo v0.0.2
github.com/onsi/ginkgo v1.16.4
github.com/onsi/gomega v1.15.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,8 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jenkins-zh/jenkins-cli v0.0.32/go.mod h1:uE1mH9PNITrg0sugv6HXuM/CSddg0zxXoYu3w57I3JY=
github.com/jenkins-zh/jenkins-client v0.0.2 h1:x4yHjGIkJ51n62Qybr6mz4wXWocb59UWDqRGpRJXO1A=
github.com/jenkins-zh/jenkins-client v0.0.2/go.mod h1:ICBk7OOoTafVP//f/VfKZ34c0ff8vJwVnOsF9btiMYU=
github.com/jenkins-zh/jenkins-client v0.0.3-0.20210830140903-1ae131e1f28b h1:+5d4wUkSGy/Ql5/ZBDAPjXA+Aab39V3nvw5Ec6TCHx8=
github.com/jenkins-zh/jenkins-client v0.0.3-0.20210830140903-1ae131e1f28b/go.mod h1:ICBk7OOoTafVP//f/VfKZ34c0ff8vJwVnOsF9btiMYU=
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=
Expand Down