github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/web/elm/src/Concourse.elm (about)

     1  module Concourse exposing
     2      ( AuthSession
     3      , AuthToken
     4      , Build
     5      , BuildDuration
     6      , BuildId
     7      , BuildName
     8      , BuildPlan
     9      , BuildPrep
    10      , BuildPrepStatus(..)
    11      , BuildResources
    12      , BuildResourcesInput
    13      , BuildResourcesOutput
    14      , BuildStep(..)
    15      , CSRFToken
    16      , Cause
    17      , ClusterInfo
    18      , DatabaseID
    19      , HookedPlan
    20      , Job
    21      , JobBuildIdentifier
    22      , JobIdentifier
    23      , JobInput
    24      , JobName
    25      , JobOutput
    26      , JsonValue(..)
    27      , Metadata
    28      , MetadataField
    29      , Pipeline
    30      , PipelineGroup
    31      , PipelineIdentifier
    32      , PipelineName
    33      , Resource
    34      , ResourceIdentifier
    35      , Team
    36      , TeamName
    37      , User
    38      , Version
    39      , VersionedResource
    40      , VersionedResourceIdentifier
    41      , csrfTokenHeaderName
    42      , customDecoder
    43      , decodeAuthToken
    44      , decodeBuild
    45      , decodeBuildPlan
    46      , decodeBuildPlanResponse
    47      , decodeBuildPrep
    48      , decodeBuildResources
    49      , decodeCause
    50      , decodeInfo
    51      , decodeJob
    52      , decodeMetadata
    53      , decodePipeline
    54      , decodeResource
    55      , decodeTeam
    56      , decodeUser
    57      , decodeVersion
    58      , decodeVersionedResource
    59      , emptyBuildResources
    60      , encodeBuild
    61      , encodeJob
    62      , encodePipeline
    63      , encodeResource
    64      , encodeTeam
    65      , mapBuildPlan
    66      , retrieveCSRFToken
    67      )
    68  
    69  import Array exposing (Array)
    70  import Concourse.BuildStatus exposing (BuildStatus)
    71  import Dict exposing (Dict)
    72  import Json.Decode
    73  import Json.Decode.Extra exposing (andMap)
    74  import Json.Encode
    75  import Json.Encode.Extra
    76  import Time
    77  
    78  
    79  
    80  -- AuthToken
    81  
    82  
    83  type alias AuthToken =
    84      String
    85  
    86  
    87  type alias DatabaseID =
    88      Int
    89  
    90  
    91  decodeAuthToken : Json.Decode.Decoder AuthToken
    92  decodeAuthToken =
    93      customDecoder
    94          (Json.Decode.succeed (\a b -> ( a, b ))
    95              |> andMap (Json.Decode.field "type" Json.Decode.string)
    96              |> andMap (Json.Decode.field "value" Json.Decode.string)
    97          )
    98          authTokenFromTuple
    99  
   100  
   101  authTokenFromTuple : ( String, String ) -> Result Json.Decode.Error AuthToken
   102  authTokenFromTuple ( t, token ) =
   103      case t of
   104          "Bearer" ->
   105              Ok token
   106  
   107          _ ->
   108              Err <| Json.Decode.Failure "unknown token type" <| Json.Encode.string token
   109  
   110  
   111  
   112  -- CSRF token
   113  
   114  
   115  type alias CSRFToken =
   116      String
   117  
   118  
   119  csrfTokenHeaderName : String
   120  csrfTokenHeaderName =
   121      "X-Csrf-Token"
   122  
   123  
   124  retrieveCSRFToken : Dict String String -> Result String CSRFToken
   125  retrieveCSRFToken headers =
   126      Dict.get (String.toLower csrfTokenHeaderName) (keysToLower headers) |> Result.fromMaybe "error CSRFToken not found"
   127  
   128  
   129  keysToLower : Dict String a -> Dict String a
   130  keysToLower =
   131      Dict.fromList << List.map fstToLower << Dict.toList
   132  
   133  
   134  fstToLower : ( String, a ) -> ( String, a )
   135  fstToLower ( x, y ) =
   136      ( String.toLower x, y )
   137  
   138  
   139  type alias AuthSession =
   140      { authToken : AuthToken
   141      , csrfToken : CSRFToken
   142      }
   143  
   144  
   145  
   146  -- Build
   147  
   148  
   149  type alias BuildId =
   150      Int
   151  
   152  
   153  type alias BuildName =
   154      String
   155  
   156  
   157  type alias JobBuildIdentifier =
   158      { teamName : TeamName
   159      , pipelineName : PipelineName
   160      , jobName : JobName
   161      , buildName : BuildName
   162      }
   163  
   164  
   165  type alias Build =
   166      { id : BuildId
   167      , name : BuildName
   168      , job : Maybe JobIdentifier
   169      , status : BuildStatus
   170      , duration : BuildDuration
   171      , reapTime : Maybe Time.Posix
   172      }
   173  
   174  
   175  type alias BuildDuration =
   176      { startedAt : Maybe Time.Posix
   177      , finishedAt : Maybe Time.Posix
   178      }
   179  
   180  
   181  encodeBuild : Build -> Json.Encode.Value
   182  encodeBuild build =
   183      Json.Encode.object
   184          ([ ( "id", build.id |> Json.Encode.int ) |> Just
   185           , ( "name", build.name |> Json.Encode.string ) |> Just
   186           , optionalField "team_name" Json.Encode.string (build.job |> Maybe.map .teamName)
   187           , optionalField "pipeline_name" Json.Encode.string (build.job |> Maybe.map .pipelineName)
   188           , optionalField "job_name" Json.Encode.string (build.job |> Maybe.map .jobName)
   189           , ( "status", build.status |> Concourse.BuildStatus.encodeBuildStatus ) |> Just
   190           , optionalField "start_time" (secondsFromDate >> Json.Encode.int) build.duration.startedAt
   191           , optionalField "end_time" (secondsFromDate >> Json.Encode.int) build.duration.finishedAt
   192           , optionalField "reap_time" (secondsFromDate >> Json.Encode.int) build.reapTime
   193           ]
   194              |> List.filterMap identity
   195          )
   196  
   197  
   198  encodeMaybeBuild : Maybe Build -> Json.Encode.Value
   199  encodeMaybeBuild maybeBuild =
   200      case maybeBuild of
   201          Nothing ->
   202              Json.Encode.null
   203  
   204          Just build ->
   205              encodeBuild build
   206  
   207  
   208  decodeBuild : Json.Decode.Decoder Build
   209  decodeBuild =
   210      Json.Decode.succeed Build
   211          |> andMap (Json.Decode.field "id" Json.Decode.int)
   212          |> andMap (Json.Decode.field "name" Json.Decode.string)
   213          |> andMap
   214              (Json.Decode.maybe
   215                  (Json.Decode.succeed JobIdentifier
   216                      |> andMap (Json.Decode.field "team_name" Json.Decode.string)
   217                      |> andMap (Json.Decode.field "pipeline_name" Json.Decode.string)
   218                      |> andMap (Json.Decode.field "job_name" Json.Decode.string)
   219                  )
   220              )
   221          |> andMap (Json.Decode.field "status" Concourse.BuildStatus.decodeBuildStatus)
   222          |> andMap
   223              (Json.Decode.succeed BuildDuration
   224                  |> andMap (Json.Decode.maybe (Json.Decode.field "start_time" (Json.Decode.map dateFromSeconds Json.Decode.int)))
   225                  |> andMap (Json.Decode.maybe (Json.Decode.field "end_time" (Json.Decode.map dateFromSeconds Json.Decode.int)))
   226              )
   227          |> andMap (Json.Decode.maybe (Json.Decode.field "reap_time" (Json.Decode.map dateFromSeconds Json.Decode.int)))
   228  
   229  
   230  
   231  -- BuildPrep
   232  
   233  
   234  type alias BuildPrep =
   235      { pausedPipeline : BuildPrepStatus
   236      , pausedJob : BuildPrepStatus
   237      , maxRunningBuilds : BuildPrepStatus
   238      , inputs : Dict String BuildPrepStatus
   239      , inputsSatisfied : BuildPrepStatus
   240      , missingInputReasons : Dict String String
   241      }
   242  
   243  
   244  type BuildPrepStatus
   245      = BuildPrepStatusUnknown
   246      | BuildPrepStatusBlocking
   247      | BuildPrepStatusNotBlocking
   248  
   249  
   250  decodeBuildPrep : Json.Decode.Decoder BuildPrep
   251  decodeBuildPrep =
   252      Json.Decode.succeed BuildPrep
   253          |> andMap (Json.Decode.field "paused_pipeline" decodeBuildPrepStatus)
   254          |> andMap (Json.Decode.field "paused_job" decodeBuildPrepStatus)
   255          |> andMap (Json.Decode.field "max_running_builds" decodeBuildPrepStatus)
   256          |> andMap (Json.Decode.field "inputs" <| Json.Decode.dict decodeBuildPrepStatus)
   257          |> andMap (Json.Decode.field "inputs_satisfied" decodeBuildPrepStatus)
   258          |> andMap (defaultTo Dict.empty <| Json.Decode.field "missing_input_reasons" <| Json.Decode.dict Json.Decode.string)
   259  
   260  
   261  decodeBuildPrepStatus : Json.Decode.Decoder BuildPrepStatus
   262  decodeBuildPrepStatus =
   263      customDecoder Json.Decode.string <|
   264          \status ->
   265              case status of
   266                  "unknown" ->
   267                      Ok BuildPrepStatusUnknown
   268  
   269                  "blocking" ->
   270                      Ok BuildPrepStatusBlocking
   271  
   272                  "not_blocking" ->
   273                      Ok BuildPrepStatusNotBlocking
   274  
   275                  unknown ->
   276                      Err <| Json.Decode.Failure "unknown build preparation status" <| Json.Encode.string unknown
   277  
   278  
   279  
   280  -- BuildResources
   281  
   282  
   283  type alias BuildResources =
   284      { inputs : List BuildResourcesInput
   285      , outputs : List BuildResourcesOutput
   286      }
   287  
   288  
   289  type alias BuildResourcesInput =
   290      { name : String
   291      , version : Version
   292      , firstOccurrence : Bool
   293      }
   294  
   295  
   296  type alias BuildResourcesOutput =
   297      { name : String
   298      , version : Version
   299      }
   300  
   301  
   302  emptyBuildResources : BuildResources
   303  emptyBuildResources =
   304      { inputs = []
   305      , outputs = []
   306      }
   307  
   308  
   309  decodeBuildResources : Json.Decode.Decoder BuildResources
   310  decodeBuildResources =
   311      Json.Decode.succeed BuildResources
   312          |> andMap (Json.Decode.field "inputs" <| Json.Decode.list decodeResourcesInput)
   313          |> andMap (Json.Decode.field "outputs" <| Json.Decode.list decodeResourcesOutput)
   314  
   315  
   316  decodeResourcesInput : Json.Decode.Decoder BuildResourcesInput
   317  decodeResourcesInput =
   318      Json.Decode.succeed BuildResourcesInput
   319          |> andMap (Json.Decode.field "name" Json.Decode.string)
   320          |> andMap (Json.Decode.field "version" decodeVersion)
   321          |> andMap (Json.Decode.field "first_occurrence" Json.Decode.bool)
   322  
   323  
   324  decodeResourcesOutput : Json.Decode.Decoder BuildResourcesOutput
   325  decodeResourcesOutput =
   326      Json.Decode.succeed BuildResourcesOutput
   327          |> andMap (Json.Decode.field "name" Json.Decode.string)
   328          |> andMap (Json.Decode.field "version" <| Json.Decode.dict Json.Decode.string)
   329  
   330  
   331  
   332  -- BuildPlan
   333  
   334  
   335  type alias BuildPlan =
   336      { id : String
   337      , step : BuildStep
   338      }
   339  
   340  
   341  mapBuildPlan : (BuildPlan -> a) -> BuildPlan -> List a
   342  mapBuildPlan fn plan =
   343      fn plan
   344          :: (case plan.step of
   345                  BuildStepTask _ ->
   346                      []
   347  
   348                  BuildStepSetPipeline _ ->
   349                      []
   350  
   351                  BuildStepLoadVar _ ->
   352                      []
   353  
   354                  BuildStepArtifactInput _ ->
   355                      []
   356  
   357                  BuildStepPut _ ->
   358                      []
   359  
   360                  BuildStepCheck _ ->
   361                      []
   362  
   363                  BuildStepGet _ _ ->
   364                      []
   365  
   366                  BuildStepArtifactOutput _ ->
   367                      []
   368  
   369                  BuildStepAggregate plans ->
   370                      List.concatMap (mapBuildPlan fn) (Array.toList plans)
   371  
   372                  BuildStepInParallel plans ->
   373                      List.concatMap (mapBuildPlan fn) (Array.toList plans)
   374  
   375                  BuildStepAcross { steps } ->
   376                      List.concatMap (mapBuildPlan fn)
   377                          (steps |> List.map Tuple.second)
   378  
   379                  BuildStepDo plans ->
   380                      List.concatMap (mapBuildPlan fn) (Array.toList plans)
   381  
   382                  BuildStepOnSuccess { step, hook } ->
   383                      mapBuildPlan fn step ++ mapBuildPlan fn hook
   384  
   385                  BuildStepOnFailure { step, hook } ->
   386                      mapBuildPlan fn step ++ mapBuildPlan fn hook
   387  
   388                  BuildStepOnAbort { step, hook } ->
   389                      mapBuildPlan fn step ++ mapBuildPlan fn hook
   390  
   391                  BuildStepOnError { step, hook } ->
   392                      mapBuildPlan fn step ++ mapBuildPlan fn hook
   393  
   394                  BuildStepEnsure { step, hook } ->
   395                      mapBuildPlan fn step ++ mapBuildPlan fn hook
   396  
   397                  BuildStepTry step ->
   398                      mapBuildPlan fn step
   399  
   400                  BuildStepRetry plans ->
   401                      List.concatMap (mapBuildPlan fn) (Array.toList plans)
   402  
   403                  BuildStepTimeout step ->
   404                      mapBuildPlan fn step
   405             )
   406  
   407  
   408  type alias StepName =
   409      String
   410  
   411  
   412  type BuildStep
   413      = BuildStepTask StepName
   414      | BuildStepSetPipeline StepName
   415      | BuildStepLoadVar StepName
   416      | BuildStepArtifactInput StepName
   417      | BuildStepCheck StepName
   418      | BuildStepGet StepName (Maybe Version)
   419      | BuildStepArtifactOutput StepName
   420      | BuildStepPut StepName
   421      | BuildStepAggregate (Array BuildPlan)
   422      | BuildStepInParallel (Array BuildPlan)
   423      | BuildStepAcross AcrossPlan
   424      | BuildStepDo (Array BuildPlan)
   425      | BuildStepOnSuccess HookedPlan
   426      | BuildStepOnFailure HookedPlan
   427      | BuildStepOnAbort HookedPlan
   428      | BuildStepOnError HookedPlan
   429      | BuildStepEnsure HookedPlan
   430      | BuildStepTry BuildPlan
   431      | BuildStepRetry (Array BuildPlan)
   432      | BuildStepTimeout BuildPlan
   433  
   434  
   435  type alias HookedPlan =
   436      { step : BuildPlan
   437      , hook : BuildPlan
   438      }
   439  
   440  
   441  type JsonValue
   442      = JsonString String
   443      | JsonNumber Float
   444      | JsonObject (List ( String, JsonValue ))
   445      | JsonArray (List JsonValue)
   446      | JsonRaw Json.Decode.Value
   447  
   448  
   449  decodeJsonValue : Json.Decode.Decoder JsonValue
   450  decodeJsonValue =
   451      Json.Decode.oneOf
   452          [ Json.Decode.keyValuePairs decodeSimpleJsonValue |> Json.Decode.map JsonObject
   453          , Json.Decode.list decodeSimpleJsonValue |> Json.Decode.map JsonArray
   454          , decodeSimpleJsonValue
   455          ]
   456  
   457  
   458  decodeSimpleJsonValue : Json.Decode.Decoder JsonValue
   459  decodeSimpleJsonValue =
   460      Json.Decode.oneOf
   461          [ Json.Decode.string |> Json.Decode.map JsonString
   462          , Json.Decode.float |> Json.Decode.map JsonNumber
   463          , Json.Decode.value |> Json.Decode.map JsonRaw
   464          ]
   465  
   466  
   467  type alias AcrossPlan =
   468      { vars : List String
   469      , steps : List ( List JsonValue, BuildPlan )
   470      }
   471  
   472  
   473  decodeBuildPlanResponse : Json.Decode.Decoder BuildPlan
   474  decodeBuildPlanResponse =
   475      Json.Decode.at [ "plan" ] decodeBuildPlan
   476  
   477  
   478  decodeBuildPlan : Json.Decode.Decoder BuildPlan
   479  decodeBuildPlan =
   480      Json.Decode.succeed BuildPlan
   481          |> andMap (Json.Decode.field "id" Json.Decode.string)
   482          |> andMap
   483              (Json.Decode.oneOf
   484                  -- buckle up
   485                  [ Json.Decode.field "task" <|
   486                      lazy (\_ -> decodeBuildStepTask)
   487                  , Json.Decode.field "check" <|
   488                      lazy (\_ -> decodeBuildStepCheck)
   489                  , Json.Decode.field "get" <|
   490                      lazy (\_ -> decodeBuildStepGet)
   491                  , Json.Decode.field "artifact_input" <|
   492                      lazy (\_ -> decodeBuildStepArtifactInput)
   493                  , Json.Decode.field "put" <|
   494                      lazy (\_ -> decodeBuildStepPut)
   495                  , Json.Decode.field "artifact_output" <|
   496                      lazy (\_ -> decodeBuildStepArtifactOutput)
   497                  , Json.Decode.field "dependent_get" <|
   498                      lazy (\_ -> decodeBuildStepGet)
   499                  , Json.Decode.field "aggregate" <|
   500                      lazy (\_ -> decodeBuildStepAggregate)
   501                  , Json.Decode.field "in_parallel" <|
   502                      lazy (\_ -> decodeBuildStepInParallel)
   503                  , Json.Decode.field "do" <|
   504                      lazy (\_ -> decodeBuildStepDo)
   505                  , Json.Decode.field "on_success" <|
   506                      lazy (\_ -> decodeBuildStepOnSuccess)
   507                  , Json.Decode.field "on_failure" <|
   508                      lazy (\_ -> decodeBuildStepOnFailure)
   509                  , Json.Decode.field "on_abort" <|
   510                      lazy (\_ -> decodeBuildStepOnAbort)
   511                  , Json.Decode.field "on_error" <|
   512                      lazy (\_ -> decodeBuildStepOnError)
   513                  , Json.Decode.field "ensure" <|
   514                      lazy (\_ -> decodeBuildStepEnsure)
   515                  , Json.Decode.field "try" <|
   516                      lazy (\_ -> decodeBuildStepTry)
   517                  , Json.Decode.field "retry" <|
   518                      lazy (\_ -> decodeBuildStepRetry)
   519                  , Json.Decode.field "timeout" <|
   520                      lazy (\_ -> decodeBuildStepTimeout)
   521                  , Json.Decode.field "set_pipeline" <|
   522                      lazy (\_ -> decodeBuildSetPipeline)
   523                  , Json.Decode.field "load_var" <|
   524                      lazy (\_ -> decodeBuildStepLoadVar)
   525                  , Json.Decode.field "across" <|
   526                      lazy (\_ -> decodeBuildStepAcross)
   527                  ]
   528              )
   529  
   530  
   531  decodeBuildStepTask : Json.Decode.Decoder BuildStep
   532  decodeBuildStepTask =
   533      Json.Decode.succeed BuildStepTask
   534          |> andMap (Json.Decode.field "name" Json.Decode.string)
   535  
   536  
   537  decodeBuildStepArtifactInput : Json.Decode.Decoder BuildStep
   538  decodeBuildStepArtifactInput =
   539      Json.Decode.succeed BuildStepArtifactInput
   540          |> andMap (Json.Decode.field "name" Json.Decode.string)
   541  
   542  
   543  decodeBuildStepGet : Json.Decode.Decoder BuildStep
   544  decodeBuildStepGet =
   545      Json.Decode.succeed BuildStepGet
   546          |> andMap (Json.Decode.field "name" Json.Decode.string)
   547          |> andMap (Json.Decode.maybe <| Json.Decode.field "version" decodeVersion)
   548  
   549  
   550  decodeBuildStepCheck : Json.Decode.Decoder BuildStep
   551  decodeBuildStepCheck =
   552      Json.Decode.succeed BuildStepCheck
   553          |> andMap (Json.Decode.field "name" Json.Decode.string)
   554  
   555  
   556  decodeBuildStepArtifactOutput : Json.Decode.Decoder BuildStep
   557  decodeBuildStepArtifactOutput =
   558      Json.Decode.succeed BuildStepArtifactOutput
   559          |> andMap (Json.Decode.field "name" Json.Decode.string)
   560  
   561  
   562  decodeBuildStepPut : Json.Decode.Decoder BuildStep
   563  decodeBuildStepPut =
   564      Json.Decode.succeed BuildStepPut
   565          |> andMap (Json.Decode.field "name" Json.Decode.string)
   566  
   567  
   568  decodeBuildStepAggregate : Json.Decode.Decoder BuildStep
   569  decodeBuildStepAggregate =
   570      Json.Decode.succeed BuildStepAggregate
   571          |> andMap (Json.Decode.array (lazy (\_ -> decodeBuildPlan)))
   572  
   573  
   574  decodeBuildStepInParallel : Json.Decode.Decoder BuildStep
   575  decodeBuildStepInParallel =
   576      Json.Decode.succeed BuildStepInParallel
   577          |> andMap (Json.Decode.field "steps" <| Json.Decode.array (lazy (\_ -> decodeBuildPlan)))
   578  
   579  
   580  decodeBuildStepDo : Json.Decode.Decoder BuildStep
   581  decodeBuildStepDo =
   582      Json.Decode.succeed BuildStepDo
   583          |> andMap (Json.Decode.array (lazy (\_ -> decodeBuildPlan)))
   584  
   585  
   586  decodeBuildStepOnSuccess : Json.Decode.Decoder BuildStep
   587  decodeBuildStepOnSuccess =
   588      Json.Decode.map BuildStepOnSuccess
   589          (Json.Decode.succeed HookedPlan
   590              |> andMap (Json.Decode.field "step" <| lazy (\_ -> decodeBuildPlan))
   591              |> andMap (Json.Decode.field "on_success" <| lazy (\_ -> decodeBuildPlan))
   592          )
   593  
   594  
   595  decodeBuildStepOnFailure : Json.Decode.Decoder BuildStep
   596  decodeBuildStepOnFailure =
   597      Json.Decode.map BuildStepOnFailure
   598          (Json.Decode.succeed HookedPlan
   599              |> andMap (Json.Decode.field "step" <| lazy (\_ -> decodeBuildPlan))
   600              |> andMap (Json.Decode.field "on_failure" <| lazy (\_ -> decodeBuildPlan))
   601          )
   602  
   603  
   604  decodeBuildStepOnAbort : Json.Decode.Decoder BuildStep
   605  decodeBuildStepOnAbort =
   606      Json.Decode.map BuildStepOnAbort
   607          (Json.Decode.succeed HookedPlan
   608              |> andMap (Json.Decode.field "step" <| lazy (\_ -> decodeBuildPlan))
   609              |> andMap (Json.Decode.field "on_abort" <| lazy (\_ -> decodeBuildPlan))
   610          )
   611  
   612  
   613  decodeBuildStepOnError : Json.Decode.Decoder BuildStep
   614  decodeBuildStepOnError =
   615      Json.Decode.map BuildStepOnError
   616          (Json.Decode.succeed HookedPlan
   617              |> andMap (Json.Decode.field "step" <| lazy (\_ -> decodeBuildPlan))
   618              |> andMap (Json.Decode.field "on_error" <| lazy (\_ -> decodeBuildPlan))
   619          )
   620  
   621  
   622  decodeBuildStepEnsure : Json.Decode.Decoder BuildStep
   623  decodeBuildStepEnsure =
   624      Json.Decode.map BuildStepEnsure
   625          (Json.Decode.succeed HookedPlan
   626              |> andMap (Json.Decode.field "step" <| lazy (\_ -> decodeBuildPlan))
   627              |> andMap (Json.Decode.field "ensure" <| lazy (\_ -> decodeBuildPlan))
   628          )
   629  
   630  
   631  decodeBuildStepTry : Json.Decode.Decoder BuildStep
   632  decodeBuildStepTry =
   633      Json.Decode.succeed BuildStepTry
   634          |> andMap (Json.Decode.field "step" <| lazy (\_ -> decodeBuildPlan))
   635  
   636  
   637  decodeBuildStepRetry : Json.Decode.Decoder BuildStep
   638  decodeBuildStepRetry =
   639      Json.Decode.succeed BuildStepRetry
   640          |> andMap (Json.Decode.array (lazy (\_ -> decodeBuildPlan)))
   641  
   642  
   643  decodeBuildStepTimeout : Json.Decode.Decoder BuildStep
   644  decodeBuildStepTimeout =
   645      Json.Decode.succeed BuildStepTimeout
   646          |> andMap (Json.Decode.field "step" <| lazy (\_ -> decodeBuildPlan))
   647  
   648  
   649  decodeBuildSetPipeline : Json.Decode.Decoder BuildStep
   650  decodeBuildSetPipeline =
   651      Json.Decode.succeed BuildStepSetPipeline
   652          |> andMap (Json.Decode.field "name" Json.Decode.string)
   653  
   654  
   655  decodeBuildStepLoadVar : Json.Decode.Decoder BuildStep
   656  decodeBuildStepLoadVar =
   657      Json.Decode.succeed BuildStepLoadVar
   658          |> andMap (Json.Decode.field "name" Json.Decode.string)
   659  
   660  
   661  decodeBuildStepAcross : Json.Decode.Decoder BuildStep
   662  decodeBuildStepAcross =
   663      Json.Decode.map BuildStepAcross
   664          (Json.Decode.succeed AcrossPlan
   665              |> andMap
   666                  (Json.Decode.field "vars" <|
   667                      Json.Decode.list <|
   668                          Json.Decode.field "name" Json.Decode.string
   669                  )
   670              |> andMap
   671                  (Json.Decode.field "steps" <|
   672                      Json.Decode.list <|
   673                          Json.Decode.map2 Tuple.pair
   674                              (Json.Decode.field "values" <| Json.Decode.list decodeJsonValue)
   675                              (Json.Decode.field "step" decodeBuildPlan)
   676                  )
   677          )
   678  
   679  
   680  
   681  -- Info
   682  
   683  
   684  type alias ClusterInfo =
   685      { version : String
   686      , clusterName : String
   687      }
   688  
   689  
   690  decodeInfo : Json.Decode.Decoder ClusterInfo
   691  decodeInfo =
   692      Json.Decode.succeed ClusterInfo
   693          |> andMap (Json.Decode.field "version" Json.Decode.string)
   694          |> andMap (defaultTo "" <| Json.Decode.field "cluster_name" Json.Decode.string)
   695  
   696  
   697  
   698  -- Job
   699  
   700  
   701  type alias JobName =
   702      String
   703  
   704  
   705  type alias JobIdentifier =
   706      { teamName : TeamName
   707      , pipelineName : PipelineName
   708      , jobName : JobName
   709      }
   710  
   711  
   712  type alias Job =
   713      { name : JobName
   714      , pipelineName : PipelineName
   715      , teamName : TeamName
   716      , nextBuild : Maybe Build
   717      , finishedBuild : Maybe Build
   718      , transitionBuild : Maybe Build
   719      , paused : Bool
   720      , disableManualTrigger : Bool
   721      , inputs : List JobInput
   722      , outputs : List JobOutput
   723      , groups : List String
   724      }
   725  
   726  
   727  type alias JobInput =
   728      { name : String
   729      , resource : String
   730      , passed : List String
   731      , trigger : Bool
   732      }
   733  
   734  
   735  type alias JobOutput =
   736      { name : String
   737      , resource : String
   738      }
   739  
   740  
   741  encodeJob : Job -> Json.Encode.Value
   742  encodeJob job =
   743      Json.Encode.object
   744          [ ( "name", job.name |> Json.Encode.string )
   745          , ( "pipeline_name", job.pipelineName |> Json.Encode.string )
   746          , ( "team_name", job.teamName |> Json.Encode.string )
   747          , ( "next_build", job.nextBuild |> encodeMaybeBuild )
   748          , ( "finished_build", job.finishedBuild |> encodeMaybeBuild )
   749          , ( "transition_build", job.finishedBuild |> encodeMaybeBuild )
   750          , ( "paused", job.paused |> Json.Encode.bool )
   751          , ( "disable_manual_trigger", job.disableManualTrigger |> Json.Encode.bool )
   752          , ( "inputs", job.inputs |> Json.Encode.list encodeJobInput )
   753          , ( "outputs", job.outputs |> Json.Encode.list encodeJobOutput )
   754          , ( "groups", job.groups |> Json.Encode.list Json.Encode.string )
   755          ]
   756  
   757  
   758  decodeJob : Json.Decode.Decoder Job
   759  decodeJob =
   760      Json.Decode.succeed Job
   761          |> andMap (Json.Decode.field "name" Json.Decode.string)
   762          |> andMap (Json.Decode.field "pipeline_name" Json.Decode.string)
   763          |> andMap (Json.Decode.field "team_name" Json.Decode.string)
   764          |> andMap (Json.Decode.maybe (Json.Decode.field "next_build" decodeBuild))
   765          |> andMap (Json.Decode.maybe (Json.Decode.field "finished_build" decodeBuild))
   766          |> andMap (Json.Decode.maybe (Json.Decode.field "transition_build" decodeBuild))
   767          |> andMap (defaultTo False <| Json.Decode.field "paused" Json.Decode.bool)
   768          |> andMap (defaultTo False <| Json.Decode.field "disable_manual_trigger" Json.Decode.bool)
   769          |> andMap (defaultTo [] <| Json.Decode.field "inputs" <| Json.Decode.list decodeJobInput)
   770          |> andMap (defaultTo [] <| Json.Decode.field "outputs" <| Json.Decode.list decodeJobOutput)
   771          |> andMap (defaultTo [] <| Json.Decode.field "groups" <| Json.Decode.list Json.Decode.string)
   772  
   773  
   774  encodeJobInput : JobInput -> Json.Encode.Value
   775  encodeJobInput jobInput =
   776      Json.Encode.object
   777          [ ( "name", jobInput.name |> Json.Encode.string )
   778          , ( "resource", jobInput.resource |> Json.Encode.string )
   779          , ( "passed", jobInput.passed |> Json.Encode.list Json.Encode.string )
   780          , ( "trigger", jobInput.trigger |> Json.Encode.bool )
   781          ]
   782  
   783  
   784  decodeJobInput : Json.Decode.Decoder JobInput
   785  decodeJobInput =
   786      Json.Decode.succeed JobInput
   787          |> andMap (Json.Decode.field "name" Json.Decode.string)
   788          |> andMap (Json.Decode.field "resource" Json.Decode.string)
   789          |> andMap (defaultTo [] <| Json.Decode.field "passed" <| Json.Decode.list Json.Decode.string)
   790          |> andMap (defaultTo False <| Json.Decode.field "trigger" Json.Decode.bool)
   791  
   792  
   793  encodeJobOutput : JobOutput -> Json.Encode.Value
   794  encodeJobOutput jobOutput =
   795      Json.Encode.object
   796          [ ( "name", jobOutput.name |> Json.Encode.string )
   797          , ( "resource", jobOutput.resource |> Json.Encode.string )
   798          ]
   799  
   800  
   801  decodeJobOutput : Json.Decode.Decoder JobOutput
   802  decodeJobOutput =
   803      Json.Decode.succeed JobOutput
   804          |> andMap (Json.Decode.field "name" Json.Decode.string)
   805          |> andMap (Json.Decode.field "resource" Json.Decode.string)
   806  
   807  
   808  
   809  -- Pipeline
   810  
   811  
   812  type alias PipelineName =
   813      String
   814  
   815  
   816  type alias PipelineIdentifier =
   817      { teamName : TeamName
   818      , pipelineName : PipelineName
   819      }
   820  
   821  
   822  type alias Pipeline =
   823      { id : Int
   824      , name : PipelineName
   825      , paused : Bool
   826      , archived : Bool
   827      , public : Bool
   828      , teamName : TeamName
   829      , groups : List PipelineGroup
   830      , backgroundImage : Maybe String
   831      }
   832  
   833  
   834  type alias PipelineGroup =
   835      { name : String
   836      , jobs : List String
   837      , resources : List String
   838      }
   839  
   840  
   841  encodePipeline : Pipeline -> Json.Encode.Value
   842  encodePipeline pipeline =
   843      Json.Encode.object
   844          [ ( "id", pipeline.id |> Json.Encode.int )
   845          , ( "name", pipeline.name |> Json.Encode.string )
   846          , ( "paused", pipeline.paused |> Json.Encode.bool )
   847          , ( "archived", pipeline.archived |> Json.Encode.bool )
   848          , ( "public", pipeline.public |> Json.Encode.bool )
   849          , ( "team_name", pipeline.teamName |> Json.Encode.string )
   850          , ( "groups", pipeline.groups |> Json.Encode.list encodePipelineGroup )
   851          , ( "display", Json.Encode.object [ ( "background_image", pipeline.backgroundImage |> Json.Encode.Extra.maybe Json.Encode.string ) ] )
   852          ]
   853  
   854  
   855  decodePipeline : Json.Decode.Decoder Pipeline
   856  decodePipeline =
   857      Json.Decode.succeed Pipeline
   858          |> andMap (Json.Decode.field "id" Json.Decode.int)
   859          |> andMap (Json.Decode.field "name" Json.Decode.string)
   860          |> andMap (Json.Decode.field "paused" Json.Decode.bool)
   861          |> andMap (Json.Decode.field "archived" Json.Decode.bool)
   862          |> andMap (Json.Decode.field "public" Json.Decode.bool)
   863          |> andMap (Json.Decode.field "team_name" Json.Decode.string)
   864          |> andMap (defaultTo [] <| Json.Decode.field "groups" (Json.Decode.list decodePipelineGroup))
   865          |> andMap (Json.Decode.maybe (Json.Decode.at [ "display", "background_image" ] Json.Decode.string))
   866  
   867  
   868  encodePipelineGroup : PipelineGroup -> Json.Encode.Value
   869  encodePipelineGroup pipelineGroup =
   870      Json.Encode.object
   871          [ ( "name", pipelineGroup.name |> Json.Encode.string )
   872          , ( "jobs", pipelineGroup.jobs |> Json.Encode.list Json.Encode.string )
   873          , ( "resources", pipelineGroup.resources |> Json.Encode.list Json.Encode.string )
   874          ]
   875  
   876  
   877  decodePipelineGroup : Json.Decode.Decoder PipelineGroup
   878  decodePipelineGroup =
   879      Json.Decode.succeed PipelineGroup
   880          |> andMap (Json.Decode.field "name" Json.Decode.string)
   881          |> andMap (defaultTo [] <| Json.Decode.field "jobs" <| Json.Decode.list Json.Decode.string)
   882          |> andMap (defaultTo [] <| Json.Decode.field "resources" <| Json.Decode.list Json.Decode.string)
   883  
   884  
   885  
   886  -- Resource
   887  
   888  
   889  type alias Resource =
   890      { teamName : String
   891      , pipelineName : String
   892      , name : String
   893      , icon : Maybe String
   894      , lastChecked : Maybe Time.Posix
   895      , pinnedVersion : Maybe Version
   896      , pinnedInConfig : Bool
   897      , pinComment : Maybe String
   898      , build : Maybe Build
   899      }
   900  
   901  
   902  type alias ResourceIdentifier =
   903      { teamName : String
   904      , pipelineName : String
   905      , resourceName : String
   906      }
   907  
   908  
   909  type alias VersionedResource =
   910      { id : Int
   911      , version : Version
   912      , metadata : Metadata
   913      , enabled : Bool
   914      }
   915  
   916  
   917  type alias VersionedResourceIdentifier =
   918      { teamName : String
   919      , pipelineName : String
   920      , resourceName : String
   921      , versionID : Int
   922      }
   923  
   924  
   925  decodeResource : Json.Decode.Decoder Resource
   926  decodeResource =
   927      Json.Decode.succeed Resource
   928          |> andMap (Json.Decode.field "team_name" Json.Decode.string)
   929          |> andMap (Json.Decode.field "pipeline_name" Json.Decode.string)
   930          |> andMap (Json.Decode.field "name" Json.Decode.string)
   931          |> andMap (Json.Decode.maybe (Json.Decode.field "icon" Json.Decode.string))
   932          |> andMap (Json.Decode.maybe (Json.Decode.field "last_checked" (Json.Decode.map dateFromSeconds Json.Decode.int)))
   933          |> andMap (Json.Decode.maybe (Json.Decode.field "pinned_version" decodeVersion))
   934          |> andMap (defaultTo False <| Json.Decode.field "pinned_in_config" Json.Decode.bool)
   935          |> andMap (Json.Decode.maybe (Json.Decode.field "pin_comment" Json.Decode.string))
   936          |> andMap (Json.Decode.maybe (Json.Decode.field "build" decodeBuild))
   937  
   938  
   939  encodeResource : Resource -> Json.Encode.Value
   940  encodeResource r =
   941      Json.Encode.object
   942          ([ ( "team_name", r.teamName |> Json.Encode.string ) |> Just
   943           , ( "pipeline_name", r.pipelineName |> Json.Encode.string ) |> Just
   944           , ( "name", r.name |> Json.Encode.string ) |> Just
   945           , optionalField "icon" Json.Encode.string r.icon
   946           , optionalField "last_checked" (secondsFromDate >> Json.Encode.int) r.lastChecked
   947           , optionalField "pinned_version" encodeVersion r.pinnedVersion
   948           , ( "pinned_in_config", r.pinnedInConfig |> Json.Encode.bool ) |> Just
   949           , optionalField "pin_comment" Json.Encode.string r.pinComment
   950           , ( "build", r.build |> encodeMaybeBuild ) |> Just
   951           ]
   952              |> List.filterMap identity
   953          )
   954  
   955  
   956  decodeVersionedResource : Json.Decode.Decoder VersionedResource
   957  decodeVersionedResource =
   958      Json.Decode.succeed VersionedResource
   959          |> andMap (Json.Decode.field "id" Json.Decode.int)
   960          |> andMap (Json.Decode.field "version" decodeVersion)
   961          |> andMap (defaultTo [] (Json.Decode.field "metadata" decodeMetadata))
   962          |> andMap (Json.Decode.field "enabled" Json.Decode.bool)
   963  
   964  
   965  
   966  -- Version
   967  
   968  
   969  type alias Version =
   970      Dict String String
   971  
   972  
   973  decodeVersion : Json.Decode.Decoder Version
   974  decodeVersion =
   975      Json.Decode.dict Json.Decode.string
   976  
   977  
   978  encodeVersion : Version -> Json.Encode.Value
   979  encodeVersion =
   980      Json.Encode.dict identity Json.Encode.string
   981  
   982  
   983  
   984  -- Metadata
   985  
   986  
   987  type alias Metadata =
   988      List MetadataField
   989  
   990  
   991  type alias MetadataField =
   992      { name : String
   993      , value : String
   994      }
   995  
   996  
   997  decodeMetadata : Json.Decode.Decoder (List MetadataField)
   998  decodeMetadata =
   999      Json.Decode.list decodeMetadataField
  1000  
  1001  
  1002  decodeMetadataField : Json.Decode.Decoder MetadataField
  1003  decodeMetadataField =
  1004      Json.Decode.succeed MetadataField
  1005          |> andMap (Json.Decode.field "name" Json.Decode.string)
  1006          |> andMap (Json.Decode.field "value" Json.Decode.string)
  1007  
  1008  
  1009  
  1010  -- Team
  1011  
  1012  
  1013  type alias TeamName =
  1014      String
  1015  
  1016  
  1017  type alias Team =
  1018      { id : Int
  1019      , name : TeamName
  1020      }
  1021  
  1022  
  1023  encodeTeam : Team -> Json.Encode.Value
  1024  encodeTeam team =
  1025      Json.Encode.object
  1026          [ ( "id", team.id |> Json.Encode.int )
  1027          , ( "name", team.name |> Json.Encode.string )
  1028          ]
  1029  
  1030  
  1031  decodeTeam : Json.Decode.Decoder Team
  1032  decodeTeam =
  1033      Json.Decode.succeed Team
  1034          |> andMap (Json.Decode.field "id" Json.Decode.int)
  1035          |> andMap (Json.Decode.field "name" Json.Decode.string)
  1036  
  1037  
  1038  
  1039  -- User
  1040  
  1041  
  1042  type alias User =
  1043      { id : String
  1044      , userName : String
  1045      , name : String
  1046      , email : String
  1047      , isAdmin : Bool
  1048      , teams : Dict String (List String)
  1049      }
  1050  
  1051  
  1052  decodeUser : Json.Decode.Decoder User
  1053  decodeUser =
  1054      Json.Decode.succeed User
  1055          |> andMap (Json.Decode.field "user_id" Json.Decode.string)
  1056          |> andMap (Json.Decode.field "user_name" Json.Decode.string)
  1057          |> andMap (Json.Decode.field "name" Json.Decode.string)
  1058          |> andMap (Json.Decode.field "email" Json.Decode.string)
  1059          |> andMap (Json.Decode.field "is_admin" Json.Decode.bool)
  1060          |> andMap (Json.Decode.field "teams" (Json.Decode.dict (Json.Decode.list Json.Decode.string)))
  1061  
  1062  
  1063  
  1064  -- Cause
  1065  
  1066  
  1067  type alias Cause =
  1068      { versionedResourceID : Int
  1069      , buildID : Int
  1070      }
  1071  
  1072  
  1073  decodeCause : Json.Decode.Decoder Cause
  1074  decodeCause =
  1075      Json.Decode.succeed Cause
  1076          |> andMap (Json.Decode.field "versioned_resource_id" Json.Decode.int)
  1077          |> andMap (Json.Decode.field "build_id" Json.Decode.int)
  1078  
  1079  
  1080  
  1081  -- Helpers
  1082  
  1083  
  1084  dateFromSeconds : Int -> Time.Posix
  1085  dateFromSeconds =
  1086      Time.millisToPosix << (*) 1000
  1087  
  1088  
  1089  secondsFromDate : Time.Posix -> Int
  1090  secondsFromDate =
  1091      Time.posixToMillis >> (\m -> m // 1000)
  1092  
  1093  
  1094  lazy : (() -> Json.Decode.Decoder a) -> Json.Decode.Decoder a
  1095  lazy thunk =
  1096      customDecoder Json.Decode.value
  1097          (\js -> Json.Decode.decodeValue (thunk ()) js)
  1098  
  1099  
  1100  defaultTo : a -> Json.Decode.Decoder a -> Json.Decode.Decoder a
  1101  defaultTo default =
  1102      Json.Decode.map (Maybe.withDefault default) << Json.Decode.maybe
  1103  
  1104  
  1105  customDecoder : Json.Decode.Decoder b -> (b -> Result Json.Decode.Error a) -> Json.Decode.Decoder a
  1106  customDecoder decoder toResult =
  1107      Json.Decode.andThen
  1108          (\a ->
  1109              case toResult a of
  1110                  Ok b ->
  1111                      Json.Decode.succeed b
  1112  
  1113                  Err err ->
  1114                      Json.Decode.fail <| Json.Decode.errorToString err
  1115          )
  1116          decoder
  1117  
  1118  
  1119  optionalField : String -> (a -> Json.Encode.Value) -> Maybe a -> Maybe ( String, Json.Encode.Value )
  1120  optionalField field encoder =
  1121      Maybe.map (\val -> ( field, encoder val ))