1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-14 11:03:09 +02:00
sap-jenkins-library/pkg/orchestrator/jenkins.go
ffeldmann ccc1c976ee
fix(orchestrator) usage of correct env variables (#3650)
* Reorders getApiInformation, changes variables to get start time, adjusts and adds test cases
* Changes the way to get apiInformation and reduces number of requests
* Changes getting pipeline start time from correct env variable
* Refactors getApiInformation functionality
* Adds GetBuildReason() for Azure and Jenkins
* Updates JobURL for ADO
2022-03-28 09:52:15 +02:00

232 lines
7.4 KiB
Go

package orchestrator
import (
"encoding/json"
"github.com/Jeffail/gabs/v2"
piperHttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/pkg/errors"
"io/ioutil"
"time"
)
type JenkinsConfigProvider struct {
client piperHttp.Client
options piperHttp.ClientOptions
apiInformation map[string]interface{}
}
// InitOrchestratorProvider initializes the Jenkins orchestrator with credentials
func (j *JenkinsConfigProvider) InitOrchestratorProvider(settings *OrchestratorSettings) {
j.client = piperHttp.Client{}
j.options = piperHttp.ClientOptions{
Username: settings.JenkinsUser,
Password: settings.JenkinsToken,
MaxRetries: 3,
TransportTimeout: time.Second * 10,
}
j.client.SetOptions(j.options)
log.Entry().Debug("Successfully initialized Jenkins config provider")
}
// OrchestratorVersion returns the orchestrator version currently running on
func (j *JenkinsConfigProvider) OrchestratorVersion() string {
return getEnv("JENKINS_VERSION", "n/a")
}
// OrchestratorType returns the orchestrator type Jenkins
func (j *JenkinsConfigProvider) OrchestratorType() string {
return "Jenkins"
}
func (j *JenkinsConfigProvider) fetchAPIInformation() {
if len(j.apiInformation) == 0 {
log.Entry().Debugf("apiInformation is empty, getting infos from API")
URL := j.GetBuildURL() + "api/json"
log.Entry().Debugf("API URL: %s", URL)
response, err := j.client.GetRequest(URL, nil, nil)
if err != nil {
log.Entry().WithError(err).Error("could not get API information from Jenkins")
j.apiInformation = map[string]interface{}{}
return
}
if response.StatusCode != 200 { //http.StatusNoContent
log.Entry().Errorf("Response-Code is %v, could not get timestamp from Jenkins. Setting timestamp to 1970.", response.StatusCode)
j.apiInformation = map[string]interface{}{}
return
}
err = piperHttp.ParseHTTPResponseBodyJSON(response, &j.apiInformation)
if err != nil {
log.Entry().WithError(err).Errorf("could not parse HTTP response body")
j.apiInformation = map[string]interface{}{}
return
}
log.Entry().Debugf("successfully retrieved apiInformation")
} else {
log.Entry().Debugf("apiInformation already set")
}
}
// GetBuildStatus returns build status of the current job
func (j *JenkinsConfigProvider) GetBuildStatus() string {
j.fetchAPIInformation()
if val, ok := j.apiInformation["result"]; ok {
// cases in ADO: succeeded, failed, canceled, none, partiallySucceeded
switch result := val; result {
case "SUCCESS":
return "SUCCESS"
case "ABORTED":
return "ABORTED"
default:
// FAILURE, NOT_BUILT
return "FAILURE"
}
}
return "FAILURE"
}
// GetLog returns the logfile from the current job as byte object
func (j *JenkinsConfigProvider) GetLog() ([]byte, error) {
URL := j.GetBuildURL() + "consoleText"
response, err := j.client.GetRequest(URL, nil, nil)
if err != nil {
return []byte{}, errors.Wrapf(err, "could not GET Jenkins log file %v", err)
} else if response.StatusCode != 200 {
log.Entry().Error("response code !=200 could not get log information from Jenkins, returning with empty log.")
return []byte{}, nil
}
logFile, err := ioutil.ReadAll(response.Body)
if err != nil {
return []byte{}, errors.Wrapf(err, "could not read Jenkins log file from request %v", err)
}
defer response.Body.Close()
return logFile, nil
}
// GetPipelineStartTime returns the pipeline start time in UTC
func (j *JenkinsConfigProvider) GetPipelineStartTime() time.Time {
URL := j.GetBuildURL() + "api/json"
response, err := j.client.GetRequest(URL, nil, nil)
if err != nil {
log.Entry().WithError(err).Errorf("could not getRequest to URL %s", URL)
return time.Time{}.UTC()
}
if response.StatusCode != 200 { //http.StatusNoContent -> also empty log!
log.Entry().Errorf("response code is %v . \n Could not get timestamp from Jenkins. Setting timestamp to 1970.", response.StatusCode)
return time.Time{}.UTC()
}
var responseInterface map[string]interface{}
err = piperHttp.ParseHTTPResponseBodyJSON(response, &responseInterface)
if err != nil {
log.Entry().WithError(err).Infof("could not parse http response, returning 1970")
return time.Time{}.UTC()
}
rawTimeStamp := responseInterface["timestamp"].(float64)
timeStamp := time.Unix(int64(rawTimeStamp)/1000, 0)
log.Entry().Debugf("Pipeline start time: %v", timeStamp.String())
defer response.Body.Close()
return timeStamp.UTC()
}
// GetJobName returns the job name of the current job e.g. foo/bar/BRANCH
func (j *JenkinsConfigProvider) GetJobName() string {
return getEnv("JOB_NAME", "n/a")
}
// GetJobURL returns the current job URL e.g. https://jaas.url/job/foo/job/bar/job/main
func (j *JenkinsConfigProvider) GetJobURL() string {
return getEnv("JOB_URL", "n/a")
}
// getJenkinsHome returns the jenkins home e.g. /var/lib/jenkins
func (j *JenkinsConfigProvider) getJenkinsHome() string {
return getEnv("JENKINS_HOME", "n/a")
}
// GetBuildID returns the build ID of the current job, e.g. 1234
func (j *JenkinsConfigProvider) GetBuildID() string {
return getEnv("BUILD_ID", "n/a")
}
// GetStageName returns the stage name the job is currently in, e.g. Promote
func (j *JenkinsConfigProvider) GetStageName() string {
return getEnv("STAGE_NAME", "n/a")
}
//GetBuildReason returns the build reason of the current build
func (j *JenkinsConfigProvider) GetBuildReason() string {
j.fetchAPIInformation()
marshal, err := json.Marshal(j.apiInformation)
if err != nil {
log.Entry().WithError(err).Debugf("could not marshal apiInformation")
return "Unknown"
}
jsonParsed, err := gabs.ParseJSON(marshal)
if err != nil {
log.Entry().WithError(err).Debugf("could not parse apiInformation")
return "Unknown"
}
for _, child := range jsonParsed.S("actions").Children() {
class := child.S("_class")
if class.String() == "\"hudson.model.CauseAction\"" {
for _, val := range child.S("causes").Children() {
subclass := val.S("_class")
if subclass.String() == "\"hudson.model.Cause$UserIdCause\"" {
return "Manual"
} else if subclass.String() == "\"hudson.triggers.TimerTrigger$TimerTriggerCause\"" {
return "Schedule"
} else {
return "Unknown"
}
}
}
}
return "Unknown"
}
// GetBranch returns the branch name, only works with the git plugin enabled
func (j *JenkinsConfigProvider) GetBranch() string {
return getEnv("BRANCH_NAME", "n/a")
}
// GetBuildURL returns the build url, e.g. https://jaas.url/job/foo/job/bar/job/main/1234/
func (j *JenkinsConfigProvider) GetBuildURL() string {
return getEnv("BUILD_URL", "n/a")
}
// GetCommit returns the commit SHA from the current build, only works with the git plugin enabled
func (j *JenkinsConfigProvider) GetCommit() string {
return getEnv("GIT_COMMIT", "n/a")
}
// GetRepoURL returns the repo URL of the current build, only works with the git plugin enabled
func (j *JenkinsConfigProvider) GetRepoURL() string {
return getEnv("GIT_URL", "n/a")
}
// GetPullRequestConfig returns the pull request config
func (j *JenkinsConfigProvider) GetPullRequestConfig() PullRequestConfig {
return PullRequestConfig{
Branch: getEnv("CHANGE_BRANCH", "n/a"),
Base: getEnv("CHANGE_TARGET", "n/a"),
Key: getEnv("CHANGE_ID", "n/a"),
}
}
// IsPullRequest returns boolean indicating if current job is a PR
func (j *JenkinsConfigProvider) IsPullRequest() bool {
return truthy("CHANGE_ID")
}
func isJenkins() bool {
envVars := []string{"JENKINS_HOME", "JENKINS_URL"}
return areIndicatingEnvVarsSet(envVars)
}