2019-05-05 22:00:45 +00:00
// Copyright 2019 Sorint.lab
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied
// See the License for the specific language governing permissions and
// limitations under the License.
package action
import (
"context"
2019-05-06 13:19:29 +00:00
"encoding/json"
2019-05-05 22:00:45 +00:00
"net/http"
2019-06-11 07:31:12 +00:00
"path"
2019-08-22 14:19:44 +00:00
"regexp"
2019-05-05 22:00:45 +00:00
2019-07-01 09:40:20 +00:00
"agola.io/agola/internal/config"
gitsource "agola.io/agola/internal/gitsources"
"agola.io/agola/internal/runconfig"
2022-02-24 10:18:29 +00:00
scommon "agola.io/agola/internal/services/common"
"agola.io/agola/internal/services/gateway/common"
2019-09-05 07:29:20 +00:00
itypes "agola.io/agola/internal/services/types"
2019-07-01 09:40:20 +00:00
"agola.io/agola/internal/util"
2019-07-31 13:39:07 +00:00
cstypes "agola.io/agola/services/configstore/types"
rsapitypes "agola.io/agola/services/runservice/api/types"
rstypes "agola.io/agola/services/runservice/types"
2019-09-05 07:29:20 +00:00
"agola.io/agola/services/types"
2019-05-05 22:00:45 +00:00
2019-05-23 09:23:14 +00:00
errors "golang.org/x/xerrors"
2019-05-05 22:00:45 +00:00
)
2019-06-11 07:31:12 +00:00
const (
defaultSSHPort = "22"
2020-03-04 12:08:56 +00:00
agolaDefaultConfigDir = ".agola"
agolaDefaultStarlarkConfigFile = "config.star"
agolaDefaultJsonnetConfigFile = "config.jsonnet"
agolaDefaultJsonConfigFile = "config.json"
agolaDefaultYamlConfigFile = "config.yml"
2019-06-11 07:31:12 +00:00
// List of runs annotations
AnnotationRunType = "run_type"
AnnotationRefType = "ref_type"
AnnotationProjectID = "projectid"
AnnotationUserID = "userid"
AnnotationRunCreationTrigger = "run_creation_trigger"
AnnotationWebhookEvent = "webhook_event"
AnnotationWebhookSender = "webhook_sender"
AnnotationCommitSHA = "commit_sha"
AnnotationRef = "ref"
AnnotationMessage = "message"
AnnotationCommitLink = "commit_link"
AnnotationCompareLink = "compare_link"
AnnotationBranch = "branch"
AnnotationBranchLink = "branch_link"
AnnotationTag = "tag"
AnnotationTagLink = "tag_link"
AnnotationPullRequestID = "pull_request_id"
AnnotationPullRequestLink = "pull_request_link"
)
2019-08-22 14:19:44 +00:00
var (
2019-10-24 08:58:57 +00:00
SkipRunMessage = regexp . MustCompile ( ` .*\[ci skip\].* ` )
2019-08-22 14:19:44 +00:00
)
2019-07-31 13:39:07 +00:00
func ( h * ActionHandler ) GetRun ( ctx context . Context , runID string ) ( * rsapitypes . RunResponse , error ) {
2022-02-21 11:19:55 +00:00
runResp , _ , err := h . runserviceClient . GetRun ( ctx , runID , nil )
2019-05-05 22:00:45 +00:00
if err != nil {
2022-02-21 11:19:55 +00:00
return nil , util . NewAPIError ( util . KindFromRemoteError ( err ) , err )
2019-05-05 22:00:45 +00:00
}
2019-05-03 21:19:23 +00:00
canGetRun , err := h . CanGetRun ( ctx , runResp . RunConfig . Group )
if err != nil {
2019-05-23 09:23:14 +00:00
return nil , errors . Errorf ( "failed to determine permissions: %w" , err )
2019-05-03 21:19:23 +00:00
}
if ! canGetRun {
2022-02-21 11:19:55 +00:00
return nil , util . NewAPIError ( util . ErrForbidden , errors . Errorf ( "user not authorized" ) )
2019-05-03 21:19:23 +00:00
}
2019-05-05 22:00:45 +00:00
return runResp , nil
}
type GetRunsRequest struct {
PhaseFilter [ ] string
2019-07-05 08:32:51 +00:00
ResultFilter [ ] string
2019-05-03 21:19:23 +00:00
Group string
2019-05-05 22:00:45 +00:00
LastRun bool
ChangeGroups [ ] string
StartRunID string
Limit int
Asc bool
}
2019-07-31 13:39:07 +00:00
func ( h * ActionHandler ) GetRuns ( ctx context . Context , req * GetRunsRequest ) ( * rsapitypes . GetRunsResponse , error ) {
2019-05-03 21:19:23 +00:00
canGetRun , err := h . CanGetRun ( ctx , req . Group )
if err != nil {
2019-05-23 09:23:14 +00:00
return nil , errors . Errorf ( "failed to determine permissions: %w" , err )
2019-05-03 21:19:23 +00:00
}
if ! canGetRun {
2022-02-21 11:19:55 +00:00
return nil , util . NewAPIError ( util . ErrForbidden , errors . Errorf ( "user not authorized" ) )
2019-05-03 21:19:23 +00:00
}
groups := [ ] string { req . Group }
2022-02-21 11:19:55 +00:00
runsResp , _ , err := h . runserviceClient . GetRuns ( ctx , req . PhaseFilter , req . ResultFilter , groups , req . LastRun , req . ChangeGroups , req . StartRunID , req . Limit , req . Asc )
2019-05-05 22:00:45 +00:00
if err != nil {
2022-02-21 11:19:55 +00:00
return nil , util . NewAPIError ( util . KindFromRemoteError ( err ) , err )
2019-05-05 22:00:45 +00:00
}
return runsResp , nil
}
type GetLogsRequest struct {
RunID string
TaskID string
Setup bool
Step int
Follow bool
}
func ( h * ActionHandler ) GetLogs ( ctx context . Context , req * GetLogsRequest ) ( * http . Response , error ) {
2022-02-21 11:19:55 +00:00
runResp , _ , err := h . runserviceClient . GetRun ( ctx , req . RunID , nil )
2019-05-03 21:19:23 +00:00
if err != nil {
2022-02-21 11:19:55 +00:00
return nil , util . NewAPIError ( util . KindFromRemoteError ( err ) , err )
2019-05-03 21:19:23 +00:00
}
canGetRun , err := h . CanGetRun ( ctx , runResp . RunConfig . Group )
if err != nil {
2019-05-23 09:23:14 +00:00
return nil , errors . Errorf ( "failed to determine permissions: %w" , err )
2019-05-03 21:19:23 +00:00
}
if ! canGetRun {
2022-02-21 11:19:55 +00:00
return nil , util . NewAPIError ( util . ErrForbidden , errors . Errorf ( "user not authorized" ) )
2019-05-03 21:19:23 +00:00
}
2022-02-21 11:19:55 +00:00
resp , err := h . runserviceClient . GetLogs ( ctx , req . RunID , req . TaskID , req . Setup , req . Step , req . Follow )
2019-05-05 22:00:45 +00:00
if err != nil {
2022-02-21 11:19:55 +00:00
return nil , util . NewAPIError ( util . KindFromRemoteError ( err ) , err )
2019-05-05 22:00:45 +00:00
}
return resp , nil
}
2019-11-09 10:18:00 +00:00
type DeleteLogsRequest struct {
RunID string
TaskID string
Setup bool
Step int
}
func ( h * ActionHandler ) DeleteLogs ( ctx context . Context , req * DeleteLogsRequest ) error {
2022-02-21 11:19:55 +00:00
runResp , _ , err := h . runserviceClient . GetRun ( ctx , req . RunID , nil )
2019-11-09 10:18:00 +00:00
if err != nil {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . KindFromRemoteError ( err ) , err )
2019-11-09 10:18:00 +00:00
}
canDoRunActions , err := h . CanDoRunActions ( ctx , runResp . RunConfig . Group )
if err != nil {
return errors . Errorf ( "failed to determine permissions: %w" , err )
}
if ! canDoRunActions {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrForbidden , errors . Errorf ( "user not authorized" ) )
2019-11-09 10:18:00 +00:00
}
2022-02-21 11:19:55 +00:00
if _ , err = h . runserviceClient . DeleteLogs ( ctx , req . RunID , req . TaskID , req . Setup , req . Step ) ; err != nil {
return util . NewAPIError ( util . KindFromRemoteError ( err ) , err )
2019-11-09 10:18:00 +00:00
}
return nil
}
2019-05-05 22:00:45 +00:00
type RunActionType string
const (
RunActionTypeRestart RunActionType = "restart"
2019-05-15 12:42:50 +00:00
RunActionTypeCancel RunActionType = "cancel"
2019-05-05 22:00:45 +00:00
RunActionTypeStop RunActionType = "stop"
)
type RunActionsRequest struct {
RunID string
ActionType RunActionType
// Restart
FromStart bool
}
2019-07-31 13:39:07 +00:00
func ( h * ActionHandler ) RunAction ( ctx context . Context , req * RunActionsRequest ) ( * rsapitypes . RunResponse , error ) {
2022-02-21 11:19:55 +00:00
runResp , _ , err := h . runserviceClient . GetRun ( ctx , req . RunID , nil )
2019-05-03 21:19:23 +00:00
if err != nil {
2022-02-21 11:19:55 +00:00
return nil , util . NewAPIError ( util . KindFromRemoteError ( err ) , err )
2019-05-03 21:19:23 +00:00
}
canGetRun , err := h . CanDoRunActions ( ctx , runResp . RunConfig . Group )
if err != nil {
2019-05-23 09:23:14 +00:00
return nil , errors . Errorf ( "failed to determine permissions: %w" , err )
2019-05-03 21:19:23 +00:00
}
if ! canGetRun {
2022-02-21 11:19:55 +00:00
return nil , util . NewAPIError ( util . ErrForbidden , errors . Errorf ( "user not authorized" ) )
2019-05-03 21:19:23 +00:00
}
2019-05-05 22:00:45 +00:00
switch req . ActionType {
case RunActionTypeRestart :
2019-07-31 13:39:07 +00:00
rsreq := & rsapitypes . RunCreateRequest {
2019-05-05 22:00:45 +00:00
RunID : req . RunID ,
FromStart : req . FromStart ,
}
2022-02-21 11:19:55 +00:00
runResp , _ , err = h . runserviceClient . CreateRun ( ctx , rsreq )
2019-05-05 22:00:45 +00:00
if err != nil {
2022-02-21 11:19:55 +00:00
return nil , util . NewAPIError ( util . KindFromRemoteError ( err ) , err )
2019-05-05 22:00:45 +00:00
}
2019-05-15 12:42:50 +00:00
case RunActionTypeCancel :
2019-07-31 13:39:07 +00:00
rsreq := & rsapitypes . RunActionsRequest {
ActionType : rsapitypes . RunActionTypeChangePhase ,
2019-05-15 12:42:50 +00:00
Phase : rstypes . RunPhaseCancelled ,
}
2022-02-21 11:19:55 +00:00
if _ , err = h . runserviceClient . RunActions ( ctx , req . RunID , rsreq ) ; err != nil {
return nil , util . NewAPIError ( util . KindFromRemoteError ( err ) , err )
2019-05-15 12:42:50 +00:00
}
2019-05-05 22:00:45 +00:00
case RunActionTypeStop :
2019-07-31 13:39:07 +00:00
rsreq := & rsapitypes . RunActionsRequest {
ActionType : rsapitypes . RunActionTypeStop ,
2019-05-05 22:00:45 +00:00
}
2022-02-21 11:19:55 +00:00
if _ , err = h . runserviceClient . RunActions ( ctx , req . RunID , rsreq ) ; err != nil {
return nil , util . NewAPIError ( util . KindFromRemoteError ( err ) , err )
2019-05-05 22:00:45 +00:00
}
default :
2022-02-21 11:19:55 +00:00
return nil , util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "wrong run action type %q" , req . ActionType ) )
2019-05-05 22:00:45 +00:00
}
2019-05-07 21:23:58 +00:00
return runResp , nil
2019-05-05 22:00:45 +00:00
}
type RunTaskActionType string
const (
RunTaskActionTypeApprove RunTaskActionType = "approve"
)
type RunTaskActionsRequest struct {
RunID string
TaskID string
2019-05-06 13:19:29 +00:00
ActionType RunTaskActionType
2019-05-05 22:00:45 +00:00
}
func ( h * ActionHandler ) RunTaskAction ( ctx context . Context , req * RunTaskActionsRequest ) error {
2022-02-21 11:19:55 +00:00
runResp , _ , err := h . runserviceClient . GetRun ( ctx , req . RunID , nil )
2019-05-03 21:19:23 +00:00
if err != nil {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . KindFromRemoteError ( err ) , err )
2019-05-03 21:19:23 +00:00
}
2019-05-06 13:19:29 +00:00
canDoRunAction , err := h . CanDoRunActions ( ctx , runResp . RunConfig . Group )
2019-05-03 21:19:23 +00:00
if err != nil {
2019-05-23 09:23:14 +00:00
return errors . Errorf ( "failed to determine permissions: %w" , err )
2019-05-03 21:19:23 +00:00
}
2019-05-06 13:19:29 +00:00
if ! canDoRunAction {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrForbidden , errors . Errorf ( "user not authorized" ) )
2019-05-03 21:19:23 +00:00
}
2022-02-24 10:18:29 +00:00
curUserID := common . CurrentUserID ( ctx )
2019-05-06 13:19:29 +00:00
if curUserID == "" {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "no logged in user" ) )
2019-05-06 13:19:29 +00:00
}
2019-05-03 21:19:23 +00:00
2019-05-05 22:00:45 +00:00
switch req . ActionType {
case RunTaskActionTypeApprove :
2019-05-06 13:19:29 +00:00
rt , ok := runResp . Run . Tasks [ req . TaskID ]
if ! ok {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "run %q doesn't have task %q" , req . RunID , req . TaskID ) )
2019-05-06 13:19:29 +00:00
}
approvers := [ ] string { }
annotations := map [ string ] string { }
if rt . Annotations != nil {
annotations = rt . Annotations
}
2022-02-24 10:18:29 +00:00
approversAnnotation , ok := annotations [ scommon . ApproversAnnotation ]
2019-05-06 13:19:29 +00:00
if ok {
if err := json . Unmarshal ( [ ] byte ( approversAnnotation ) , & approvers ) ; err != nil {
2019-05-23 09:23:14 +00:00
return errors . Errorf ( "failed to unmarshal run task approvers annotation: %w" , err )
2019-05-06 13:19:29 +00:00
}
}
for _ , approver := range approvers {
if approver == curUserID {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "user %q alredy approved the task" , approver ) )
2019-05-06 13:19:29 +00:00
}
}
approvers = append ( approvers , curUserID )
approversj , err := json . Marshal ( approvers )
if err != nil {
2019-05-23 09:23:14 +00:00
return errors . Errorf ( "failed to marshal run task approvers annotation: %w" , err )
2019-05-06 13:19:29 +00:00
}
2022-02-24 10:18:29 +00:00
annotations [ scommon . ApproversAnnotation ] = string ( approversj )
2019-05-06 13:19:29 +00:00
2019-07-31 13:39:07 +00:00
rsreq := & rsapitypes . RunTaskActionsRequest {
ActionType : rsapitypes . RunTaskActionTypeSetAnnotations ,
2019-05-06 13:19:29 +00:00
Annotations : annotations ,
ChangeGroupsUpdateToken : runResp . ChangeGroupsUpdateToken ,
2019-05-05 22:00:45 +00:00
}
2022-02-21 11:19:55 +00:00
if _ , err := h . runserviceClient . RunTaskActions ( ctx , req . RunID , req . TaskID , rsreq ) ; err != nil {
return util . NewAPIError ( util . KindFromRemoteError ( err ) , err )
2019-05-05 22:00:45 +00:00
}
default :
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "wrong run task action type %q" , req . ActionType ) )
2019-05-05 22:00:45 +00:00
}
return nil
}
2019-06-11 07:31:12 +00:00
type CreateRunRequest struct {
2019-09-05 07:29:20 +00:00
RunType itypes . RunType
RefType itypes . RunRefType
RunCreationTrigger itypes . RunCreationTriggerType
2019-06-11 07:31:12 +00:00
2019-07-31 13:17:54 +00:00
Project * cstypes . Project
User * cstypes . User
2019-06-11 07:31:12 +00:00
RepoPath string
GitSource gitsource . GitSource
CommitSHA string
Message string
Branch string
Tag string
Ref string
PullRequestID string
2020-01-25 11:33:53 +00:00
PRFromSameRepo bool
2019-06-11 07:31:12 +00:00
SSHPrivKey string
SSHHostKey string
SkipSSHHostKeyCheck bool
CloneURL string
WebhookEvent string
WebhookSender string
CommitLink string
BranchLink string
TagLink string
PullRequestLink string
// CompareLink is provided only when triggered by a webhook and contains the
// commit compare link
CompareLink string
2019-07-03 13:19:52 +00:00
2019-08-05 15:33:30 +00:00
// fields only used with user direct runs
2019-07-03 13:19:52 +00:00
UserRunRepoUUID string
2019-08-05 15:33:30 +00:00
Variables map [ string ] string
2019-06-11 07:31:12 +00:00
}
func ( h * ActionHandler ) CreateRuns ( ctx context . Context , req * CreateRunRequest ) error {
setupErrors := [ ] string { }
if req . CommitSHA == "" {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "empty commit SHA" ) )
2019-06-11 07:31:12 +00:00
}
if req . Message == "" {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "empty message" ) )
2019-06-11 07:31:12 +00:00
}
2022-02-24 10:18:29 +00:00
var baseGroupType scommon . GroupType
2019-06-11 07:31:12 +00:00
var baseGroupID string
2022-02-24 10:18:29 +00:00
var groupType scommon . GroupType
2019-06-11 07:31:12 +00:00
var group string
2019-09-05 07:29:20 +00:00
if req . RunType == itypes . RunTypeProject {
2022-02-24 10:18:29 +00:00
baseGroupType = scommon . GroupTypeProject
2019-06-11 07:31:12 +00:00
baseGroupID = req . Project . ID
} else {
2022-02-24 10:18:29 +00:00
baseGroupType = scommon . GroupTypeUser
2019-06-11 07:31:12 +00:00
baseGroupID = req . User . ID
}
switch req . RefType {
2019-09-05 07:29:20 +00:00
case itypes . RunRefTypeBranch :
2022-02-24 10:18:29 +00:00
groupType = scommon . GroupTypeBranch
2019-06-11 07:31:12 +00:00
group = req . Branch
2019-09-05 07:29:20 +00:00
case itypes . RunRefTypeTag :
2022-02-24 10:18:29 +00:00
groupType = scommon . GroupTypeTag
2019-06-11 07:31:12 +00:00
group = req . Tag
2019-09-05 07:29:20 +00:00
case itypes . RunRefTypePullRequest :
2022-02-24 10:18:29 +00:00
groupType = scommon . GroupTypePullRequest
2019-06-11 07:31:12 +00:00
group = req . PullRequestID
}
2022-02-24 10:18:29 +00:00
runGroup := scommon . GenRunGroup ( baseGroupType , baseGroupID , groupType , group )
2019-06-11 07:31:12 +00:00
gitURL , err := util . ParseGitURL ( req . CloneURL )
if err != nil {
return errors . Errorf ( "failed to parse clone url: %w" , err )
}
gitHost := gitURL . Hostname ( )
gitPort := gitURL . Port ( )
if gitPort == "" {
gitPort = defaultSSHPort
}
// this env vars overrides other env vars
env := map [ string ] string {
2020-03-05 15:03:26 +00:00
"CI" : "true" ,
"AGOLA_SSHPRIVKEY" : req . SSHPrivKey ,
"AGOLA_REPOSITORY_URL" : req . CloneURL ,
"AGOLA_GIT_HOST" : gitHost ,
"AGOLA_GIT_PORT" : gitPort ,
"AGOLA_GIT_BRANCH" : req . Branch ,
"AGOLA_GIT_TAG" : req . Tag ,
"AGOLA_PULL_REQUEST_ID" : req . PullRequestID ,
2020-03-05 15:31:58 +00:00
"AGOLA_GIT_REF_TYPE" : string ( req . RefType ) ,
2020-03-05 15:03:26 +00:00
"AGOLA_GIT_REF" : req . Ref ,
"AGOLA_GIT_COMMITSHA" : req . CommitSHA ,
2019-06-11 07:31:12 +00:00
}
if req . SSHHostKey != "" {
env [ "AGOLA_SSHHOSTKEY" ] = req . SSHHostKey
}
if req . SkipSSHHostKeyCheck {
env [ "AGOLA_SKIPSSHHOSTKEYCHECK" ] = "1"
}
2019-08-05 15:33:30 +00:00
var variables map [ string ] string
2019-09-05 07:29:20 +00:00
if req . RunType == itypes . RunTypeProject {
2020-01-25 11:33:53 +00:00
if req . RefType != itypes . RunRefTypePullRequest || req . PRFromSameRepo || req . Project . PassVarsToForkedPR {
var err error
variables , err = h . genRunVariables ( ctx , req )
if err != nil {
return err
}
2019-06-11 07:31:12 +00:00
}
2019-08-05 15:33:30 +00:00
} else {
variables = req . Variables
2019-06-11 07:31:12 +00:00
}
annotations := map [ string ] string {
AnnotationRunType : string ( req . RunType ) ,
AnnotationRefType : string ( req . RefType ) ,
AnnotationRunCreationTrigger : string ( req . RunCreationTrigger ) ,
AnnotationWebhookEvent : req . WebhookEvent ,
AnnotationWebhookSender : req . WebhookSender ,
AnnotationCommitSHA : req . CommitSHA ,
AnnotationRef : req . Ref ,
AnnotationMessage : req . Message ,
AnnotationCommitLink : req . CommitLink ,
AnnotationCompareLink : req . CompareLink ,
}
2019-09-05 07:29:20 +00:00
if req . RunType == itypes . RunTypeProject {
2019-06-11 07:31:12 +00:00
annotations [ AnnotationProjectID ] = req . Project . ID
} else {
annotations [ AnnotationUserID ] = req . User . ID
}
if req . Branch != "" {
annotations [ AnnotationBranch ] = req . Branch
annotations [ AnnotationBranchLink ] = req . BranchLink
}
if req . Tag != "" {
annotations [ AnnotationTag ] = req . Tag
annotations [ AnnotationTagLink ] = req . TagLink
}
if req . PullRequestID != "" {
annotations [ AnnotationPullRequestID ] = req . PullRequestID
annotations [ AnnotationPullRequestLink ] = req . PullRequestLink
}
2019-07-03 13:19:52 +00:00
// Since user belong to the same group (the user uuid) we needed another way to differentiate the cache. We'll use the user uuid + the user run repo uuid
var cacheGroup string
2019-09-05 07:29:20 +00:00
if req . RunType == itypes . RunTypeUser {
2019-07-03 13:19:52 +00:00
cacheGroup = req . User . ID + "-" + req . UserRunRepoUUID
}
2019-07-25 13:55:52 +00:00
data , filename , err := h . fetchConfigFiles ( ctx , req . GitSource , req . RepoPath , req . CommitSHA )
2019-06-11 07:31:12 +00:00
if err != nil {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrInternal , errors . Errorf ( "failed to fetch config file: %w" , err ) )
2019-06-11 07:31:12 +00:00
}
h . log . Debug ( "data: %s" , data )
var configFormat config . ConfigFormat
switch path . Ext ( filename ) {
2020-03-04 12:08:56 +00:00
case ".star" :
configFormat = config . ConfigFormatStarlark
2019-06-11 07:31:12 +00:00
case ".jsonnet" :
configFormat = config . ConfigFormatJsonnet
case ".json" :
fallthrough
case ".yml" :
configFormat = config . ConfigFormatJSON
}
2019-10-14 14:36:46 +00:00
configContext := & config . ConfigContext {
RefType : req . RefType ,
Ref : req . Ref ,
Branch : req . Branch ,
Tag : req . Tag ,
PullRequestID : req . PullRequestID ,
CommitSHA : req . CommitSHA ,
}
config , err := config . ParseConfig ( [ ] byte ( data ) , configFormat , configContext )
2019-06-11 07:31:12 +00:00
if err != nil {
h . log . Errorf ( "failed to parse config: %+v" , err )
// create a run (per config file) with a generic error since we cannot parse
// it and know how many runs are defined
setupErrors = append ( setupErrors , err . Error ( ) )
2019-07-31 13:39:07 +00:00
createRunReq := & rsapitypes . RunCreateRequest {
2019-06-11 07:31:12 +00:00
RunConfigTasks : nil ,
Group : runGroup ,
SetupErrors : setupErrors ,
Name : rstypes . RunGenericSetupErrorName ,
StaticEnvironment : env ,
Annotations : annotations ,
}
if _ , _ , err := h . runserviceClient . CreateRun ( ctx , createRunReq ) ; err != nil {
h . log . Errorf ( "failed to create run: %+v" , err )
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . KindFromRemoteError ( err ) , err )
2019-06-11 07:31:12 +00:00
}
return nil
}
for _ , run := range config . Runs {
2019-08-22 14:19:44 +00:00
if SkipRunMessage . MatchString ( req . Message ) {
h . log . Debugf ( "skipping run since special commit message" )
continue
}
2019-10-14 14:51:54 +00:00
if match := types . MatchWhen ( run . When . ToWhen ( ) , req . RefType , req . Branch , req . Tag , req . Ref ) ; ! match {
2019-08-01 16:16:34 +00:00
h . log . Debugf ( "skipping run since when condition doesn't match" )
continue
}
2019-10-14 14:51:54 +00:00
rcts := runconfig . GenRunConfigTasks ( util . DefaultUUIDGenerator { } , config , run . Name , variables , req . RefType , req . Branch , req . Tag , req . Ref )
2019-06-11 07:31:12 +00:00
2019-07-31 13:39:07 +00:00
createRunReq := & rsapitypes . RunCreateRequest {
2019-06-11 07:31:12 +00:00
RunConfigTasks : rcts ,
Group : runGroup ,
SetupErrors : setupErrors ,
Name : run . Name ,
StaticEnvironment : env ,
Annotations : annotations ,
2019-07-03 13:19:52 +00:00
CacheGroup : cacheGroup ,
2019-06-11 07:31:12 +00:00
}
if _ , _ , err := h . runserviceClient . CreateRun ( ctx , createRunReq ) ; err != nil {
h . log . Errorf ( "failed to create run: %+v" , err )
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . KindFromRemoteError ( err ) , err )
2019-06-11 07:31:12 +00:00
}
}
return nil
}
2019-07-25 13:55:52 +00:00
func ( h * ActionHandler ) fetchConfigFiles ( ctx context . Context , gitSource gitsource . GitSource , repopath , commitSHA string ) ( [ ] byte , string , error ) {
2019-06-11 07:31:12 +00:00
var data [ ] byte
var filename string
2019-07-25 13:55:52 +00:00
err := util . ExponentialBackoff ( ctx , util . FetchFileBackoff , func ( ) ( bool , error ) {
2020-03-04 12:08:56 +00:00
for _ , filename = range [ ] string { agolaDefaultStarlarkConfigFile , agolaDefaultJsonnetConfigFile , agolaDefaultJsonConfigFile , agolaDefaultYamlConfigFile } {
2019-06-11 07:31:12 +00:00
var err error
data , err = gitSource . GetFile ( repopath , commitSHA , path . Join ( agolaDefaultConfigDir , filename ) )
if err == nil {
return true , nil
}
h . log . Errorf ( "get file err: %v" , err )
}
return false , nil
} )
if err != nil {
return nil , "" , err
}
return data , filename , nil
}
func ( h * ActionHandler ) genRunVariables ( ctx context . Context , req * CreateRunRequest ) ( map [ string ] string , error ) {
variables := map [ string ] string { }
// get project variables
pvars , _ , err := h . configstoreClient . GetProjectVariables ( ctx , req . Project . ID , true )
if err != nil {
return nil , errors . Errorf ( "failed to get project variables: %w" , err )
}
// remove overriden variables
2022-02-24 10:18:29 +00:00
pvars = scommon . FilterOverriddenVariables ( pvars )
2019-06-11 07:31:12 +00:00
// get project secrets
secrets , _ , err := h . configstoreClient . GetProjectSecrets ( ctx , req . Project . ID , true )
if err != nil {
return nil , errors . Errorf ( "failed to get project secrets: %w" , err )
}
for _ , pvar := range pvars {
// find the value match
2019-07-31 13:17:54 +00:00
var varval cstypes . VariableValue
2019-06-11 07:31:12 +00:00
for _ , varval = range pvar . Values {
2019-10-14 14:51:54 +00:00
match := types . MatchWhen ( varval . When , req . RefType , req . Branch , req . Tag , req . Ref )
2019-06-11 07:31:12 +00:00
if ! match {
continue
}
// get the secret value referenced by the variable, it must be a secret at the same level or a lower level
2022-02-24 10:18:29 +00:00
secret := scommon . GetVarValueMatchingSecret ( varval , pvar . ParentPath , secrets )
2019-06-11 07:31:12 +00:00
if secret != nil {
varValue , ok := secret . Data [ varval . SecretVar ]
if ok {
variables [ pvar . Name ] = varValue
}
}
break
}
}
return variables , nil
}