diff --git a/boilerplates/be-golang/Jenkinsfile b/boilerplates/be-golang/Jenkinsfile new file mode 100644 index 0000000..c205f38 --- /dev/null +++ b/boilerplates/be-golang/Jenkinsfile @@ -0,0 +1,77 @@ +/* generated jenkins file used for building and deploying @component_id@ in projects @project_id@ */ +def final projectId = '@project_id@' +def final componentId = '@component_id@' +def final credentialsId = "${projectId}-cd-cd-user-with-password" +def sharedLibraryRepository +def dockerRegistry +node { + sharedLibraryRepository = env.SHARED_LIBRARY_REPOSITORY + dockerRegistry = env.DOCKER_REGISTRY +} + +library identifier: 'ods-library@production', retriever: modernSCM( + [$class: 'GitSCMSource', + remote: sharedLibraryRepository, + credentialsId: credentialsId]) + +/* + See readme of shared library for usage and customization + @ https://github.com/opendevstack/ods-jenkins-shared-library/blob/master/README.md + eg. to create and set your own builder slave instead of + the base slave used here - the code of the base slave can be found at + https://github.com/opendevstack/ods-core/tree/master/jenkins/slave-base + */ +odsPipeline( + image: "${dockerRegistry}/cd/jenkins-slave-golang", + projectId: projectId, + componentId: componentId, + branchToEnvironmentMapping: [ + 'master': 'test', + '*': 'dev' + ] +) { context -> + stageCheckFormat(context) + stageLint(context) + stageScanForSonarqube(context) + stageUnitTest(context) + stageBuild(context) + stageStartOpenshiftBuild(context) + stageDeployToOpenshift(context) +} + +def stageCheckFormat(def context) { + stage('Check Format') { + def unformatted = sh(script: 'gofmt -l .', returnStdout: true) + if (unformatted) { + println "Unformatted files:\n${unformatted}" + error 'All files need to be gofmt\'d. Please run: gofmt -w .' + } + } +} + +def stageLint(def context) { + stage('Lint') { + withEnv(["CGO_ENABLED=0"]) { + sh "golangci-lint run" + } + } +} + +def stageBuild(def context) { + stage('Build') { + def binary = "app_linux_amd64" + withEnv(["CGO_ENABLED=0"]) { + sh "go build -o docker/${binary}" + } + } +} + +def stageUnitTest(def context) { + stage('Unit Test') { + def gopkgs = sh(script: 'go list ./... | grep -v /vendor', returnStdout: true) + withEnv(["GOPKGS=${gopkgs}", "CGO_ENABLED=0"]) { + sh 'go test -v -cover $GOPKGS' + } + } +} + diff --git a/boilerplates/be-golang/README.md b/boilerplates/be-golang/README.md new file mode 100644 index 0000000..acc057c --- /dev/null +++ b/boilerplates/be-golang/README.md @@ -0,0 +1,44 @@ +# Backend - Go (be-golang) + +## Purpose of this quickstarter +Use this quickstarter when you want to use [Go](https://golang.org). Go is well +suited for CLI tools, network/operational related things and microservices. + +## What files / which architecture is generated? + +``` +├── Jenkinsfile - Contains Jenkins build configuration +├── README.md +├── docker - Contains Dockerfile for the build +│ └── Dockerfile +├── sonar-project.properties - SonarQube Configuration +├── main.go - Example Go file +``` + +## Frameworks used +None, except the ODS [Jenkins Shared Library](https://github.com/opendevstack/ods-jenkins-shared-library) + +## Usage - how do you start after you provisioned this quickstarter +Simply start to write Go code, e.g. by extending `main.go`. No further adjustments +should be necessary. Typically, you'd want to use Go modules: +``` +go mod init example.com/project/component +``` + +## How this quickstarter is built through Jenkins +There are six steps: + +* Check that all files are gofmt'd. +* Run SonarQube analysis. +* Run all package tests. +* Build the binary (placing it into the `docker` directory). +* Build the container image. +* Deploy. + +## Builder Slave used + +This quickstarter uses +[Golang builder slave](https://github.com/opendevstack/ods-project-quickstarters/tree/master/jenkins-slaves/golang). + +## Known limitations +N/A diff --git a/boilerplates/be-golang/files/docker/Dockerfile b/boilerplates/be-golang/files/docker/Dockerfile new file mode 100644 index 0000000..3219a37 --- /dev/null +++ b/boilerplates/be-golang/files/docker/Dockerfile @@ -0,0 +1,7 @@ +FROM alpine + +COPY app_linux_amd64 app_linux_amd64 + +EXPOSE 8080 + +CMD ["./app_linux_amd64"] diff --git a/boilerplates/be-golang/files/main.go b/boilerplates/be-golang/files/main.go new file mode 100644 index 0000000..3026800 --- /dev/null +++ b/boilerplates/be-golang/files/main.go @@ -0,0 +1,15 @@ +package main + +import ( + "fmt" + "log" + "net/http" +) + +func main() { + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "Hello, world!") + }) + + log.Fatal(http.ListenAndServe(":8080", nil)) +} diff --git a/boilerplates/be-golang/init.sh b/boilerplates/be-golang/init.sh new file mode 100755 index 0000000..63b34ec --- /dev/null +++ b/boilerplates/be-golang/init.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -eux + +# Get directory of this script +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +while [[ "$#" > 0 ]]; do case $1 in + -p=*|--project=*) PROJECT="${1#*=}";; + -p|--project) PROJECT="$2"; shift;; + + -c=*|--component=*) COMPONENT="${1#*=}";; + -c|--component) COMPONENT="$2"; shift;; + + -g=*|--group=*) GROUP="${1#*=}";; + -g|--group) GROUP="$2"; shift;; + + -t=*|--target-dir=*) TARGET_DIR="${1#*=}";; + -t|--target-dir) TARGET_DIR="$2"; shift;; + + -o=*|--owner=*) OWNER="${1#*=}";; + -o|--owner) OWNER="$2"; shift;; + + *) echo "Unknown parameter passed: $1"; exit 1;; +esac; shift; done + +cd $TARGET_DIR + +mkdir -p $COMPONENT + +cd $COMPONENT + +sudo chown -R $OWNER . + +echo "copy files from quickstart to generated project" +cp -rv $SCRIPT_DIR/files/. . + +echo "go mod init" +echo "module example.com/$PROJECT/$COMPONENT" > go.mod +echo "" >> go.mod +echo "go 1.12" >> go.mod diff --git a/boilerplates/be-golang/sonar-project.properties b/boilerplates/be-golang/sonar-project.properties new file mode 100644 index 0000000..8e4dcd6 --- /dev/null +++ b/boilerplates/be-golang/sonar-project.properties @@ -0,0 +1,14 @@ +# Project Key (required) +sonar.projectKey=@project_id@-@component_id@ + +# Project Name (optional) +sonar.projectName=@project_id@-@component_id@ + +# Comma-separated paths to directories with sources (required) +sonar.sources=. + +# change to your programming language +# sonar.language= + +# Encoding of the source files (optional but recommended as default is ASCII) +sonar.sourceEncoding=UTF-8 diff --git a/jenkins-slaves/golang/Dockerfile.rhel7 b/jenkins-slaves/golang/Dockerfile.rhel7 new file mode 100644 index 0000000..bb599d4 --- /dev/null +++ b/jenkins-slaves/golang/Dockerfile.rhel7 @@ -0,0 +1,18 @@ +FROM cd/jenkins-slave-base + +LABEL maintainer="Michael Sauter " + +ENV GO_VERSION 1.12.6 + +RUN cd /tmp && \ + curl -LO https://storage.googleapis.com/golang/go$GO_VERSION.linux-amd64.tar.gz && \ + tar -C /usr/local -xzf go$GO_VERSION.linux-amd64.tar.gz && \ + rm -f *.tar.gz && \ + cd - && \ + mkdir /go + +RUN curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b /usr/local/bin v1.17.1 + +ENV PATH $PATH:/usr/local/go/bin + +WORKDIR /go diff --git a/jenkins-slaves/golang/ocp-config/Tailorfile b/jenkins-slaves/golang/ocp-config/Tailorfile new file mode 100644 index 0000000..348493e --- /dev/null +++ b/jenkins-slaves/golang/ocp-config/Tailorfile @@ -0,0 +1,5 @@ +namespace cd +selector app=jenkins-slave-golang +param-dir ../../../../ods-configuration/ods-project-quickstarters/jenkins-slaves/golang/ocp-config + +bc,is diff --git a/jenkins-slaves/golang/ocp-config/bc.yml b/jenkins-slaves/golang/ocp-config/bc.yml new file mode 100644 index 0000000..15dd0f1 --- /dev/null +++ b/jenkins-slaves/golang/ocp-config/bc.yml @@ -0,0 +1,43 @@ +apiVersion: v1 +kind: Template +metadata: + annotations: {} + creationTimestamp: null + name: jenkins-slave-golang +objects: +- apiVersion: v1 + kind: BuildConfig + metadata: + annotations: {} + creationTimestamp: null + name: jenkins-slave-golang + labels: + app: jenkins-slave-golang + spec: + nodeSelector: null + output: + to: + kind: ImageStreamTag + name: jenkins-slave-golang:latest + postCommit: {} + resources: {} + runPolicy: Serial + source: + contextDir: jenkins-slaves/golang + git: + ref: production + uri: ${REPO_BASE}/opendevstack/ods-project-quickstarters.git + sourceSecret: + name: cd-user-token + type: Git + strategy: + dockerStrategy: + dockerfilePath: Dockerfile.rhel7 + from: + kind: ImageStreamTag + name: jenkins-slave-base:latest + type: Docker + triggers: [] +parameters: +- name: REPO_BASE + required: true diff --git a/jenkins-slaves/golang/ocp-config/is.yml b/jenkins-slaves/golang/ocp-config/is.yml new file mode 100644 index 0000000..99d04b1 --- /dev/null +++ b/jenkins-slaves/golang/ocp-config/is.yml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Template +metadata: + annotations: {} + creationTimestamp: null + name: jenkins-slave-golang +objects: +- apiVersion: v1 + kind: ImageStream + metadata: + annotations: {} + creationTimestamp: null + name: jenkins-slave-golang + labels: + app: jenkins-slave-golang + spec: + dockerImageRepository: jenkins-slave-golang + lookupPolicy: + local: false diff --git a/rundeck-jobs/common/prepare-continuous-integration.yaml b/rundeck-jobs/common/prepare-continuous-integration.yaml index 8fd4b25..c8682ca 100644 --- a/rundeck-jobs/common/prepare-continuous-integration.yaml +++ b/rundeck-jobs/common/prepare-continuous-integration.yaml @@ -21,6 +21,7 @@ - fe-ionic - fe-react - be-docker-plain + - be-golang - description: location of the generated quickstarter project name: quickstarter_directory required: true diff --git a/rundeck-jobs/quickstarts/be-golang.yaml b/rundeck-jobs/quickstarts/be-golang.yaml new file mode 100644 index 0000000..06c366b --- /dev/null +++ b/rundeck-jobs/quickstarts/be-golang.yaml @@ -0,0 +1,50 @@ +- description: A Go component + executionEnabled: true + group: quickstarts + id: f3a7717d-f51a-426c-82fe-4574d4e595ad + loglevel: INFO + name: be-golang + nodeFilterEditable: false + options: + - description: id of the project (i.e. bhw for basic hellow world) + name: project_id + required: true + - description: group id for maven style projects (i.e. org.opendevstack.bhw for bhw project) + name: group_id + - description: id of the component to create (i.e. bhw-be for bhw backend) + name: component_id + required: true + - description: git url to access target repository via http + name: git_url_http + required: true + - description: git url to access target repository via ssh + name: git_url_ssh + required: true + - description: name of the source code root package + name: package_name + - description: openshift api token to log on to open shift + name: openshift_api_token + required: true + secure: true + storagePath: keys/openshift-api-token + valueExposed: true + scheduleEnabled: true + sequence: + commands: + - exec: 'echo project_id: ${option.project_id}, component_id: ${option.component_id}, + git_url_https: ${option.git_url_https}, git_url_ssh: ${option.git_url_ssh}, + package_name: ${option.package_name}' + - description: checkout quickstart + exec: mkdir /tmp/rundeck_${job.id}_${job.execid} && cd /tmp/rundeck_${job.id}_${job.execid} && git clone ${globals.bitbucket_sshhost}/opendevstack/ods-project-quickstarters.git && cd ods-project-quickstarters && git checkout origin/production + - description: Init Go repository + exec: cd /tmp/rundeck_${job.id}_${job.execid}/ods-project-quickstarters/boilerplates/be-golang && ./init.sh --project "${option.project_id}" --component "${option.component_id}" --group "${option.group_id}" --target-dir "/tmp/rundeck_${job.id}_${job.execid}" --owner "${globals.rundeck_os_user}" + - description: setup quickstarter for continuous integration + jobref: + args: -component_type be-golang -component_id ${option.component_id} -project_id ${option.project_id} -quickstarter_directory /tmp/rundeck_${job.id}_${job.execid}/${option.component_id} -git_url_ssh ${option.git_url_ssh} -git_url_http ${option.git_url_http} + group: common + name: prepare-continuous-integration + nodeStep: 'true' + keepgoing: false + strategy: node-first + uuid: 7f98bafb-c81d-4eb0-aad1-700b6c05fc12 +