# NOTE: Do not upgrade past Swagger 2. zclient does not support OpenAPI 3 unless
# https://github.com/Yelp/bravado/issues/306 is resolved.
---
swagger: "2.0"
info:
  description: "Stores CI build results"
  version: "1.0.0"
  title: "ci_builds"
  contact:
    name: "Infra"
    email: "infrateam@zoox.com"
    url: "https://git.zooxlabs.com/zooxco/driving"

basePath: "/v1"

paths:
  /builds:
    get:
      summary: "Get builds"
      operationId: "getBuilds"
      produces:
        - "application/json"
      parameters:
        - name: "buildName"
          in: "query"
          description: "Only return builds with this name (wildcards supported) e.g. 'PR 1234', 'GPU*'"
          type: "string"
        - name: "startDate"
          in: "query"
          description: "Only return builds after this start date e.g. 2019-04-20"
          type: "string"
          format: "date"
        - name: "endDate"
          in: "query"
          description: "Only return builds before this start date e.g. 2019-04-20"
          type: "string"
          format: "date"
        - name: "offset"
          in: "query"
          description: "The offset at which to return the results"
          type: "integer"
          default: 0
        - name: "limit"
          in: "query"
          description: "The max number of results to return"
          type: "integer"
          default: 20
        - name: "direction"
          in: "query"
          description: "Direction of the sorting order"
          type: "string"
          enum:
            - ASC
            - DESC
          default: "DESC"
        - name: "jobResults"
          in: "query"
          description: "List of job results (Result enum) to filter by e.g. `QUEUED,PENDING` to return builds with any jobs that are queued or pending"
          type: "array"
          items:
            type: "string"
      responses:
        "200":
          description: "Successfully retrieved builds"
          schema:
            $ref: "#/definitions/PaginatedBuilds"
        "404":
          description: "Build not found"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "500":
          description: "Internal server error"
          schema:
            $ref: "#/definitions/ErrorResponse"

  /builds/{buildId}:
    parameters:
      - in: "path"
        name: "buildId"
        description: "Unique identifier for this build. It has historically been the same as the pipedream id but is not required to be the case."
        type: "string"
        format: "uuid"
        required: true
    post:
      summary: "Create a build"
      operationId: "createBuild"
      consumes:
        - "application/json"
      produces:
        - "application/json"
      parameters:
        - in: "body"
          name: "build"
          description: "Build to create"
          required: true
          schema:
            $ref: "#/definitions/BuildPost"
      responses:
        "201":
          description: "Successfully created the build"
          schema:
            $ref: "#/definitions/Build"
        "400":
          description: "Invalid parameter"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "500":
          description: "Internal server error"
          schema:
            $ref: "#/definitions/ErrorResponse"
    get:
      summary: "Get a build"
      operationId: "getBuild"
      produces:
        - "application/json"
      responses:
        "200":
          description: "Successfully retrieved the build"
          schema:
            $ref: "#/definitions/Build"
        "404":
          description: "Build not found"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "500":
          description: "Internal server error"
          schema:
            $ref: "#/definitions/ErrorResponse"

  /builds/{buildId}/jobs/{jobName}:
    parameters:
      - in: "path"
        name: "buildId"
        description: "Build id"
        type: "string"
        format: "uuid"
        required: true
      - in: "path"
        name: "jobName"
        description: "Job name"
        type: "string"
        required: true
    post:
      summary: "DEPRECATED (create jobs upfront with the build instead): Create a build job or start the build if it is QUEUED."
      operationId: "createJob"
      consumes:
        - "application/json"
      produces:
        - "application/json"
      parameters:
        - in: "body"
          name: "job"
          description: "Job to create"
          required: true
          schema:
            $ref: "#/definitions/Job"
      responses:
        "200":
          description: "Successfully started the existing job"
          schema:
            $ref: "#/definitions/Job"
        "201":
          description: "Successfully created the job"
          schema:
            $ref: "#/definitions/Job"
        "400":
          description: "Invalid parameter"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "404":
          description: "Build not found"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "500":
          description: "Internal server error"
          schema:
            $ref: "#/definitions/ErrorResponse"
    patch:
      summary: "Update an existing build job"
      operationId: "patchJob"
      consumes:
        - "application/json"
      produces:
        - "application/json"
      parameters:
        - in: "body"
          name: "jobPatch"
          description: "Job updates"
          required: true
          schema:
            $ref: "#/definitions/JobPatch"
      responses:
        "200":
          description: "Successfully updated the job"
          schema:
            $ref: "#/definitions/Job"
        "400":
          description: "Invalid parameter"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "404":
          description: "Job not found"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "500":
          description: "Internal server error"
          schema:
            $ref: "#/definitions/ErrorResponse"

  /builds/{buildId}/jobs/{jobName}/stages/{stageName}:
    parameters:
      - in: "path"
        name: "buildId"
        description: "Build id"
        type: "string"
        format: "uuid"
        required: true
      - in: "path"
        name: "jobName"
        description: "Job name"
        type: "string"
        required: true
      - in: "path"
        name: "stageName"
        description: "Stage name"
        type: "string"
        required: true
    post:
      summary: "Create a build job stage"
      operationId: "createStage"
      consumes:
        - "application/json"
      produces:
        - "application/json"
      parameters:
        - in: "body"
          name: "stage"
          description: "Stage to create"
          required: true
          schema:
            $ref: "#/definitions/Stage"
      responses:
        "201":
          description: "Successfully created the stage"
          schema:
            $ref: "#/definitions/Stage"
        "400":
          description: "Invalid parameter"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "404":
          description: "Job not found"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "500":
          description: "Internal server error"
          schema:
            $ref: "#/definitions/ErrorResponse"
    patch:
      summary: "Update an existing build job stage"
      operationId: "patchStage"
      consumes:
        - "application/json"
      produces:
        - "application/json"
      parameters:
        - in: "body"
          name: "stagePatch"
          description: "Stage updates"
          required: true
          schema:
            $ref: "#/definitions/StagePatch"
      responses:
        "200":
          description: "Successfully updated the stage"
          schema:
            $ref: "#/definitions/Stage"
        "400":
          description: "Invalid parameter"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "404":
          description: "Stage not found"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "500":
          description: "Internal server error"
          schema:
            $ref: "#/definitions/ErrorResponse"

  /builds/{buildId}/jobs/{jobName}/meta:
    parameters:
      - in: "path"
        name: "buildId"
        description: "Build id"
        type: "string"
        format: "uuid"
        required: true
      - in: "path"
        name: "jobName"
        description: "Job name"
        type: "string"
        required: true
    post:
      summary: "Create meta data"
      description: "Duplicate keys on a job are forbidden and will cause requests to fail"
      operationId: "createMeta"
      consumes:
        - "application/json"
      produces:
        - "application/json"
      parameters:
        - in: "body"
          name: "metaDataDict"
          description: "Metadata to create"
          required: true
          schema:
            $ref: "#/definitions/MetaDataDict"
      responses:
        "201":
          description: "Successfully created the metadata"
          schema:
            $ref: "#/definitions/MetaDataDict"
        "400":
          description: "Invalid parameter"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "404":
          description: "Job not found"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "500":
          description: "Internal server error"
          schema:
            $ref: "#/definitions/ErrorResponse"

  /builds/{buildId}/jobs/{jobName}/messages:
    parameters:
      - in: "path"
        name: "buildId"
        description: "Build id"
        type: "string"
        format: "uuid"
        required: true
      - in: "path"
        name: "jobName"
        description: "Job name"
        type: "string"
        required: true
    get:
      summary: "Get a job's messages"
      operationId: "getJobMessages"
      produces:
        - "application/json"
      responses:
        "200":
          description: "Successfully retrieved job's messages"
          schema:
            $ref: "#/definitions/MessageList"
        "404":
          description: "Job not found"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "500":
          description: "Internal server error"
          schema:
            $ref: "#/definitions/ErrorResponse"
    post:
      summary: "Create message"
      operationId: "createMessage"
      consumes:
        - "application/json"
      produces:
        - "application/json"
      parameters:
        - in: "body"
          name: "message"
          description: "Message to create"
          required: true
          schema:
            $ref: "#/definitions/Message"
      responses:
        "201":
          description: "Successfully created the message"
          schema:
            $ref: "#/definitions/Message"
        "400":
          description: "Invalid parameter"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "404":
          description: "Job not found"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "500":
          description: "Internal server error"
          schema:
            $ref: "#/definitions/ErrorResponse"

  /builds/{buildId}/jobs/{jobName}/tests:
    parameters:
      - in: "path"
        name: "buildId"
        description: "Build id"
        type: "string"
        format: "uuid"
        required: true
      - in: "path"
        name: "jobName"
        description: "Job name"
        type: "string"
        required: true
    get:
      summary: "Get a job's test results"
      operationId: "getJobTests"
      produces:
        - "application/json"
      responses:
        "200":
          description: "Successfully retrieved job's test results"
          schema:
            $ref: "#/definitions/PaginatedTests"
        "404":
          description: "Job not found"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "500":
          description: "Internal server error"
          schema:
            $ref: "#/definitions/ErrorResponse"
    post:
      summary: "Create test results"
      operationId: "createTestResults"
      consumes:
        - "application/json"
      produces:
        - "application/json"
      parameters:
        - in: "body"
          name: "testResults"
          description: "Test results to create"
          required: true
          schema:
            $ref: "#/definitions/TestResultList"
      responses:
        "201":
          description: "Successfully created the test results"
          schema:
            $ref: "#/definitions/TestResultList"
        "400":
          description: "Invalid parameter"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "404":
          description: "Job not found"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "500":
          description: "Internal server error"
          schema:
            $ref: "#/definitions/ErrorResponse"

  /tests:
    get:
      summary: "List test results"
      operationId: "getTests"
      produces:
        - "application/json"
      parameters:
        - name: "startDate"
          in: "query"
          description: "Only return results after this start date e.g. 2019-04-20"
          type: "string"
          format: "date"
        - name: "endDate"
          in: "query"
          description: "Only return results before this start date e.g. 2019-04-20"
          type: "string"
          format: "date"
        - name: "offset"
          in: "query"
          description: "The offset at which to return the results"
          type: "integer"
          default: 0
        - name: "limit"
          in: "query"
          description: "The max number of results to return"
          type: "integer"
          default: 20
        - name: "bazelTarget"
          in: "query"
          description: "The bazel target to filter results by"
          type: "string"
        - name: "results"
          in: "query"
          description: "List of results to filter by e.g. `FAILURE,TIMEOUT` to return only tests that fail or timeout"
          type: "array"
          items:
            type: "string"
      responses:
        "200":
          description: "Successful operation"
          schema:
            $ref: "#/definitions/PaginatedTests"
        "400":
          description: "Invalid parameter"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "500":
          description: "Internal server error"
          schema:
            $ref: "#/definitions/ErrorResponse"

  /tests/logs:
    post:
      summary: "Upload test log"
      operationId: "uploadTestLog"
      consumes:
        - "application/json"
      produces:
        - "application/json"
      parameters:
        - in: "body"
          name: "testLog"
          description: "Test log to upload"
          required: true
          schema:
            $ref: "#/definitions/TestLog"
      responses:
        "201":
          description: "Successfully uploaded test log"
          schema:
            $ref: "#/definitions/UploadTestLogResult"
        "400":
          description: "Invalid parameter"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "500":
          description: "Internal server error"
          schema:
            $ref: "#/definitions/ErrorResponse"


  /tests/targets:
    get:
      summary: "List all bazel targets executed in the last 7 days. The list will be sorted."
      operationId: "getTestTargets"
      produces:
        - "application/json"
      responses:
        "200":
          description: "Successfully retrieved bazel targets"
          schema:
            $ref: "#/definitions/TestTargetsList"
        "400":
          description: "Invalid parameter"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "500":
          description: "Internal server error"
          schema:
            $ref: "#/definitions/ErrorResponse"

  /tests/states:
    get:
      summary: "List test states"
      operationId: "getTestStates"
      produces:
        - "application/json"
      parameters:
        - name: "onlyCurrentState"
          in: "query"
          description: "Only return the most recent state for each test"
          type: "boolean"
          default: false
        - name: "bazelTarget"
          in: "query"
          description: "The bazel target to filter results by"
          type: "string"
        - name: "states"
          in: "query"
          description: "Only return test states with one of these states"
          type: "array"
          items:
            type: "string"
        - name: "startTime"
          in: "query"
          description: "Only return test states at and after this time"
          type: "string"
          format: "date-time"
        - name: "endTime"
          in: "query"
          description: "Only return test states before this time"
          type: "string"
          format: "date-time"
      responses:
        "200":
          description: "Successfully retrieved test states"
          schema:
            $ref: "#/definitions/TestStates"
        "400":
          description: "Invalid parameter"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "500":
          description: "Internal server error"
          schema:
            $ref: "#/definitions/ErrorResponse"
    post:
      summary: "Create test state"
      operationId: "createTestState"
      consumes:
        - "application/json"
      produces:
        - "application/json"
      parameters:
        - in: "body"
          name: "testState"
          description: "Test state to create"
          required: true
          schema:
            $ref: "#/definitions/TestState"
      responses:
        "201":
          description: "Successfully created the test state"
          schema:
            $ref: "#/definitions/TestState"
        "400":
          description: "Invalid parameter"
          schema:
            $ref: "#/definitions/ErrorResponse"
        "500":
          description: "Internal server error"
          schema:
            $ref: "#/definitions/ErrorResponse"

definitions:
  ErrorResponse:
    type: "object"
    properties:
      message:
        description: "A message describing the error"
        type: "string"

  BuildPost:
    description: "Model for creating a new Build"
    type: "object"
    properties:
      name:
        description: "Name of the build to be used for grouping e.g. PR-1234, MAX"
        type: "string"
      pipeline:
        description: "The Cinder pipeline name"
        type: "string"
      trigger:
        description: "A description of what triggered this build e.g. user, cron"
        type: "string"
      githubOwner:
        description: "The GitHub owner for this build"
        type: "string"
      githubRepo:
        description: "The GitHub repository for this build"
        type: "string"
      gitSha:
        description: "The git sha being built"
        type: "string"
      gitBranch:
        description: "The git branch being built"
        type: "string"
      jobs:
        description: "List of jobs for this build"
        type: "array"
        items:
          $ref: "#/definitions/JobPost"
      pipedreamId:
        description: "Pipedream id for this build. If unset, defaults to the build/pipedream id in the URL"
        type: "string"
        format: "uuid"
    required:
      - "name"
      - "trigger"

  Build:
    description: "Groups multiple jobs together into a single build"
    type: "object"
    properties:
      id:
        description: "Build id for this build which may or may not be different than the pipedream id"
        type: "string"
        format: "uuid"
      name:
        description: "Name of the build to be used for grouping e.g. PR-1234, MAX"
        type: "string"
      pipeline:
        description: "The Cinder pipeline name"
        type: "string"
      trigger:
        description: "A description of what triggered this build e.g. user, cron"
        type: "string"
      githubOwner:
        description: "The GitHub owner for this build"
        type: "string"
      githubRepo:
        description: "The GitHub repository for this build"
        type: "string"
      gitSha:
        description: "The git sha being built"
        type: "string"
      gitBranch:
        description: "The git branch being built"
        type: "string"
      startTime:
        description: "Build's start time e.g. probably when it was put into the queue"
        type: "string"
        format: "date-time"
      pipedreamId:
        description: "The pipedream id for all of the build jobs"
        type: "string"
        format: "uuid"
      jobs:
        description: "List of jobs for this build"
        type: "array"
        items:
          $ref: "#/definitions/Job"
    required:
      - "name"
      - "trigger"

  PaginatedBuilds:
    type: "object"
    properties:
      builds:
        description: "The list of builds"
        type: "array"
        items:
          $ref: "#/definitions/Build"

  JobPost:
    description: "Model for creating a new Job"
    type: "object"
    properties:
      name:
        description: "Job name unique to this Build (typically matches the pipedream stage name)"
        type: "string"
      gitSha:
        description: "Git sha being built"
        type: "string"
      planKey:
        description: "Plan key defined in CI code e.g. cpu, gpu_optimized"
        type: "string"
      planName:
        description: "Plan name defined in CI code e.g. CPU, GPU Optimized"
        type: "string"
      deps:
        description: "List of job names that this job depends on"
        type: "array"
        items:
          type: "string"
      variables:
        $ref: "#/definitions/Variables"
    required:
      - "name"
      - "gitSha"
      - "planKey"
      - "planName"

  Job:
    description: "Job run as part of a build e.g. GPU, CPU, Clang, Custom Jobs"
    type: "object"
    properties:
      name:
        description: "Job name unique to this Build (typically matches the pipedream stage name)"
        type: "string"
        readOnly: true
      startTime:
        description: "Job's start time (perhaps after a small amount of setup e.g. git fetch)"
        type: "string"
        format: "date-time"
        readOnly: true
      endTime:
        description: "Job's end time"
        type: "string"
        format: "date-time"
        readOnly: true
      gitSha:
        description: "Git sha being built"
        type: "string"
      planKey:
        description: "Plan key defined in CI code e.g. cpu, gpu_optimized"
        type: "string"
      planName:
        description: "Plan name defined in CI code e.g. CPU, GPU Optimized"
        type: "string"
      result:
        $ref: "#/definitions/Result"
      stages:
        description: "List of stages for this job"
        readOnly: true
        type: "array"
        items:
          $ref: "#/definitions/Stage"
      metaData:
        $ref: "#/definitions/MetaDataDict"
      deps:
        description: "List of job names that this job depends on"
        type: "array"
        items:
          type: "string"
      variables:
        $ref: "#/definitions/Variables"
    required:
      - "gitSha"
      - "planKey"
      - "planName"

  JobPatch:
    description: "Updatable Job fields via PATCH endpoint. Setting the result to a 'completed' value sets the endTime too."
    type: "object"
    properties:
      result:
        $ref: "#/definitions/Result"

  Stage:
    description: "Logical grouping of work in a job e.g. Setup Script, Test."
    type: "object"
    properties:
      name:
        description: "Stage name e.g. Setup, Test"
        type: "string"
        readOnly: true
      startTime:
        description: "Stage's start time"
        type: "string"
        format: "date-time"
        readOnly: true
      endTime:
        description: "Stage's end time"
        type: "string"
        format: "date-time"
        readOnly: true
      result:
        $ref: "#/definitions/Result"

  StagePatch:
    description: "Updatable Stage fields via PATCH endpoint"
    type: "object"
    properties:
      result:
        $ref: "#/definitions/Result"

  Variables:
    description: "Input Variables"
    type: "object"
    additionalProperties:
      type: "string"

  MetaDataDict:
    description: "Meta data dictionary"
    type: "object"
    additionalProperties:
      type: "string"

  PaginatedTests:
    type: "object"
    properties:
      tests:
        description: "The list of tests"
        $ref: "#/definitions/TestResultList"

  TestResultList:
    type: "array"
    items:
      $ref: "#/definitions/TestResult"

  TestResult:
    type: "object"
    properties:
      id:
        description: "Unique id for the test result set by the server"
        type: "string"
        format: "uuid"
        readOnly: true
      bazelTarget:
        description: "Bazel target for this test"
        type: "string"
      shard:
        description: "Shard number for the test (1-indexed)"
        type: "integer"
      run:
        description: "Run number for the test typically for stress tests (1-indexed)"
        type: "integer"
      attempt:
        description: "Attempt number for the test typically for flaky tests (1-indexed)"
        type: "integer"
      startTime:
        description: "Test's start time"
        type: "string"
        format: "date-time"
      endTime:
        description: "Test's end time"
        type: "string"
        format: "date-time"
      result:
        description: "Test result"
        type: "string"
        enum:
          - "SUCCESS"
          - "FAILURE"
          - "TIMEOUT"
      logS3Uri:
        description: "S3 URI to log file if the log is available. The log should be uploaded using the uploadTestLog endpoint."
        type: "string"
      logUrl:
        description: "URL to log file if the log is available (see `logS3Uri`.)"
        type: "string"
        readOnly: true
      # Fields that are inherent to the Job that may or may not be returned in
      # the list test results endpoint.
      branch:
        description: "Test branch"
        type: "string"
      targetBranch:
        description: "Test target branch (for PRs)"
        type: "string"
      pullRequestId:
        description: "Test PR number"
        type: "integer"
        format: "int64"
      gitSha:
        description: "Git commit"
        type: "string"
      # Job identifying information.
      buildId:
        description: "Build id"
        type: "string"
      pipedreamId:
        description: "Pipedream id (deprecated - use buildId instead)"
        type: "string"
      jobName:
        description: "Job name"
        type: "string"
      planKey:
        description: "Plan key"
        type: "string"
    required:
      - "bazelTarget"
      - "shard"
      - "run"
      - "attempt"
      - "startTime"
      - "endTime"
      - "result"

  Result:
    type: "string"
    enum:
      - "QUEUED"
      - "PENDING"
      - "SUCCESS"
      - "FAILURE"
      - "TERMINATED"

  TestState:
    type: "object"
    properties:
      id:
        description: "Unique id for the test state set by the server"
        type: "string"
        format: "uuid"
        readOnly: true
      time:
        description: "Time of state change"
        type: "string"
        format: "date-time"
        readOnly: true
      bazelTarget:
        description: "Bazel test target"
        type: "string"
      state:
        description: "Test state"
        type: "string"
        enum:
          - "ENABLED"
          - "FLAKY"
          - "DISABLED"
      description:
        description: "Text describing why this state transition was made"
        type: "string"
      user:
        description: "The user making the state transition"
        type: "string"
      jira:
        description: "JIRA issue key tracking the work to fix the test"
        type: "string"
    required:
      - "bazelTarget"
      - "state"
      - "description"
      - "user"

  TestStates:
    type: "object"
    properties:
      testStates:
        type: "array"
        items:
          $ref: "#/definitions/TestState"
    required:
      - "testStates"

  TestTargetsList:
    type: "object"
    properties:
      testTargets:
        type: "array"
        items:
          type: "string"
    required:
      - "testTargets"

  TestLog:
    description: "Test log used for uploading"
    type: "object"
    properties:
      log:
        description: "Log output to store"
        type: "string"
    required:
      - "log"

  UploadTestLogResult:
    description: "Result of uploading a test log"
    type: "object"
    properties:
      s3Uri:
        description: "S3 URI for uploaded test log"
        type: "string"
        readOnly: true
    required:
      - "s3Uri"

  MessageList:
    type: "object"
    properties:
      messages:
        type: "array"
        items:
          $ref: "#/definitions/Message"

  Message:
    type: "object"
    properties:
      id:
        description: "Unique id for the message set by the server"
        type: "string"
        format: "uuid"
        readOnly: true
      time:
        description: "Time the message was created"
        type: "string"
        format: "date-time"
        readOnly: true
      title:
        description: "Title of the message"
        type: "string"
      severity:
        description: "Severity"
        type: "string"
        enum:
          - "SUCCESS"
          - "INFO"
          - "WARNING"
          - "ERROR"
      text:
        description: "Longform markdown text"
        type: "string"
    required:
      - "title"
      - "severity"
      - "text"
