From bab014f9bef72b6f16e480805736ed46c8b6ed87 Mon Sep 17 00:00:00 2001 From: NimRegev Date: Thu, 26 Sep 2024 07:33:34 +0300 Subject: [PATCH 01/11] Create analytics-api-examples.md --- _docs/api-examples/analytics-api-examples.md | 265 +++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 _docs/api-examples/analytics-api-examples.md diff --git a/_docs/api-examples/analytics-api-examples.md b/_docs/api-examples/analytics-api-examples.md new file mode 100644 index 000000000..68778ff9c --- /dev/null +++ b/_docs/api-examples/analytics-api-examples.md @@ -0,0 +1,265 @@ +--- +title: "Analytics API" +description: "" +group: api +toc: true +--- + + + +The Analytics API uses HTTP POST requests with JSON arguments and JSON responses. ???? + + +## Authorization +To make calls to the Analytics API, you need authorization through an API key passed in the header of the API request. + +>**NOTE** +The user who generates the API token must be an account administrator. +Currently, you do not need to select specific scopes for the API key. + +##### How to get the API key +1. From your avatar dropdown in the Codefresh toolbar, select **User Settings**. +1. Do one of the following: + * If you have an existing API key you have saved, use that key. + * To generate a new API key, click **Generate**. + 1. In **Key Name**, type a new name for the API key. + This name is displayed in the UI with random numbers and letters. + 1. Click **Create**. + 1. Copy the API key to a handy location. + + + + +## Get list of pipelines + +Gets the list of + + +### Headers +The API authorization token must be included in the header of the API request. See [Authorization](#authorization). + +``` +content-type: application/json +Authorization: +``` + +### Request body + +For a description of the fields, see [Request parameters](#request-parameters). + + + +### Request example + +The request is formatted in curl. + +``` +curl -X POST https://codefresh-hosted-gitops-runtime.com/api/promotions/commit \ + --header "content-type: application/json" \ + --header "Authorization: 214ffb**************" \ + --data +{ + \"srcAppId\": { + \"runtime\": \"codefresh\", + \"namespace\": \"orders-qa\", + \"name\": \"orders-qa-us-east\" + }, + \"destAppId\": { + \"runtime\": \"codefresh\", + \"namespace\": \"orders-prod\", + \"name\": \"orders-prod-us-east\" + }, + \"message\": \"Update image tag and bump version\" +}" +``` +### Response example + +#### Success +Here's an example of the response for a successful request. +It includes the: +* Commit SHA +* Commit message +* Name and email of the user who authored the commit + +``` +{"COMMIT_SHA":"ff46cab5a4c94fc2db215b2bd2102da05c5314ba","COMMIT_MESSAGE":"bumped version","COMMIT_AUTHOR":"codefresh-user "} +``` +#### Failure +Here's an example of the response for a failed request when there were no changes to promote between the source and the destination applications. + +``` +{"statusCode":400,"message":"no changes found between source and destination applications","error":"Bad Request"} +``` + + +## POST `/promotions/pullRequest` + +Promotes the application from the source environment to the destination or target environment through a `pull request` as the promotion action. + +### `pullRequest` request body + +``` +{ + "srcAppId": { + "runtime": "", + "namespace": "", + "name": "" + }, + "destAppId": { + "runtime": "", + "namespace": "", + "name": "" + }, + "head": "", + "title": "", + "description": "", + "commitDescription": "", + }" +``` + +### `pullRequest` request example +The request is formatted in curl. + +``` +curl -X POST https://codefresh-hosted-gitops-runtime.com/api/promotions/pullRequest \ + --header "content-type: application/json" \ + --header "Authorization: 214ffb**************" \ + --data "{ + \"srcAppId\": { + \"runtime\": \"codefresh\", + \"namespace\": \"membership-staging\", + \"name\": \"membership-staging\" + }, + \"destAppId\": { + \"runtime\": \"codefresh\", + \"namespace\": \"membership-prod\", + \"name\": \"membership-prod\" + }, + \"head\": \"main\", + \"title\": \"Merge new-accounts\", + \"description\": \"Added new accounts and git sources\", + \"commitMessage\": \"Merge new-accounts\", + \"commitDescription\": \"Approved new accounts and git sources\", + }" + +``` +### `pullRequest` response example + +#### Success +TBD + + +#### Failure +TBD + + + +## Request query parameters + +{: .table .table-bordered .table-hover} +| Parameter | Description | +| ---------- | -------- | +| `dateRange` | The time frame for which to send report data. This can be in the from-to format for a custom time frame, or a predefined fixed range.
For from-to date ranges, the format is `yyyy-mm-dd`. For example, `?dateRange=2024-04-30&dateRange=2023-08-01`. The from date must be earlier than the to date.
For fixed date ranges, use one of the following:
- `today`: Today's date.
- `Last 7 days`:
- `Last 30 days`: `dateRange=last%203%20month` (NIMA: need to find what are the fixed date ranges supported and how to add them?)| +| `filter` | | +| `granularity` | | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDescriptionData TypeRequired/Optional
dateRangeThe application in the source environment to promote through the runtime, namespace, and name key-value pairs.
srcAppId.runtime: The name of the GitOps Runtime associated with the source application.StringRequired
srcAppId.namespace: The namespace where the source application is deployed.StringRequired
srcAppId.name: The name of the source application to be promoted.StringRequired
destAppIdThe application in the destination environment to be promoted through the runtime, namespace, and name key-value pairs.
destAppId.runtime: The name of the GitOps Runtime associated with the application in the destination environment.StringRequired
destAppId.namespace: The namespace in the destination environment where the application being promoted is deployed.StringRequired
destAppId.name: The name of the application in the destination environment to be promoted.StringRequired
messageApplies to commit promotion actions.
The commit message to associate for the commit promotion action.(limits)
StringRequired
headApplies to pull request promotion actions.
The branch of the application in the destination environment on which to open the PR.
StringRequired
titleApplies to pull request promotion actions.
The title of the pull request.
StringRequired
descriptionApplies to pull request promotion actions.
Additional information describing the pull request.
StringOptional
commitMessageApplies to pull request promotion actions.
The commit message when the pull request is approved.
If omitted, uses title instead.
StringOptional
commitDescriptionApplies to pull request promotion actions.
Additional information on the commit message when the pull request is approved.
StringOptional
+ + + + + + From d09f265e6068d890ff3a46065fbf6c9479584d16 Mon Sep 17 00:00:00 2001 From: NimRegev Date: Thu, 26 Sep 2024 14:40:57 +0300 Subject: [PATCH 02/11] Update analytics-api-examples.md --- _docs/api-examples/analytics-api-examples.md | 246 +++++++++++++++++-- 1 file changed, 221 insertions(+), 25 deletions(-) diff --git a/_docs/api-examples/analytics-api-examples.md b/_docs/api-examples/analytics-api-examples.md index 68778ff9c..bdef44774 100644 --- a/_docs/api-examples/analytics-api-examples.md +++ b/_docs/api-examples/analytics-api-examples.md @@ -30,9 +30,10 @@ Currently, you do not need to select specific scopes for the API key. -## Get list of pipelines +## Get list of pipelines /pipelinesDropdown -Gets the list of +Gets the list of pipelines - max number? what are the default settings? +by pipeline name or ID. ### Headers @@ -51,47 +52,242 @@ For a description of the fields, see [Request parameters](#request-parameters). ### Request example -The request is formatted in curl. +The request is an HTTP GET request. ``` -curl -X POST https://codefresh-hosted-gitops-runtime.com/api/promotions/commit \ - --header "content-type: application/json" \ - --header "Authorization: 214ffb**************" \ - --data +GET https://g.codefresh.io/api/analytics/reports/pipelinesDropdown +``` +### Response example + +#### Success +Here's an example of the response for a successful request. + +For each pipeline, the following data is returned. +* `id`: The ID of the pipeline, generated when the pipeline was created. +* `pipelineName`: The full name of the pipeline, including the project name, in the format `"/"`. +* `shortName`: The name of the pipeline, without the project name. +* `isDeleted`: Indicates if the pipeline has been deleted from the account (`true`), or not (`false`). + +```json { - \"srcAppId\": { - \"runtime\": \"codefresh\", - \"namespace\": \"orders-qa\", - \"name\": \"orders-qa-us-east\" - }, - \"destAppId\": { - \"runtime\": \"codefresh\", - \"namespace\": \"orders-prod\", - \"name\": \"orders-prod-us-east\" + "data": [ + { + "id": "61a893f69ff69e2cf086f12d", + "pipelineName": "NimaCFProject/BasicPipeline", + "shortName": "basicpipeline", + "isDeleted": false + }, + { + "id": "632afb121899584bf3ec14f8", + "pipelineName": "default/NimaCronLink", + "shortName": "nimacronlink", + "isDeleted": false + }, + { + "id": "6372180f39b06e632745555d", + "pipelineName": "test", + "shortName": "test", + "isDeleted": false + }, + { + "id": "639ede86ec4d257410904ba7", + "pipelineName": "NimaCFProject/StepTest", + "shortName": "steptest", + "isDeleted": false + }, + { + "id": "63b58656e8dad136b2a74927", + "pipelineName": "my-first-project/My Pipeline", + "shortName": "my pipeline", + "isDeleted": false + }, + { + "id": "641fe3c0ba826b3e53d3bbbd", + "pipelineName": "TestTags", + "shortName": "testtags", + "isDeleted": false + }, + { + "id": "641fe485ba826b8fe8d3bbbe", + "pipelineName": "MyPipelines", + "shortName": "mypipelines", + "isDeleted": false + }, + { + "id": "6423edc4dbc27269e2693bb6", + "pipelineName": "NimaCFProject/Restart", + "shortName": "restart", + "isDeleted": false + }, + { + "id": "642578967afcb3664998231a", + "pipelineName": "AnnotatePipeline", + "shortName": "annotatepipeline", + "isDeleted": false + }, + { + "id": "64cb4160795de76fcd8b5b29", + "pipelineName": "MyPipelines template", + "shortName": "mypipelines template", + "isDeleted": false + }, + { + "id": "64cb42f2993fc4da530b8756", + "pipelineName": "mu", + "shortName": "mu", + "isDeleted": false + }, + + { + "id": "66f246ff58c8309825491a5a", + "pipelineName": "Marvel/smoke-tests", + "shortName": "smoke-tests", + "isDeleted": false + } + ] }, - \"message\": \"Update image tag and bump version\" -}" + + "timeDimensions": {} +``` + +#### Failure +Here's an example of the + +``` +{"statusCode":400,"message":"no changes found between source and destination applications","error":"Bad Request"} +``` + +## Get list of pipeline by name + +Get the list of pipelines that correspond to the name passed as the query parameter. +You can either pass the complete name of the pipeline or a partial name. In which case, returns all pipelines including those characters. +by pipeline name or ID. + + +### Headers +The API authorization token must be included in the header of the API request. See [Authorization](#authorization). + +``` +content-type: application/json +Authorization: +``` + +### Request body + +For a description of the fields, see [Request parameters](#request-parameters). + + + +### Request example + +The request is an HTTP GET request. + +``` +GET https://g.codefresh.io/api/analytics/reports/pipelinesDropdown/?filters={"name":[""]} ``` ### Response example #### Success Here's an example of the response for a successful request. -It includes the: -* Commit SHA -* Commit message -* Name and email of the user who authored the commit +For each pipeline, the following data is returned. +* `id`: The ID of the pipeline, generated when the pipeline was created. +* `pipelineName`: The full name of the pipeline, including the project name, in the format `"/"`. +* `shortName`: The name of the pipeline, without the project name. +* `isDeleted`: Indicates if the pipeline has been deleted from the account (`true`), or not (`false`). + +```json +{ + "data": [ + { + "id": "61a893f69ff69e2cf086f12d", + "pipelineName": "NimaCFProject/BasicPipeline", + "shortName": "basicpipeline", + "isDeleted": false + }, + { + "id": "632afb121899584bf3ec14f8", + "pipelineName": "default/NimaCronLink", + "shortName": "nimacronlink", + "isDeleted": false + }, + { + "id": "6372180f39b06e632745555d", + "pipelineName": "test", + "shortName": "test", + "isDeleted": false + }, + { + "id": "639ede86ec4d257410904ba7", + "pipelineName": "NimaCFProject/StepTest", + "shortName": "steptest", + "isDeleted": false + }, + { + "id": "63b58656e8dad136b2a74927", + "pipelineName": "my-first-project/My Pipeline", + "shortName": "my pipeline", + "isDeleted": false + }, + { + "id": "641fe3c0ba826b3e53d3bbbd", + "pipelineName": "TestTags", + "shortName": "testtags", + "isDeleted": false + }, + { + "id": "641fe485ba826b8fe8d3bbbe", + "pipelineName": "MyPipelines", + "shortName": "mypipelines", + "isDeleted": false + }, + { + "id": "6423edc4dbc27269e2693bb6", + "pipelineName": "NimaCFProject/Restart", + "shortName": "restart", + "isDeleted": false + }, + { + "id": "642578967afcb3664998231a", + "pipelineName": "AnnotatePipeline", + "shortName": "annotatepipeline", + "isDeleted": false + }, + { + "id": "64cb4160795de76fcd8b5b29", + "pipelineName": "MyPipelines template", + "shortName": "mypipelines template", + "isDeleted": false + }, + { + "id": "64cb42f2993fc4da530b8756", + "pipelineName": "mu", + "shortName": "mu", + "isDeleted": false + }, + + { + "id": "66f246ff58c8309825491a5a", + "pipelineName": "Marvel/smoke-tests", + "shortName": "smoke-tests", + "isDeleted": false + } + ] + }, + + "timeDimensions": {} ``` -{"COMMIT_SHA":"ff46cab5a4c94fc2db215b2bd2102da05c5314ba","COMMIT_MESSAGE":"bumped version","COMMIT_AUTHOR":"codefresh-user "} -``` + #### Failure -Here's an example of the response for a failed request when there were no changes to promote between the source and the destination applications. +Here's an example of the ``` {"statusCode":400,"message":"no changes found between source and destination applications","error":"Bad Request"} ``` + + ## POST `/promotions/pullRequest` Promotes the application from the source environment to the destination or target environment through a `pull request` as the promotion action. From a71408bf45ad403b0ac17c5d1ba8448900baf7ce Mon Sep 17 00:00:00 2001 From: NimRegev Date: Thu, 26 Sep 2024 18:23:57 +0300 Subject: [PATCH 03/11] Update analytics-api-examples.md --- _docs/api-examples/analytics-api-examples.md | 317 +------------------ 1 file changed, 12 insertions(+), 305 deletions(-) diff --git a/_docs/api-examples/analytics-api-examples.md b/_docs/api-examples/analytics-api-examples.md index bdef44774..dff892f9a 100644 --- a/_docs/api-examples/analytics-api-examples.md +++ b/_docs/api-examples/analytics-api-examples.md @@ -30,164 +30,34 @@ Currently, you do not need to select specific scopes for the API key. -## Get list of pipelines /pipelinesDropdown +## Get all pipelines/pipelines by name -Gets the list of pipelines - max number? what are the default settings? -by pipeline name or ID. +Retrieve all the pipelines in your account, or filter by a pipeline name or part of the name to retrieve a specific set of pipelines. +Filtering by a name retrieves those pipelines whose names match or contain the text in the filter string. ### Headers -The API authorization token must be included in the header of the API request. See [Authorization](#authorization). +The API authorization token must be included in the header of the GET request. See [Authorization](#authorization). -``` -content-type: application/json -Authorization: -``` - -### Request body - -For a description of the fields, see [Request parameters](#request-parameters). - - - -### Request example - -The request is an HTTP GET request. - -``` -GET https://g.codefresh.io/api/analytics/reports/pipelinesDropdown -``` -### Response example - -#### Success -Here's an example of the response for a successful request. - -For each pipeline, the following data is returned. -* `id`: The ID of the pipeline, generated when the pipeline was created. -* `pipelineName`: The full name of the pipeline, including the project name, in the format `"/"`. -* `shortName`: The name of the pipeline, without the project name. -* `isDeleted`: Indicates if the pipeline has been deleted from the account (`true`), or not (`false`). - -```json -{ - "data": [ - { - "id": "61a893f69ff69e2cf086f12d", - "pipelineName": "NimaCFProject/BasicPipeline", - "shortName": "basicpipeline", - "isDeleted": false - }, - { - "id": "632afb121899584bf3ec14f8", - "pipelineName": "default/NimaCronLink", - "shortName": "nimacronlink", - "isDeleted": false - }, - { - "id": "6372180f39b06e632745555d", - "pipelineName": "test", - "shortName": "test", - "isDeleted": false - }, - { - "id": "639ede86ec4d257410904ba7", - "pipelineName": "NimaCFProject/StepTest", - "shortName": "steptest", - "isDeleted": false - }, - { - "id": "63b58656e8dad136b2a74927", - "pipelineName": "my-first-project/My Pipeline", - "shortName": "my pipeline", - "isDeleted": false - }, - { - "id": "641fe3c0ba826b3e53d3bbbd", - "pipelineName": "TestTags", - "shortName": "testtags", - "isDeleted": false - }, - { - "id": "641fe485ba826b8fe8d3bbbe", - "pipelineName": "MyPipelines", - "shortName": "mypipelines", - "isDeleted": false - }, - { - "id": "6423edc4dbc27269e2693bb6", - "pipelineName": "NimaCFProject/Restart", - "shortName": "restart", - "isDeleted": false - }, - { - "id": "642578967afcb3664998231a", - "pipelineName": "AnnotatePipeline", - "shortName": "annotatepipeline", - "isDeleted": false - }, - { - "id": "64cb4160795de76fcd8b5b29", - "pipelineName": "MyPipelines template", - "shortName": "mypipelines template", - "isDeleted": false - }, - { - "id": "64cb42f2993fc4da530b8756", - "pipelineName": "mu", - "shortName": "mu", - "isDeleted": false - }, - { - "id": "66f246ff58c8309825491a5a", - "pipelineName": "Marvel/smoke-tests", - "shortName": "smoke-tests", - "isDeleted": false - } - ] - }, - "timeDimensions": {} -``` +### Endpoint -#### Failure -Here's an example of the +`GET https://g.codefresh.io/api/analytics/reports/pipelinesDropdown&filters={"name":["pipeline_name"]}` -``` -{"statusCode":400,"message":"no changes found between source and destination applications","error":"Bad Request"} -``` -## Get list of pipeline by name -Get the list of pipelines that correspond to the name passed as the query parameter. -You can either pass the complete name of the pipeline or a partial name. In which case, returns all pipelines including those characters. -by pipeline name or ID. +### Query parameters +` -### Headers -The API authorization token must be included in the header of the API request. See [Authorization](#authorization). - -``` -content-type: application/json -Authorization: -``` - -### Request body - -For a description of the fields, see [Request parameters](#request-parameters). - - - -### Request example +{: .table .table-bordered .table-hover} +| Setting | Description | Data Type | Required/Optional +| `name` | The name of the pipeline or a part of the name by which to filter the pipelines. For example, ??? retrieves only pipelines that match the whole name. `e-to-e` retrieves all pipelines that include `e-to-e` in their names. | string | Optional | -The request is an HTTP GET request. -``` -GET https://g.codefresh.io/api/analytics/reports/pipelinesDropdown/?filters={"name":[""]} -``` -### Response example -#### Success +#### Reponse Here's an example of the response for a successful request. For each pipeline, the following data is returned. @@ -288,171 +158,8 @@ Here's an example of the -## POST `/promotions/pullRequest` - -Promotes the application from the source environment to the destination or target environment through a `pull request` as the promotion action. - -### `pullRequest` request body - -``` -{ - "srcAppId": { - "runtime": "", - "namespace": "", - "name": "" - }, - "destAppId": { - "runtime": "", - "namespace": "", - "name": "" - }, - "head": "", - "title": "", - "description": "", - "commitDescription": "", - }" -``` - -### `pullRequest` request example -The request is formatted in curl. - -``` -curl -X POST https://codefresh-hosted-gitops-runtime.com/api/promotions/pullRequest \ - --header "content-type: application/json" \ - --header "Authorization: 214ffb**************" \ - --data "{ - \"srcAppId\": { - \"runtime\": \"codefresh\", - \"namespace\": \"membership-staging\", - \"name\": \"membership-staging\" - }, - \"destAppId\": { - \"runtime\": \"codefresh\", - \"namespace\": \"membership-prod\", - \"name\": \"membership-prod\" - }, - \"head\": \"main\", - \"title\": \"Merge new-accounts\", - \"description\": \"Added new accounts and git sources\", - \"commitMessage\": \"Merge new-accounts\", - \"commitDescription\": \"Approved new accounts and git sources\", - }" - -``` -### `pullRequest` response example - -#### Success -TBD - - -#### Failure -TBD - -## Request query parameters - -{: .table .table-bordered .table-hover} -| Parameter | Description | -| ---------- | -------- | -| `dateRange` | The time frame for which to send report data. This can be in the from-to format for a custom time frame, or a predefined fixed range.
For from-to date ranges, the format is `yyyy-mm-dd`. For example, `?dateRange=2024-04-30&dateRange=2023-08-01`. The from date must be earlier than the to date.
For fixed date ranges, use one of the following:
- `today`: Today's date.
- `Last 7 days`:
- `Last 30 days`: `dateRange=last%203%20month` (NIMA: need to find what are the fixed date ranges supported and how to add them?)| -| `filter` | | -| `granularity` | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ParameterDescriptionData TypeRequired/Optional
dateRangeThe application in the source environment to promote through the runtime, namespace, and name key-value pairs.
srcAppId.runtime: The name of the GitOps Runtime associated with the source application.StringRequired
srcAppId.namespace: The namespace where the source application is deployed.StringRequired
srcAppId.name: The name of the source application to be promoted.StringRequired
destAppIdThe application in the destination environment to be promoted through the runtime, namespace, and name key-value pairs.
destAppId.runtime: The name of the GitOps Runtime associated with the application in the destination environment.StringRequired
destAppId.namespace: The namespace in the destination environment where the application being promoted is deployed.StringRequired
destAppId.name: The name of the application in the destination environment to be promoted.StringRequired
messageApplies to commit promotion actions.
The commit message to associate for the commit promotion action.(limits)
StringRequired
headApplies to pull request promotion actions.
The branch of the application in the destination environment on which to open the PR.
StringRequired
titleApplies to pull request promotion actions.
The title of the pull request.
StringRequired
descriptionApplies to pull request promotion actions.
Additional information describing the pull request.
StringOptional
commitMessageApplies to pull request promotion actions.
The commit message when the pull request is approved.
If omitted, uses title instead.
StringOptional
commitDescriptionApplies to pull request promotion actions.
Additional information on the commit message when the pull request is approved.
StringOptional
From e2cfbc01db34c72d9a6a28574a9a94f0956093d8 Mon Sep 17 00:00:00 2001 From: NimRegev Date: Tue, 1 Oct 2024 16:37:39 +0300 Subject: [PATCH 04/11] Update analytics-api-examples.md --- _docs/api-examples/analytics-api-examples.md | 323 +++++++++++++++++-- 1 file changed, 303 insertions(+), 20 deletions(-) diff --git a/_docs/api-examples/analytics-api-examples.md b/_docs/api-examples/analytics-api-examples.md index dff892f9a..50d4e3e62 100644 --- a/_docs/api-examples/analytics-api-examples.md +++ b/_docs/api-examples/analytics-api-examples.md @@ -5,9 +5,15 @@ group: api toc: true --- +The Analytics API is a REST API that allows programmatic access to pipeline performance metrics, enabling you to generate custom reports and insights. +It leverages HTTP GET requests and returns data in JSON format, for seamless integration with your existing tools and systems. + +The API enables you to extract data on pipelines and pipeline builds at different levels. +Whether you're automating the collection of metrics for external dashboards or conducting in-depth analysis on pipeline efficiency, +the API offers granular access to performance data. +This ensures you can optimize pipeline configurations, identify bottlenecks, and drive continuous improvement within your workflows. -The Analytics API uses HTTP POST requests with JSON arguments and JSON responses. ???? ## Authorization @@ -32,35 +38,41 @@ Currently, you do not need to select specific scopes for the API key. ## Get all pipelines/pipelines by name -Retrieve all the pipelines in your account, or filter by a pipeline name or part of the name to retrieve a specific set of pipelines. -Filtering by a name retrieves those pipelines whose names match or contain the text in the filter string. - +Retrieves a list of all pipelines in your account, or filters pipelines based on a specific name or partial name. +Filtering by name returns pipelines whose names match or contain the specified text string. -### Headers -The API authorization token must be included in the header of the GET request. See [Authorization](#authorization). ### Endpoint -`GET https://g.codefresh.io/api/analytics/reports/pipelinesDropdown&filters={"name":["pipeline_name"]}` +`GET https://g.codefresh.io/api/analytics/reports/pipelinesDropdown` ### Query parameters -` {: .table .table-bordered .table-hover} | Setting | Description | Data Type | Required/Optional -| `name` | The name of the pipeline or a part of the name by which to filter the pipelines. For example, ??? retrieves only pipelines that match the whole name. `e-to-e` retrieves all pipelines that include `e-to-e` in their names. | string | Optional | +| `name` | The name of the pipeline or a part of the name by which to filter the pipelines. For example, filtering by `name`=`e-to-e` retrieves all pipelines that include `e-to-e` in their names. | [array] | Optional | + + +### Request examples + +##### For all pipelines +`GET https://g.codefresh.io/api/analytics/reports/pipelinesDropdown` +##### For pipeline by name -#### Reponse +`GET https://g.codefresh.io/api/analytics/reports/pipelinesDropdown&filters={"name":[array]}` + + +### Response Here's an example of the response for a successful request. -For each pipeline, the following data is returned. +For each pipeline, the response includes the following data: * `id`: The ID of the pipeline, generated when the pipeline was created. * `pipelineName`: The full name of the pipeline, including the project name, in the format `"/"`. * `shortName`: The name of the pipeline, without the project name. @@ -85,7 +97,7 @@ For each pipeline, the following data is returned. "id": "6372180f39b06e632745555d", "pipelineName": "test", "shortName": "test", - "isDeleted": false + "isDeleted": true }, { "id": "639ede86ec4d257410904ba7", @@ -97,7 +109,7 @@ For each pipeline, the following data is returned. "id": "63b58656e8dad136b2a74927", "pipelineName": "my-first-project/My Pipeline", "shortName": "my pipeline", - "isDeleted": false + "isDeleted": true }, { "id": "641fe3c0ba826b3e53d3bbbd", @@ -129,13 +141,6 @@ For each pipeline, the following data is returned. "shortName": "mypipelines template", "isDeleted": false }, - { - "id": "64cb42f2993fc4da530b8756", - "pipelineName": "mu", - "shortName": "mu", - "isDeleted": false - }, - { "id": "66f246ff58c8309825491a5a", "pipelineName": "Marvel/smoke-tests", @@ -148,6 +153,190 @@ For each pipeline, the following data is returned. "timeDimensions": {} ``` +### Failure +Here's an example of the + +``` +{"statusCode":400,"message":"no changes found between source and destination applications","error":"Bad Request"} +``` + +## Get average build duration +Retrieves the average execution duration of pipeline builds. +The average (mean) duration is calculated by dividing the total execution time by the number of builds, providing an overall measure of pipeline performance. + +### Endpoint +`GET https://g.codefresh.io/api/analytics/reports/buildAvgDuration?granularity=month` + + + +### Query parameters +{: .table .table-bordered .table-hover} +| Setting | Description | Data Type | Required/Optional| +| `dateRange` | The time frame for which to generate the report, from a minimum of one day to a maximum of six months. The start and end dates must be in `yyyy-mm-dd` (ISO 8601) formats. For example, `dateRange=2024-09-05dateRange=2024-09-01`. | string | Required | +| `granularity` | The level of detail or resolution at which to present the data in the report. The `granularity` levels depend on the `dateRange` defined. {::nomarkdown}
  • 0 days to 6 months: No granularity.
  • 1 to 4 days: hour.
  • 1 day to 3 months: day
  • Up to 6 months: week or month.
{:/} | string | Optional | +| `projectId` | The ID/IDs of the project(s) with the pipeline builds for which to include data. To include data for specific pipelines, omit this filter and use `pipelineId` instead. | array | Optional | +| `granularity` | The level of detail or resolution at which to present the data in the report. The `granularity` levels depend on the `dateRange` defined. {::nomarkdown}
  • Up to 6 months: No granularity.
  • 1 to 4 days: hour.
  • 1 day to 3 months: day
  • Up to 6 months: week or month.
    When omitted, the default granularity of ???? is used.
{:/} | string | Optional | +| `projectId` | The ID/IDs of the project(s) with the pipeline builds for which to include data. To include data for specific pipeline builds, omit this filter and use `pipelineId` instead. | array | Optional | +| `pipelineId` | The ID/IDs of the pipeline(s) for which to include data. To include data for all pipeline builds in a project, omit this filter, and use `projectId` instead. | array | Optional | +| `status` | The build statuses by which to filter pipelines.
Can be one of the following: {::nomarkdown}
  • error: Pipelines with builds that failed due to errors in the pipeline specifications or with failed steps.
  • succeeded: Pipelines with builds that completed successfully.
  • terminated: TPipelines with builds terminated by the system according to the policy defined in the pipeline's settings. See Build termination in pipeline policies.
{:/} | array | Optional | +| `isFavorites` | Include only project or pipelines that have been starred as favorites. (NIMA: what is the default)| boolean | Optional | + + +### Request examples + +##### With date range + +`GET https://g.codefresh.io/api/analytics/reports/buildAvgDuration?dateRange=2024-09-01&dateRange=2024-09-05` + + + +#### With date range filtered by project ID + + + +#### With date range filtered by pipeline ID + + +##### With date range filtered by build status + +GET `https://g.codefresh.io/api/analytics/reports/buildAvgDuration?dateRange=2024-09-01:2024-09-05&filters={"pipelineId":["648821e8bb1ff22b3e31f64c"]}` + +##### With date range and all filters + + +### Response + +Here's an example of a successful response. + + +```json +{ + "data": [ + { + "totalBuilds": "4", + "successfulBuilds": "4", + "successRate": 100, + "totalDuration": 72922, + "initializingDuration": 19224, + "runningDuration": 53698, + "pendingApprovalDuration": 0, + "pendingConcurrencyDuration": 0, + "delayDuration": 0 + } + ], + "timeDimensions": { + "dateRange": [ + "2024-09-01T00:00:00.000", + "2024-09-20T23:59:59.999" + ] + } +} +``` + + +The report includes the following fields: +* `totalBuilds`: The total number of pipeline builds that match the date range, the granularity, and other filters defined. +* `successfulBuilds`: The total number of pipeline builds that match the `status` filter if defined. When no `status` filters are defined, the report includes the number of successful builds. . +* `totalDuration`: The average time, in seconds, for a pipeline build to complete execution, calculated from the total number of builds that match the date range, the granularity, and other filters defined. +* `initializingDuration`: The average time, in seconds, for a pipeline build to complete the initialization phase of its execution. +* `runningDuration`: The average time, in seconds, that a pipeline build was in phase running. +* `pendingApprovalDuration`: The average time, in seconds, that a pipeline build was pending approval, meaning that execution was suspended until manual approval. +* `pendingConcurrencyDuration`: The average time, in seconds, that a pipeline build was pending execution due to the concurrency limits configured for the pipelines. Builds with concurrency limits at the pipeline, trigger, and branch levels are included in the calculation. +* `delayDuration`: The average time, in seconds, that a pipeline build was delayed from execution due to concurrency or license limits configured for the pipelines. +* `timeDimensions.dateRange`: The start and end dates for which the report was generated. + + + + + +#### Failure +Here's an example of the + +``` +{"statusCode":400,"message":"no changes found between source and destination applications","error":"Bad Request"} +``` + + +## Get build duration by median percentile (P50) +Retrieves the median (P50) success rate and execution duration for pipeline builds. +The median, or 50th percentile, is a key measure for understanding typical build times, as it represents the middle value of all build durations. + +This metric helps you assess the overall performance without being skewed by outliers, such as exceptionally fast or slow builds. + + + +### Endpoint + +`GET https://g.codefresh.io/api/analytics/reports/buildP50Duration&dateRange=` + + + +### Query parameters +{: .table .table-bordered .table-hover} +| Setting | Description | Data Type | Required/Optional| +|`dateRange` | The time frame for which to generate the report, from a minimum of one day to a maximum of six months. The start and end dates must be in `yyyy-mm-dd` (ISO 8601) formats. For example, `dateRange=2024-09-05dateRange=2024-09-01`. | string | Required | +|`granularity` | The level of detail or resolution at which to present the data in the report. The `granularity` levels depend on the `dateRange` defined. {::nomarkdown}
  • Up to 6 months: No granularity.
  • 1 to 4 days: hour.
  • 1 day to 3 months: day
  • Up to 6 months: week or month.
    When omitted, the default granularity of ???? is used.
{:/} | string | Optional | +|`projectId` | The ID/IDs of the project(s) with the pipeline builds for which to include data. To include data for specific pipeline builds, omit this filter and use `pipelineId` instead. | array | Optional | +|`pipelineId` | The ID/IDs of the pipeline(s) for which to include data. To include data for all pipeline builds in a project, omit this filter, and use `projectId` instead. | array | Optional | +|`status` | The build statuses by which to filter pipelines.
Can be one of the following: {::nomarkdown}
  • error: Pipelines with builds that failed due to errors in the pipeline specifications or with failed steps.
  • succeeded: Pipelines with builds that completed successfully.
  • terminated: TPipelines with builds terminated by the system according to the policy defined in the pipeline's settings. See Build termination in pipeline policies.
{:/} | array | Optional | +|`isFavorites` | Include only project or pipelines that have been starred as favorites. (NIMA: what is the default)| boolean | Optional | + + +### Request examples + +##### With date range + +`GET https://g.codefresh.io/api/analytics/reports/buildAvgDuration?dateRange=2024-09-01&dateRange=2024-09-05` + + + +##### With date range filtered by project ID + + + +##### With date range filtered by pipeline ID + + +##### With date range filtered by build status + +GET `https://g.codefresh.io/api/analytics/reports/buildAvgDuration?dateRange=2024-09-01:2024-09-05&filters={"pipelineId":["648821e8bb1ff22b3e31f64c"]}` + +##### With date range and all filters + + +### Response + +Here's an example of a successful response. + + +TBD + + + +The report includes the following fields: +* `time`: The granularity defined for the report according to the date range defined. +* `totalBuilds`: The total number of pipeline builds that match the specified date range, granularity, and any additional filters defined. +* `successfulBuilds`: The total number of pipeline builds that match the `status` filter if defined. If a `status` filter is not defined, this represents the total number of successful builds. +* `successRate`: The percentage of builds that completed successfully, out of the total number of builds. +* `totalDuration`: The average duration, in seconds, for 50% of the pipeline builds to complete, calculated from the total number of builds that match the date range, granularity, and any additional filters defined. +* `initializingDuration`: The average time, in seconds, for 50% of the pipeline builds to complete the initialization phase of execution. +* `runningDuration`: The average time, in seconds, for which 50% of the pipeline builds were in the running phase. +* `pendingApprovalDuration`: The average time, in seconds, during which 50% of the pipeline builds were pending manual approval, suspending execution. +* `pendingConcurrencyDuration`: The average time, in seconds, during which 50% of the pipeline builds were suspended specifically due to the concurrency limits configured for the pipelines +at the pipeline, trigger, and branch levels. +* `delayDuration`: The average time, in seconds, for which 50% of the pipeline builds were delayed due to concurrency or license limits configured for the pipelines. +* `timeDimensions.dateRange`: The start and end dates defining the time frame for which the report is generated. + + + + + #### Failure Here's an example of the @@ -156,13 +345,107 @@ Here's an example of the ``` +## Get build duration by 90th percentile (P90) + +Retrieves the success rate and execution duration for the 90th percentile (P90) of pipeline builds. +The 90th percentile indicates the upper limit within which 90% of builds are completed. + +This metric is useful for identifying performance issues that affect the slowest 10% of builds, enabling you to focus on optimizing these outliers. + + + +### Endpoint + +`GET https://g.codefresh.io/api/analytics/reports/buildP90Duration&dateRange=` + + + +### Query parameters +{: .table .table-bordered .table-hover} +| Setting | Description | Data Type | Required/Optional| +|`dateRange` | The time frame for which to generate the report, from a minimum of one day to a maximum of six months. The start and end dates must be in `yyyy-mm-dd` (ISO 8601) formats. For example, `dateRange=2024-09-05dateRange=2024-09-01`. | string | Required | +|`granularity` | The level of detail or resolution at which to present the data in the report. The `granularity` levels depend on the `dateRange` defined. {::nomarkdown}
  • Up to 6 months: No granularity.
  • 1 to 4 days: hour.
  • 1 day to 3 months: day
  • Up to 6 months: week or month.
    When omitted, the default granularity of ???? is used.
{:/} | string | Optional | +|`projectId` | The ID/IDs of the project(s) with the pipeline builds for which to include data. To include data for specific pipeline builds, omit this filter and use `pipelineId` instead. | array | Optional | +|`pipelineId` | The ID/IDs of the pipeline(s) for which to include data. To include data for all pipeline builds in a project, omit this filter, and use `projectId` instead. | array | Optional | +|`status` | The build statuses by which to filter pipelines.
Can be one of the following: {::nomarkdown}
  • error: Pipelines with builds that failed due to errors in the pipeline specifications or with failed steps.
  • succeeded: Pipelines with builds that completed successfully.
  • terminated: TPipelines with builds terminated by the system according to the policy defined in the pipeline's settings. See Build termination in pipeline policies.
{:/} | array | Optional | +|`isFavorites` | Include only project or pipelines that have been starred as favorites. (NIMA: what is the default)| boolean | Optional | + + +### Request examples + +##### With date range + +`GET https://g.codefresh.io/api/analytics/reports/buildP90Duration?dateRange=2024-09-01&dateRange=2024-09-05` + + + +##### With date range filtered by project ID + + + +##### With date range filtered by pipeline ID + + +##### With date range filtered by build status + +GET `https://g.codefresh.io/api/analytics/reports/buildAvgDuration?dateRange=2024-09-01:2024-09-05&filters={"pipelineId":["648821e8bb1ff22b3e31f64c"]}` + +##### With date range and all filters + + +### Response + +Here's an example of a successful response. + + +TBD + + + +The report includes the following fields: +* `time`: The granularity defined for the report according to the date range defined. +* `totalBuilds`: The total number of pipeline builds that match the specified date range, granularity, and any additional filters defined. +* `successfulBuilds`: The total number of pipeline builds that match the `status` filter if defined. If a `status` filter is not defined, this represents the total number of successful builds. +* `successRate`: The percentage of builds that completed successfully, out of the total number of builds. +* `totalDuration`: The average duration, in seconds, for 50% of the pipeline builds to complete, calculated from the total number of builds that match the date range, granularity, and any additional filters defined. +* `initializingDuration`: The average time, in seconds, for 50% of the pipeline builds to complete the initialization phase of execution. +* `runningDuration`: The average time, in seconds, for which 50% of the pipeline builds were in the running phase. +* `pendingApprovalDuration`: The average time, in seconds, during which 50% of the pipeline builds were pending manual approval, suspending execution. +* `pendingConcurrencyDuration`: The average time, in seconds, during which 50% of the pipeline builds were suspended specifically due to the concurrency limits configured for the pipelines +at the pipeline, trigger, and branch levels. +* `delayDuration`: The average time, in seconds, for which 50% of the pipeline builds were delayed due to concurrency or license limits configured for the pipelines. +* `timeDimensions.dateRange`: The start and end dates defining the time frame for which the report is generated. + + + + + +#### Failure + + + +## Get average duration of pipelines +Retrieves a list of pipelines along with their average execution duration. +The average (mean) duration is calculated by dividing the total execution time by the number of pipeline runs, providing an overall assessment of pipeline performance. + +## Get pipelines with median (P50) duration +Retrieves a list of pipelines based on their median (P50) execution duration. +The P50 duration represents the time within which 50% of pipeline executions are completed, highlighting typical pipeline performance. +This metrics is useful to analyze typical pipeline performance while excluding extreme outliers. +## Get pipelines with 90th percentitle (P90) median duration +Retrieves a list of pipelines based on their 90th percentile (P90) execution duration. +The P90 represents the time within which 90% of pipeline executions are completed, highlighting the upper range of build durations while excluding the slowest 10%. +This metric is useful for identifying and addressing performance issues that affect a small minority of pipeline executions. From 1e2fc166458b08422f1ee8e40813c088bc645f0a Mon Sep 17 00:00:00 2001 From: NimRegev Date: Sun, 6 Oct 2024 10:19:41 +0300 Subject: [PATCH 05/11] Update analytics-api-examples.md --- _docs/api-examples/analytics-api-examples.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/_docs/api-examples/analytics-api-examples.md b/_docs/api-examples/analytics-api-examples.md index 50d4e3e62..2de4ebb38 100644 --- a/_docs/api-examples/analytics-api-examples.md +++ b/_docs/api-examples/analytics-api-examples.md @@ -8,7 +8,8 @@ toc: true The Analytics API is a REST API that allows programmatic access to pipeline performance metrics, enabling you to generate custom reports and insights. It leverages HTTP GET requests and returns data in JSON format, for seamless integration with your existing tools and systems. -The API enables you to extract data on pipelines and pipeline builds at different levels. +The API enables you to extract KPI data on pipelines and pipeline builds at different levels. + Whether you're automating the collection of metrics for external dashboards or conducting in-depth analysis on pipeline efficiency, the API offers granular access to performance data. This ensures you can optimize pipeline configurations, identify bottlenecks, and drive continuous improvement within your workflows. @@ -164,6 +165,8 @@ Here's an example of the Retrieves the average execution duration of pipeline builds. The average (mean) duration is calculated by dividing the total execution time by the number of builds, providing an overall measure of pipeline performance. +You can filter pipeline builds by either a project, specific pipeline, status, or by the favorites tag. + ### Endpoint `GET https://g.codefresh.io/api/analytics/reports/buildAvgDuration?granularity=month` From 129faf5629b3e21bed79e0ba10ea99ce828be0c6 Mon Sep 17 00:00:00 2001 From: NimRegev Date: Sun, 6 Oct 2024 13:25:38 +0300 Subject: [PATCH 06/11] Update nav.yml Added entry to nav yaml --- _data/nav.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/_data/nav.yml b/_data/nav.yml index a38c23c98..b0531fc0a 100644 --- a/_data/nav.yml +++ b/_data/nav.yml @@ -579,6 +579,12 @@ - title: Managing Git PATs url: "/manage-pats" +- title: API + url: "/api-examples" + pages: + - title: Analytics API + url: "/analytics-api-examples" + - title: Reference url: "/reference" pages: @@ -587,6 +593,7 @@ - title: Secrets url: "/secrets" + - title: What's new url: "/whats-new" pages: From 746c40a1c9943da3df487d249048132e29243d4d Mon Sep 17 00:00:00 2001 From: NimRegev Date: Tue, 8 Oct 2024 10:17:16 +0300 Subject: [PATCH 07/11] Update analytics-api-examples.md --- _docs/api-examples/analytics-api-examples.md | 48 +++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/_docs/api-examples/analytics-api-examples.md b/_docs/api-examples/analytics-api-examples.md index 2de4ebb38..36fbacc0c 100644 --- a/_docs/api-examples/analytics-api-examples.md +++ b/_docs/api-examples/analytics-api-examples.md @@ -47,7 +47,8 @@ Filtering by name returns pipelines whose names match or contain the specified t ### Endpoint -`GET https://g.codefresh.io/api/analytics/reports/pipelinesDropdown` +`GET https://g.codefresh.io/api/analytics/reports/pipelinesDropdown&filters={"name":[array]}` + @@ -55,8 +56,9 @@ Filtering by name returns pipelines whose names match or contain the specified t {: .table .table-bordered .table-hover} -| Setting | Description | Data Type | Required/Optional -| `name` | The name of the pipeline or a part of the name by which to filter the pipelines. For example, filtering by `name`=`e-to-e` retrieves all pipelines that include `e-to-e` in their names. | [array] | Optional | +| Parameter | Description | Data Type | Required/Optional | +| ------------ | -------------- | ------ | ------------------| +| `filters`| `name`: The name of the pipeline or a part of the name by which to filter the pipelines.
For example, filtering by `name`=`e-to-e` retrieves all pipelines that include `e-to-e` in their names. | [array] | Optional | ### Request examples @@ -162,27 +164,28 @@ Here's an example of the ``` ## Get average build duration -Retrieves the average execution duration of pipeline builds. +Retrieves the average execution duration of pipeline builds for the specified time frame. The average (mean) duration is calculated by dividing the total execution time by the number of builds, providing an overall measure of pipeline performance. -You can filter pipeline builds by either a project, specific pipeline, status, or by the favorites tag. +You can filter build data by either a project, a specific pipeline, status, or by the favorites tag. ### Endpoint -`GET https://g.codefresh.io/api/analytics/reports/buildAvgDuration?granularity=month` +`GET https://g.codefresh.io/api/analytics/reports/buildAvgDuration?dateRange=granularity=?filters={"filter-type":[array]}` ### Query parameters + {: .table .table-bordered .table-hover} | Setting | Description | Data Type | Required/Optional| +| -----------|-----------------|-----------|------------------| | `dateRange` | The time frame for which to generate the report, from a minimum of one day to a maximum of six months. The start and end dates must be in `yyyy-mm-dd` (ISO 8601) formats. For example, `dateRange=2024-09-05dateRange=2024-09-01`. | string | Required | | `granularity` | The level of detail or resolution at which to present the data in the report. The `granularity` levels depend on the `dateRange` defined. {::nomarkdown}
  • 0 days to 6 months: No granularity.
  • 1 to 4 days: hour.
  • 1 day to 3 months: day
  • Up to 6 months: week or month.
{:/} | string | Optional | -| `projectId` | The ID/IDs of the project(s) with the pipeline builds for which to include data. To include data for specific pipelines, omit this filter and use `pipelineId` instead. | array | Optional | -| `granularity` | The level of detail or resolution at which to present the data in the report. The `granularity` levels depend on the `dateRange` defined. {::nomarkdown}
  • Up to 6 months: No granularity.
  • 1 to 4 days: hour.
  • 1 day to 3 months: day
  • Up to 6 months: week or month.
    When omitted, the default granularity of ???? is used.
{:/} | string | Optional | -| `projectId` | The ID/IDs of the project(s) with the pipeline builds for which to include data. To include data for specific pipeline builds, omit this filter and use `pipelineId` instead. | array | Optional | -| `pipelineId` | The ID/IDs of the pipeline(s) for which to include data. To include data for all pipeline builds in a project, omit this filter, and use `projectId` instead. | array | Optional | -| `status` | The build statuses by which to filter pipelines.
Can be one of the following: {::nomarkdown}
  • error: Pipelines with builds that failed due to errors in the pipeline specifications or with failed steps.
  • succeeded: Pipelines with builds that completed successfully.
  • terminated: TPipelines with builds terminated by the system according to the policy defined in the pipeline's settings. See Build termination in pipeline policies.
{:/} | array | Optional | -| `isFavorites` | Include only project or pipelines that have been starred as favorites. (NIMA: what is the default)| boolean | Optional | +| `filters` | The filters by which to narrow the scope of the build data. Can be any of the following: +| | `projectId`: The ID/IDs of the project(s) with the pipeline builds for which to include data. To include data for specific pipelines, omit this filter and use `pipelineId` instead. | array | Optional | +| | `pipelineId`: The ID/IDs of the pipeline(s) for which to include data. To include data for all pipeline builds in a project, omit this filter, and use `projectId` instead. | array | Optional | +| | `status`: The build statuses by which to filter pipelines.
Can be one of the following: {::nomarkdown}
  • error: Pipelines with builds that failed due to errors in the pipeline specifications or with failed steps.
  • succeeded: Pipelines with builds that completed successfully.
  • terminated: TPipelines with builds terminated by the system according to the policy defined in the pipeline's settings. See Build termination in pipeline policies.
{:/} | array | Optional | +| | `isFavorites`: Include only project or pipelines that have been starred as favorites. (NIMA: what is the default)| boolean | Optional | ### Request examples @@ -282,10 +285,11 @@ This metric helps you assess the overall performance without being skewed by out | Setting | Description | Data Type | Required/Optional| |`dateRange` | The time frame for which to generate the report, from a minimum of one day to a maximum of six months. The start and end dates must be in `yyyy-mm-dd` (ISO 8601) formats. For example, `dateRange=2024-09-05dateRange=2024-09-01`. | string | Required | |`granularity` | The level of detail or resolution at which to present the data in the report. The `granularity` levels depend on the `dateRange` defined. {::nomarkdown}
  • Up to 6 months: No granularity.
  • 1 to 4 days: hour.
  • 1 day to 3 months: day
  • Up to 6 months: week or month.
    When omitted, the default granularity of ???? is used.
{:/} | string | Optional | -|`projectId` | The ID/IDs of the project(s) with the pipeline builds for which to include data. To include data for specific pipeline builds, omit this filter and use `pipelineId` instead. | array | Optional | -|`pipelineId` | The ID/IDs of the pipeline(s) for which to include data. To include data for all pipeline builds in a project, omit this filter, and use `projectId` instead. | array | Optional | -|`status` | The build statuses by which to filter pipelines.
Can be one of the following: {::nomarkdown}
  • error: Pipelines with builds that failed due to errors in the pipeline specifications or with failed steps.
  • succeeded: Pipelines with builds that completed successfully.
  • terminated: TPipelines with builds terminated by the system according to the policy defined in the pipeline's settings. See Build termination in pipeline policies.
{:/} | array | Optional | -|`isFavorites` | Include only project or pipelines that have been starred as favorites. (NIMA: what is the default)| boolean | Optional | +| `filters` | The filters by which to narrow the scope of the build data. Can be any of the following: +| | `projectId`: The ID/IDs of the project(s) with the pipeline builds for which to include data. To include data for specific pipelines, omit this filter and use `pipelineId` instead. | array | Optional | +| | `pipelineId`: The ID/IDs of the pipeline(s) for which to include data. To include data for all pipeline builds in a project, omit this filter, and use `projectId` instead. | array | Optional | +| | `status`: The build statuses by which to filter pipelines.
Can be one of the following: {::nomarkdown}
  • error: Pipelines with builds that failed due to errors in the pipeline specifications or with failed steps.
  • succeeded: Pipelines with builds that completed successfully.
  • terminated: TPipelines with builds terminated by the system according to the policy defined in the pipeline's settings. See Build termination in pipeline policies.
{:/} | array | Optional | +| | `isFavorites`: Include only project or pipelines that have been starred as favorites. (NIMA: what is the default)| boolean | Optional | ### Request examples @@ -344,7 +348,7 @@ at the pipeline, trigger, and branch levels. Here's an example of the ``` -{"statusCode":400,"message":"no changes found between source and destination applications","error":"Bad Request"} + ``` @@ -368,11 +372,11 @@ This metric is useful for identifying performance issues that affect the slowest | Setting | Description | Data Type | Required/Optional| |`dateRange` | The time frame for which to generate the report, from a minimum of one day to a maximum of six months. The start and end dates must be in `yyyy-mm-dd` (ISO 8601) formats. For example, `dateRange=2024-09-05dateRange=2024-09-01`. | string | Required | |`granularity` | The level of detail or resolution at which to present the data in the report. The `granularity` levels depend on the `dateRange` defined. {::nomarkdown}
  • Up to 6 months: No granularity.
  • 1 to 4 days: hour.
  • 1 day to 3 months: day
  • Up to 6 months: week or month.
    When omitted, the default granularity of ???? is used.
{:/} | string | Optional | -|`projectId` | The ID/IDs of the project(s) with the pipeline builds for which to include data. To include data for specific pipeline builds, omit this filter and use `pipelineId` instead. | array | Optional | -|`pipelineId` | The ID/IDs of the pipeline(s) for which to include data. To include data for all pipeline builds in a project, omit this filter, and use `projectId` instead. | array | Optional | -|`status` | The build statuses by which to filter pipelines.
Can be one of the following: {::nomarkdown}
  • error: Pipelines with builds that failed due to errors in the pipeline specifications or with failed steps.
  • succeeded: Pipelines with builds that completed successfully.
  • terminated: TPipelines with builds terminated by the system according to the policy defined in the pipeline's settings. See Build termination in pipeline policies.
{:/} | array | Optional | -|`isFavorites` | Include only project or pipelines that have been starred as favorites. (NIMA: what is the default)| boolean | Optional | - +| `filters` | The filters by which to narrow the scope of the build data. Can be any of the following: +| | `projectId`: The ID/IDs of the project(s) with the pipeline builds for which to include data. To include data for specific pipelines, omit this filter and use `pipelineId` instead. | array | Optional | +| | `pipelineId`: The ID/IDs of the pipeline(s) for which to include data. To include data for all pipeline builds in a project, omit this filter, and use `projectId` instead. | array | Optional | +| | `status`: The build statuses by which to filter pipelines.
Can be one of the following: {::nomarkdown}
  • error: Pipelines with builds that failed due to errors in the pipeline specifications or with failed steps.
  • succeeded: Pipelines with builds that completed successfully.
  • terminated: TPipelines with builds terminated by the system according to the policy defined in the pipeline's settings. See Build termination in pipeline policies.
{:/} | array | Optional | +| | `isFavorites`: Include only project or pipelines that have been starred as favorites. (NIMA: what is the default)| boolean | Optional | ### Request examples From 7da0219dca7ff326c3108398187f7877be9a6325 Mon Sep 17 00:00:00 2001 From: NimRegev Date: Tue, 8 Oct 2024 10:38:01 +0300 Subject: [PATCH 08/11] Update analytics-api-examples.md --- _docs/api-examples/analytics-api-examples.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_docs/api-examples/analytics-api-examples.md b/_docs/api-examples/analytics-api-examples.md index 36fbacc0c..d4365dc25 100644 --- a/_docs/api-examples/analytics-api-examples.md +++ b/_docs/api-examples/analytics-api-examples.md @@ -179,7 +179,7 @@ You can filter build data by either a project, a specific pipeline, status, or b {: .table .table-bordered .table-hover} | Setting | Description | Data Type | Required/Optional| | -----------|-----------------|-----------|------------------| -| `dateRange` | The time frame for which to generate the report, from a minimum of one day to a maximum of six months. The start and end dates must be in `yyyy-mm-dd` (ISO 8601) formats. For example, `dateRange=2024-09-05dateRange=2024-09-01`. | string | Required | +| `dateRange` | The time frame for which to generate the report, from a minimum of one day to a maximum of six months. The start and end dates must be in `yyyy-mm-dd` (ISO 8601) formats. For example, `dateRange=2024-09-05dateRange=2024-09-01`. | string | Required | | `granularity` | The level of detail or resolution at which to present the data in the report. The `granularity` levels depend on the `dateRange` defined. {::nomarkdown}
  • 0 days to 6 months: No granularity.
  • 1 to 4 days: hour.
  • 1 day to 3 months: day
  • Up to 6 months: week or month.
{:/} | string | Optional | | `filters` | The filters by which to narrow the scope of the build data. Can be any of the following: | | `projectId`: The ID/IDs of the project(s) with the pipeline builds for which to include data. To include data for specific pipelines, omit this filter and use `pipelineId` instead. | array | Optional | From e113fc2a4eb393d723c1bd4a295f4e9e79a9010e Mon Sep 17 00:00:00 2001 From: NimRegev Date: Mon, 18 Nov 2024 12:58:43 +0200 Subject: [PATCH 09/11] Update analytics-api-examples.md --- _docs/api-examples/analytics-api-examples.md | 62 ++++++++++++++------ 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/_docs/api-examples/analytics-api-examples.md b/_docs/api-examples/analytics-api-examples.md index d4365dc25..abf0de71e 100644 --- a/_docs/api-examples/analytics-api-examples.md +++ b/_docs/api-examples/analytics-api-examples.md @@ -156,7 +156,7 @@ For each pipeline, the response includes the following data: "timeDimensions": {} ``` -### Failure +### Here's an example of the ``` @@ -167,10 +167,10 @@ Here's an example of the Retrieves the average execution duration of pipeline builds for the specified time frame. The average (mean) duration is calculated by dividing the total execution time by the number of builds, providing an overall measure of pipeline performance. -You can filter build data by either a project, a specific pipeline, status, or by the favorites tag. +You can filter build data either by a project, a specific pipeline, status, or by the favorites tag. ### Endpoint -`GET https://g.codefresh.io/api/analytics/reports/buildAvgDuration?dateRange=granularity=?filters={"filter-type":[array]}` +`GET https://g.codefresh.io/api/analytics/reports/buildAvgDuration?dateRange=&dateRange=?granularity=?filters={"filter-type":[array]}` @@ -179,39 +179,57 @@ You can filter build data by either a project, a specific pipeline, status, or b {: .table .table-bordered .table-hover} | Setting | Description | Data Type | Required/Optional| | -----------|-----------------|-----------|------------------| -| `dateRange` | The time frame for which to generate the report, from a minimum of one day to a maximum of six months. The start and end dates must be in `yyyy-mm-dd` (ISO 8601) formats. For example, `dateRange=2024-09-05dateRange=2024-09-01`. | string | Required | -| `granularity` | The level of detail or resolution at which to present the data in the report. The `granularity` levels depend on the `dateRange` defined. {::nomarkdown}
  • 0 days to 6 months: No granularity.
  • 1 to 4 days: hour.
  • 1 day to 3 months: day
  • Up to 6 months: week or month.
{:/} | string | Optional | +| `dateRange` | The time frame for which to generate the report, from a minimum of one day to a maximum of six months. The start and end dates must be in `yyyy-mm-dd` (ISO 8601) formats. For example, `dateRange=2024-09-05&dateRange=2024-09-01`. | string | Required | +| `granularity` | The level of detail or resolution at which to present the data in the report. The `granularity` levels depend on the `dateRange` defined. {::nomarkdown}
  • 0 days to 6 months: No granularity. This means that data is aggregated for the entire time frame.
  • 1 to 4 days: hour.
  • 1 day to 3 months: day
  • Up to 6 months: week .
{:/} | string | Optional | | `filters` | The filters by which to narrow the scope of the build data. Can be any of the following: | | `projectId`: The ID/IDs of the project(s) with the pipeline builds for which to include data. To include data for specific pipelines, omit this filter and use `pipelineId` instead. | array | Optional | | | `pipelineId`: The ID/IDs of the pipeline(s) for which to include data. To include data for all pipeline builds in a project, omit this filter, and use `projectId` instead. | array | Optional | -| | `status`: The build statuses by which to filter pipelines.
Can be one of the following: {::nomarkdown}
  • error: Pipelines with builds that failed due to errors in the pipeline specifications or with failed steps.
  • succeeded: Pipelines with builds that completed successfully.
  • terminated: TPipelines with builds terminated by the system according to the policy defined in the pipeline's settings. See Build termination in pipeline policies.
{:/} | array | Optional | -| | `isFavorites`: Include only project or pipelines that have been starred as favorites. (NIMA: what is the default)| boolean | Optional | +| | `status`: The build statuses by which to filter pipelines.
Can be one of the following: {::nomarkdown}
  • success: Pipelines with builds that completed successfully.
  • error: Pipelines with builds that failed due to errors in the pipeline specifications or with failed steps.
  • terminated: Pipelines with builds terminated by the system according to the policy defined in the pipeline's settings. See Build termination in pipeline policies.
{:/} | array | Optional | +| | `isFavorites`: Include only projecs or pipelines that have been starred as favorites. By default (`false`), returns all pipelines.
Can be one of the following: {::nomarkdown}
  • true: Not the default. Returns only projects or pipelines tagged as favorites.
  • false: The default, returns all pipelines.
{:/} Remember to define value without quotes.| boolean | Optional | ### Request examples -##### With date range +##### With date range and no granularity and filters + +Retrieves the average build duration for all builds within the specified date range. Because granularity is not specified, the build data is aggregated for the date range. + +`GET https://g.codefresh.io/api/analytics/reports/buildAvgDuration?dateRange=2024-09-01&dateRange=2024-09-30` -`GET https://g.codefresh.io/api/analytics/reports/buildAvgDuration?dateRange=2024-09-01&dateRange=2024-09-05` - -#### With date range filtered by project ID +##### With date range filtered by project ID +Retrieves the average build duration for all pipeline builds associated with the specified project ID within the date range. + +`GET https://g.codefresh.io/api/analytics/reports/buildAvgDuration?dateRange=2024-09-01&dateRange=2024-09-3301&filters={"projectId":["argo"]}` #### With date range filtered by pipeline ID +Retrieves the average build duration for all builds associated with the specified pipeline ID within the date range. + ##### With date range filtered by build status -GET `https://g.codefresh.io/api/analytics/reports/buildAvgDuration?dateRange=2024-09-01:2024-09-05&filters={"pipelineId":["648821e8bb1ff22b3e31f64c"]}` +Retrieves the average build duration for pipeline builds with a status of success within the specified date range. + +`GET https://g.codefresh.io/api/analytics/reports/buildAvgDuration?dateRange=2024-09-01:2024-09-05&&filters={"status":["success"]}` + + ##### With date range and all filters +Retrieves the daily average build duration for builds with: +* `status`=`success` +* Belonging to project with `projectId` ?? +* With pipeline ID pipeline-456 +* Tagged as favorites +The data is grouped by daily granularity. + +`GET https://g.codefresh.io/api/analytics/reports/buildAvgDuration?dateRange=2024-01-01&dateRange=2024-01-31&granularity=day&filters={"status":["success"],"projectId":["project-123"],"pipelineId":["pipeline-456"],"favorite":["true"]}` + ### Response @@ -283,12 +301,12 @@ This metric helps you assess the overall performance without being skewed by out ### Query parameters {: .table .table-bordered .table-hover} | Setting | Description | Data Type | Required/Optional| -|`dateRange` | The time frame for which to generate the report, from a minimum of one day to a maximum of six months. The start and end dates must be in `yyyy-mm-dd` (ISO 8601) formats. For example, `dateRange=2024-09-05dateRange=2024-09-01`. | string | Required | -|`granularity` | The level of detail or resolution at which to present the data in the report. The `granularity` levels depend on the `dateRange` defined. {::nomarkdown}
  • Up to 6 months: No granularity.
  • 1 to 4 days: hour.
  • 1 day to 3 months: day
  • Up to 6 months: week or month.
    When omitted, the default granularity of ???? is used.
{:/} | string | Optional | +|`dateRange` | The time frame for which to generate the report, from a minimum of one day to a maximum of six months. The start and end dates must be in `yyyy-mm-dd` (ISO 8601) formats. For example, `dateRange=2024-09-05&dateRange=2024-10-30`. | string | Required | +|`granularity` | The level of detail or resolution at which to present the data in the report. The `granularity` levels depend on the `dateRange` defined. {::nomarkdown}
  • Up to 6 months: No granularity. This means that data is aggregated for the entire time frame.
  • 1 to 4 days: hour.
  • 1 day to 3 months: day
  • Up to 6 months: week or month.
{:/} | string | Optional | | `filters` | The filters by which to narrow the scope of the build data. Can be any of the following: | | `projectId`: The ID/IDs of the project(s) with the pipeline builds for which to include data. To include data for specific pipelines, omit this filter and use `pipelineId` instead. | array | Optional | | | `pipelineId`: The ID/IDs of the pipeline(s) for which to include data. To include data for all pipeline builds in a project, omit this filter, and use `projectId` instead. | array | Optional | -| | `status`: The build statuses by which to filter pipelines.
Can be one of the following: {::nomarkdown}
  • error: Pipelines with builds that failed due to errors in the pipeline specifications or with failed steps.
  • succeeded: Pipelines with builds that completed successfully.
  • terminated: TPipelines with builds terminated by the system according to the policy defined in the pipeline's settings. See Build termination in pipeline policies.
{:/} | array | Optional | +| | `status`: The build statuses by which to filter pipelines.
Can be one of the following: {::nomarkdown}
  • error: Pipelines with builds that failed due to errors in the pipeline specifications or with failed steps.
  • success: Pipelines with builds that completed successfully.
  • terminated: Pipelines with builds terminated by the system according to the policy defined in the pipeline's settings. See Build termination in pipeline policies.
{:/} | array | Optional | | | `isFavorites`: Include only project or pipelines that have been starred as favorites. (NIMA: what is the default)| boolean | Optional | @@ -455,4 +473,14 @@ The P90 represents the time within which 90% of pipeline executions are complete This metric is useful for identifying and addressing performance issues that affect a small minority of pipeline executions. +## Error types + +The Analytics API can return the following error types. Each error includes an HTTP status code, error type, description, and examples of possible causes. + +| **HTTP Status Code** | **Error Type** | **Description** | **Examples** | +|-------------|---------------------------|---------------------|------------------------------------------------------------| +| `400` | **BadRequestError** | The request is invalid due to incorrect parameters or structure. | - Invalid report name.
- Invalid combination of request parameters: "Passed structure is invalid - Time dimensions are not supported for target report: `{reportName}`".
- Invalid filter request parameter: "Filter by account ID is not allowed by user params." | +| `403` | **AuthError** | The user is not authorized to perform the requested operation. | - Permission denied. | +| `432` | **ReportExecutionError** | The requested report is still being processed; the request must be resent with the same parameters. | - `Analytics report not finished yet - please try again.` | +| `500` | **InternalServerError** | An internal error occurred, preventing the report from being generated. | - `Could not get analytics report - the report doesn’t contain data.`` | From 30ed0c5e1a7d56b2edc7221a06b451ffa3379275 Mon Sep 17 00:00:00 2001 From: NimRegev Date: Tue, 19 Nov 2024 12:11:05 +0200 Subject: [PATCH 10/11] Add location of project id --- _docs/api-examples/analytics-api-examples.md | 17 +++++++++++++++++ images/analytics-api/pipeline-id.png | Bin 0 -> 26499 bytes images/analytics-api/project-id-in-url.png | Bin 0 -> 31534 bytes 3 files changed, 17 insertions(+) create mode 100644 images/analytics-api/pipeline-id.png create mode 100644 images/analytics-api/project-id-in-url.png diff --git a/_docs/api-examples/analytics-api-examples.md b/_docs/api-examples/analytics-api-examples.md index abf0de71e..c2736d47b 100644 --- a/_docs/api-examples/analytics-api-examples.md +++ b/_docs/api-examples/analytics-api-examples.md @@ -35,6 +35,23 @@ Currently, you do not need to select specific scopes for the API key. 1. Copy the API key to a handy location. +## Project and pipeline IDs +Endpoints require either the Project ID or the pipeline ID. + +##### Get the project ID +1. In the Codefresh UI, from the sidebar select **Projects**. +1. Click the project with the ID to retrieve. +1. From the URL, copy the value of the `projectId` query parameter. + + {% include + image.html + lightbox="true" + file="/images/analytics-api/project-id-in-url.png" + url="/images/analytics-api/project-id-in-url.png" + alt="Project ID in URL" + caption="Project ID in URL" + max-width="60%" +%} ## Get all pipelines/pipelines by name diff --git a/images/analytics-api/pipeline-id.png b/images/analytics-api/pipeline-id.png new file mode 100644 index 0000000000000000000000000000000000000000..a9e5b01ec55f6b3a1467b3a94a248992f9792dc6 GIT binary patch literal 26499 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 J?nRrB{{v$ Date: Tue, 19 Nov 2024 15:52:56 +0200 Subject: [PATCH 11/11] Update analytics-api-examples.md --- _docs/api-examples/analytics-api-examples.md | 104 ++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/_docs/api-examples/analytics-api-examples.md b/_docs/api-examples/analytics-api-examples.md index c2736d47b..dd6f9659e 100644 --- a/_docs/api-examples/analytics-api-examples.md +++ b/_docs/api-examples/analytics-api-examples.md @@ -56,7 +56,7 @@ Endpoints require either the Project ID or the pipeline ID. ## Get all pipelines/pipelines by name -Retrieves a list of all pipelines in your account, or filters pipelines based on a specific name or partial name. +Retrieves a list of all pipelines in your account, or the pipeline based on the specific name or partial name. Filtering by name returns pipelines whose names match or contain the specified text string. @@ -84,6 +84,8 @@ Filtering by name returns pipelines whose names match or contain the specified t `GET https://g.codefresh.io/api/analytics/reports/pipelinesDropdown` + + ##### For pipeline by name `GET https://g.codefresh.io/api/analytics/reports/pipelinesDropdown&filters={"name":[array]}` @@ -99,6 +101,106 @@ For each pipeline, the response includes the following data: * `isDeleted`: Indicates if the pipeline has been deleted from the account (`true`), or not (`false`). ```json +{ + "data": [ + { + "id": "58c80a0cdda94a01008a13c3", + "pipelineName": "codefresh-io/cf-configurator/cf-configurator", + "shortName": "cf-configurator", + "isDeleted": true + }, + { + "id": "590064e3e8fe09000168cf18", + "pipelineName": "codefresh-io/sandbox/gisql-sandbox", + "shortName": "gisql-sandbox", + "isDeleted": false + }, + { + "id": "5933a6925845b90001a1b7e1", + "pipelineName": "codefresh-io/node-docker-reference/node-docker-reference", + "shortName": "node-docker-reference", + "isDeleted": true + }, + { + "id": "5953a2e3fe091d0001e7afae", + "pipelineName": "codefresh-io/cf-kubernetes/onprem-installer", + "shortName": "onprem-installer", + "isDeleted": true + }, + { + "id": "597481218b4910000111027e", + "pipelineName": "codefresh-io/event-exporter/event-exporter", + "shortName": "event-exporter", + "isDeleted": true + }, + { + "id": "59942d56153cff0001c6b192", + "pipelineName": "codefresh-io/cf-kubernetes/build-k8-deployer", + "shortName": "build-k8-deployer", + "isDeleted": true + }, + { + "id": "59aa85cd45a7e50001ac73d6", + "pipelineName": "codefresh-io/docker-compose-environment/docker-compose-environment", + "shortName": "docker-compose-environment", + "isDeleted": false + }, + { + "id": "59c9f96f87fa780001d347ad", + "pipelineName": "codefresh-io/http-infra/http-infra", + "shortName": "http-infra", + "isDeleted": true + }, + { + "id": "5a1c04b376712100015f897c", + "pipelineName": "codefresh-io/slack-message-sender/slack-message-sender", + "shortName": "slack-message-sender", + "isDeleted": false + }, + { + "id": "5a82c2388c17c000010b9585", + "pipelineName": "codefresh-contrib/images/kube-helm", + "shortName": "kube-helm", + "isDeleted": true + }, + { + "id": "5a8599eed02e80000136dd16", + "pipelineName": "codefresh-io/monitoring/helm-package-gcs", + "shortName": "helm-package-gcs", + "isDeleted": true + }, + { + "id": "670771601a5fb84949f42760", + "pipelineName": "codefresh-io/planner/planner-publishing", + "shortName": "planner-publishing", + "isDeleted": true + }, + { + "id": "67220f08aa307a26796fed65", + "pipelineName": "oidc-e2e/production-oidc-test", + "shortName": "production-oidc-test", + "isDeleted": false + }, + { + "id": "6734d4dff91435f8ffb31e40", + "pipelineName": "UI E2E Latest/UI Performance", + "shortName": "ui performance", + "isDeleted": false + }, + { + "id": "6739c84dda82e44a15cd429c", + "pipelineName": "codefresh-io/venona/venona-tester-ci", + "shortName": "venona-tester-ci", + "isDeleted": false + } + ], + "timeDimensions": {} +} +``` + + + + { "data": [ {