How to use Catalog Ingestion API to push data into Harness IDP
Introduction
In this tutorial we will be creating Jira tickets using Workflows and add the information (i.e. ticket numbers) to the corresponding Software Component in the Catalog and display the same in the UI using Additional Info Card. The aim of this tutorial is to help you understand the usage of REST APIs to push information in the Catalog and then use them in different parts of IDP according to your use-cases.
Pre-Requisite
- We assume you have JIRA set-up as your ticket management system, and you have access to the same to create tickets in your corresponding project as well as administrator access to create projects.
Create the Workflow
- Create JIRA Ticket
- Create JIRA Project
Create Jira ticket
- Using RUN Step
- Using HTTP Step
Using RUN Step
- Go to Admin in your IDP
- Now select the project where you you want to create the pipeline for the Workflows.
- Begin by selecting the Create a Pipeline button followed by adding a name for the pipeline and set up your pipeline as inline.
- Now select the Developer Portal Stage and give it a name.
- Add a RUN step, name it as create jira ticket and select the Shell as
Bash
- Now add the following under the Command.
EMAIL_ID="<+pipeline.variables.email-id>"
JIRA_TOKEN="<+pipeline.variables.jiratoken>"
PROJECT_KEY="<+pipeline.variables.projectkey>"
COMPONENT_NAME="<+pipeline.variables.componentname>"
ISSUE_TYPE="<+pipeline.variables.issuetype>"
ISSUE_SUMMARY="<+pipeline.variables.issuesummary>"
ISSUE_CONTENT="<+pipeline.variables.issuecontent>"
LABELS="<+pipeline.variables.labels>"
# Perform the POST request with curl and capture the response
response=$(curl --silent --request POST \
--url 'https://harness.atlassian.net/rest/api/3/issue' \
--user "$EMAIL_ID:$JIRA_TOKEN" \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"fields": {
"project": {
"key": "$PROJECT_KEY"
},
"components": {
"name": "$COMPONENT_NAME"
},
"issuetype": {
"name": "$ISSUE_TYPE"
},
"summary": "$ISSUE_SUMMARY",
"description": {
"version": 1,
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": "$ISSUE_CONTENT"
}
]
}
]
},
"labels": [
"$LABELS"
]
}
}')
# Extract the key from the JSON response using jq
issue_key=$(echo "$response" | jq -r '.key')
# Export the issue key as an environment variable
export ISSUE_KEY="$issue_key"
# Print the issue key (optional)
echo "The created issue key is: $ISSUE_KEY"
The above given request body can create a Jira ticket based on project and component and add a label to the same.
We have used few pipeline variables in the body, which will be used to take input from the IDP Workflows and for the users to choose project, add the summary, description for the tickets.
-
Now under Optional Configuration add the Output Variables as
ISSUE_KEY
. -
Apply the Changes.
-
Go to Variables on the right side of the page and add the following variables and have the input type as Runtime Input.
- emailid
- jiratoken
- projectkey
- componentname
- issuetype
- issuesummary
- issuecontent
- labels
- usergroup
-
Apply the changes.
Use Catalog Metadata Ingestion API
- Start by adding another
RUN
step. - Name it as Ingestion API and select the Shell as
Bash
- Now add the following under the Command.
curl --location 'https://app.harness.io/gateway/v1/catalog/custom-properties' \
--header 'Harness-Account: <+account.identifier>' \
--header 'Content-Type: application/json' \
--header 'x-api-key: <+secrets.getValue('account.TOKEN_ID')>' \
--data '{
"properties": [
{
"field": "metadata.openTicket",
"filter": {
"kind": "Component",
"type": "service",
"owners": [
"<+pipeline.variables.usergroup>"
]
},
"value_overrides": [
{
"entity_ref": "YOUR_COMPONENT_LINK",
"override_value": "<+stage.spec.execution.steps.create_jira_ticket.output.outputVariables.ISSUE_KEY>"
}
],
"value": "0"
}
]
}'
- Under
header
x-api-key:<+secrets.getValue('account.TOKEN_ID')>
, add the token ID for your API key. Get your token ID from your Profile
In the above body the openTicket which got created in JIRA will be added, to kind component and type service owned by the usergroup
selected in the Workflows. Under entity_ref
add the component link to which you want to add the ticket ID, the unique entity reference could be found using inspect entity for the component in Catalog.
- Now Apply the changes.
Using HTTP Step
HTTP Step is available under custom stage and it's part of CD License
- Go to Admin in your IDP
- Now select the project where you you want to create the pipeline for the Workflows.
- Begin by selecting the Create a Pipeline button followed by adding a name for the pipeline and set up your pipeline as inline.
- Now select the Custom Stage and give it a name.
- Add a HTTP step and name it as create jira ticket
- Under the URL add this endpoint
https://YOUR_COMPANY.atlassian.net/rest/api/3/issue
and replace theYOUR_COMPANY
with your domain name. - Select the Method as
POST
. - Under the body add the following:
{
"fields": {
"project": {
"key": "<+pipeline.variables.projectkey>"
},
"components": [
{
"name": "<+pipeline.variables.componentname>"
}
],
"issuetype": {
"name": "<+pipeline.variables.issuetype>"
},
"summary": "<+pipeline.variables.issuesummary>",
"description": {
"version": 1,
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": "<+pipeline.variables.issuecontent>"
}
]
}
]
},
"labels": [
"<+pipeline.variables.labels>"
]
}
}
The above given request body can create a Jira ticket based on project and component and add a label to the same.
We have used few pipeline variables in the body, which will be used to take input from the IDP Workflows and for the users to choose project, add the summary, description for the tickets.
- Under Optional Configuration add the Assertion as
<+httpResponseCode>==201
. - Under Headers add the following key value pairs:
- Accept:
application/json
- Authorization:
Basic <Base64 encoded username and password>
, the username is the email-id and the password would be the JIRA API key - Accept-Encoding:
gzip, deflate, br
- Accept:
- Under output add a variable
issue_key
and assign a value as expression<+json.object(httpResponseBody).key>
- Now Apply Changes.
- Go to Variables on the right side of the page and add the following variables and have the input type as Runtime Input.
- projectkey
- componentname
- issuetype
- issuesummary
- issuecontent
- labels
- usergroup
- Apply the changes.
Use Catalog Metadata Ingestion API
- Start by adding another
HTTP
step. - Add the Timeout as
30s
. - Add this endpoint as as URL
https://app.harness.io/gateway/v1/catalog/custom-properties
, read more about Catalog Metadata Ingestion API - Select the Method as
POST
. - And add the following json as Request Body
{
"properties": [
{
"field": "metadata.openTicket",
"filter": {
"kind": "Component",
"type": "service",
"owners": [
"<+pipeline.variables.usergroup>"
]
},
"value_overrides": [
{
"entity_ref": "YOUR_COMPONENT_LINK",
"override_value": "<+stage.spec.execution.steps.create_jira_ticket.output.outputVariables.issue_key>"
}
],
"value": "0"
}
]
}
In the above body the openTicket which got created in JIRA will be added, to kind component and type service owned by the usergroup
selected in the Workflows. Under entity_ref
add the component link to which you want to add the ticket ID, the component link could be found using inspect entity for the component in catalog.
-
Under Optional Configuration add the Assertion as
<+httpResponseCode>==200
. -
Under Headers add the following key value pairs:
- Harness-Account:
<+account.identifier>
- Content-Type:
application/json
- Accept:
*/*
- x-api-key:
<+secrets.getValue('account.TOKEN_ID')>
, add the token ID for your API key. Get your token ID from your Profile
- Harness-Account:
-
Now Apply Changes and SAVE the pipeline.
Create Workflow
Now we have to create a workflow, which takes the input from the user and triggers the pipeline. Here's the workflow YAML
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: jira-ticket
title: Create a JIRA Ticket
description: A template to create a Jira Ticket
tags:
- jira
- management
spec:
owner: owner@company.com
type: service
parameters:
- title: Service Details
required:
- projectkey
- issuetype
- jiracomponentname
- issuesummary
- issuecontent
- labels
- usergroup
properties:
emailid:
title: Email ID used for Atlassain account
type: string
description: Use the email ID associated with JIRA
jiratoken:
title: Jira Access Tokens
type: string
ui:widget: password
description: Add the API access tokens created under the above mentioned email id
projectkey:
title: Jira Project Key
type: string
default: IDP
description: Your ticket will be created under this project
issuetype:
type: string
title: Add your Jira component type
default: Story
jiracomponentname:
type: string
title: Add the component for this issue
desciption: Component for ticket tracing eg., Misc, Backstage Core, Platform etc.
issuesummary:
title: Give a title for your ticket
type: string
issuecontent:
title: Describe the details needed in the ticket
type: string
labels:
type: string
title: Select a label for the issue
default: roadmap
usergroup:
title: Choose an Owner for the Service
type: string
ui:field: OwnerPicker
ui:options:
allowedKinds:
- Group
# This field is hidden but needed to authenticate the request to trigger the pipeline
token:
title: Harness Token
type: string
ui:widget: password
ui:field: HarnessAuthToken
steps:
- id: trigger
name: Bootstrapping your new service
action: trigger:harness-custom-pipeline
input:
url: "PIPELINE URL"
inputset:
emailid: ${{ parameters.emailid }}
jiratoken: ${{ parameters.jiratoken }}
projectkey: ${{ parameters.projectkey }}
issuetype: ${{ parameters.issuetype }}
componentname: ${{ parameters.jiracomponentname }}
issuesummary: ${{ parameters.issuesummary }}
issuecontent: ${{ parameters.issuecontent }}
labels: ${{ parameters.labels }}
usergroup: ${{ parameters.usergroup }}
apikey: ${{ parameters.token }}
output:
links:
- title: Pipeline Details
url: ${{ steps.trigger.output.PipelineUrl }}
In the above YAML just replace the url
with the pipeline URL we created above, also make sure the key values under inputset
exactly matches with the pipeline variable names.
Also for Jira token input the input should be the personal access token from JIRA.
-
Now go to your git provider and add this workflow yaml and save it, make sure it's public incase it's in private repo make sure you have the git integration setup.
-
Once the file is created in your git repo, copy the full URL to the file. For example,
https://github.com/harness-community/idp-samples/blob/main/tutorial-jira-ticket-catalog-ingestion.yaml
.
- In the left navigation, select Create, and then select Register Software Component.
- Enter the URL to your new
workflow.yaml
.
- Click Import.
- Now go to the workflow and select the workflow you just added.
- Add the input values in the field that would be used by the workflow
Create Additional Info Card
In case you want to display the same information you have ingested on your Overview page as an additional card, follow the steps below.
- Go to the Layout Page and under Admin and add the following for Services and Save it.
- component: EntityAdditionalInfoCard
specs:
props:
title: Open JIRA Tickets
items:
- label: JIRA TICKET KEY
value: <+metadata.openTicket>
type: string
style:
bold: true
gridProps:
md: 6
- Now go to the Software Component in the Catalog and you'll find an additional info card populated with information we ingested using the API above. You can read more about additional info card
Create Jira Project
- Using RUN Step
- Using HTTP Step
Using RUN Step
- Go to Admin in your IDP
- Now select the project where you you want to create the pipeline for the Workflows.
- Begin by selecting the Create a Pipeline button followed by adding a name for the pipeline and set up your pipeline as inline.
- Now select the Developer Portal Stage and give it a name.
- Add a RUN step, name it as create jira project and select the Shell as
Bash
- Now add the following under the Command.
EMAIL_ID="<+pipeline.variables.emailid>"
JIRA_TOKEN="<+pipeline.variables.jiratoken>"
NEW_PROJECT_NAME="<+pipeline.variables.newprojectname>"
DESCRIPTION="<+pipeline.variables.description>"
NEW_PROJECT_KEY="<+pipeline.variables.newprojectkey>"
PROJECT_LEAD_ACCOUNT_ID="<+pipeline.variables.projectleadaccountid>"
PROJECT_TEMPLATE_KEY="<+pipeline.variables.projecttemplatekey>"
# Perform the POST request with curl and capture the response
response=$(curl --silent --request POST \
--url 'https://YOUR_COMPANY.atlassian.net/rest/simplified/latest/project' \
--user "$EMAIL_ID:$JIRA_TOKEN" \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"assigneeType": "PROJECT_LEAD",
"description": "$DESCRIPTION",
"key": "$NEW_PROJECT_KEY",
"leadAccountId": "$PROJECT_LEAD_ACCOUNT_ID",
"name": "$NEW_PROJECT_NAME",
"projectTemplateKey": "$PROJECT_TEMPLATE_KEY",
}')
# Extract the key from the JSON response using jq
project_key=$(echo "$response" | jq -r '.key')
# Export the issue key as an environment variable
export PROJECT_KEY="$project_key"
# Print the issue key (optional)
echo "The created issue key is: $PROJECT_KEY"
The above given request body can create a Jira project
We have used few pipeline variables in the body, which will be used to take input from the IDP Workflows and for the users to choose project, add the summary, description for the tickets.
-
Now under Optional Configuration add the Output Variables as
PROJECT_KEY
. -
Apply the Changes.
-
Go to Variables on the right side of the page and add the following variables and have the input type as Runtime Input.
- emailid
- jiratoken
- newprojectname
- newprojectkey
- projectleadaccountid
- projecttemplatekey
- usergroup
-
Apply the changes.
Use Catalog Metadata Ingestion API
- Start by adding another
RUN
step. - Name it as Ingestion API and select the Shell as
Bash
- Now add the following under the Command.
curl --location 'https://app.harness.io/gateway/v1/catalog/custom-properties' \
--header 'Harness-Account: <+account.identifier>' \
--header 'Content-Type: application/json' \
--header 'x-api-key: <+secrets.getValue('account.TOKEN_ID')>' \
--data '{
"properties": [
{
"field": "metadata.openTicket",
"filter": {
"kind": "Component",
"type": "service",
"owners": [
"<+pipeline.variables.usergroup>"
]
},
"value_overrides": [
{
"entity_ref": "YOUR_COMPONENT_LINK",
"override_value": "<+stage.spec.execution.steps.create_jira_project.output.outputVariables.PROJECT_KEY>"
}
],
"value": "0"
}
]
}'
- Under
header
x-api-key:<+secrets.getValue('account.TOKEN_ID')>
, add the token ID for your API key. Get your token ID from your Profile
In the above body the openTicket which got created in JIRA will be added, to kind component and type service owned by the usergroup
selected in the Workflows. Under entity_ref
add the component link to which you want to add the ticket ID, the unique entity reference could be found using inspect entity for the component in Catalog.
- Now Apply the changes.
- Go to Admin in your IDP
- Now select the project where you you want to create the pipeline for the Workflows.
- Begin by selecting the Create a Pipeline button followed by adding a name for the pipeline and set up your pipeline as inline.
- Now select the Custom Stage and give it a name.
- Add a HTTP step and name it as create jira project
- Under the URL add this endpoint
https://YOUR_COMPANY.atlassian.net/rest/simplified/latest/project
and replace theYOUR_COMPANY
with your domain name. - Select the Method as
POST
. - Under the body add the following:
{
"key": "<+pipeline.variables.newprojectkey>",
"leadAccountId": "<+pipeline.variables.projectleadaccountid>",
"templateKey": "<+pipeline.variables.projecttemplatekey>",
"name": "<+pipeline.variables.newprojectname>"
}
The above given request body can create a Jira Project based on templatekey
We have used few pipeline variables in the body, which will be used to take input from the IDP Workflows and for the users to provide the name, key and template.
-
Under Optional Configuration add the Assertion as
<+httpResponseCode>==200
. -
Under Headers add the following key value pairs:
- Accept:
application/json
- Authorization:
Basic <Base64 encoded username and password>
, the username is the email-id and the password would be the JIRA API key - Accept-Encoding:
gzip, deflate, br
- Accept:
-
Under output add few variable like
project_key
, assign a value as expression<+json.object(httpResponseBody).projectKey>
andproject_name
, assign the values as expression<+json.object(httpResponseBody).projectName>
-
Now Apply Changes.
-
Go to Variables on the right side of the page and add the following variables and have the input type as Runtime Input.
- projectkey
- templatekey
- projectname
- usergroup
-
Apply the changes.
Use Catalog Metadata Ingestion API
- Start by adding another
HTTP
step. - Add the Timeout as
30s
. - Add this endpoint as as URL
https://app.harness.io/gateway/v1/catalog/custom-properties
, read more about Catalog Metadata Ingestion API - Select the Method as
POST
. - And add the following json as Request Body
{
"properties": [
{
"field": "metadata.projectKey",
"filter": {
"kind": "Component",
"type": "service",
"owners": [
"<+pipeline.variables.usergroup>"
]
},
"value_overrides": [
{
"entity_ref": "YOUR_COMPONENT_LINK",
"override_value": "<+stage.spec.execution.steps.create_jira_project.output.outputVariables.project_key>"
}
],
"value": "0"
}
]
}
In the above body the openTicket which got created in JIRA will be added, to kind component and type service owned by the usergroup
selected in the Workflows. Under entity_ref
add the component link to which you want to add the ticket ID, the component link could be found using inspect entity for the component in Catalog.
-
Under Optional Configuration add the Assertion as
<+httpResponseCode>==200
. -
Under Headers add the following key value pairs:
- Harness-Account:
<+account.identifier>
- Content-Type:
application/json
- Accept:
*/*
- x-api-key:
<+secrets.getValue('account.TOKEN_ID')>
, add the token ID for your API key. Get your token ID from your Profile
- Harness-Account:
-
Now Apply Changes and SAVE the pipeline.
Create Workflow
Now we have to create a workflow, which takes the input from the user and triggers the pipeline. Here's the workflow YAML
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: jira-project
title: Create a JIRA Project
description: A template to create a Jira Project
tags:
- jira
- management
spec:
owner: owner@company.com
type: service
parameters:
- title: Service Details
required:
- emailid
- jiratoken
- newprojectname
- newprojectkey
- projectleadaccountid
- projecttemplatekey
- usergroup
properties:
newprojectkey:
title: Jira Project Key
type: string
default: DEMO
description: Your Project will have this key which will appear in the url
newprojectname:
type: string
title: Add a project name
default: demo
projecttemplatekey:
type: string
title: Add the template type
description: Select and add a template
jiratoken:
type: string
title: Add the Jira Token
ui:widget: password
projectleadaccountid:
type: string
title: Add the account id for your project lead
description: Atlassian Account ID for the project lead
emailid:
type: string
tile: Add the Atlassian emailid
description: emailid to be used for atlassian login
usergroup:
title: Choose an Owner for the Service
type: string
ui:field: OwnerPicker
ui:options:
allowedKinds:
- Group
# This field is hidden but needed to authenticate the request to trigger the pipeline
token:
title: Harness Token
type: string
ui:widget: password
ui:field: HarnessAuthToken
steps:
- id: trigger
name: Bootstrapping your new service
action: trigger:harness-custom-pipeline
input:
url: "PIPELINE URL"
inputset:
newprojectkey: ${{ parameters.newprojectkey }}
newprojectname: ${{ parameters.newprojectname }}
projecttemplatekey: ${{ parameters.projecttemplatekey }}
jiratoken: ${{ parameters.jiratoken }}
usergroup: ${{ parameters.usergroup }}
projectleadaccountid: ${{ parameters.projectleadaccountid }}
emailid: ${{ parameters.emailid }}
apikey: ${{ parameters.token }}
output:
links:
- title: Pipeline Details
url: ${{ steps.trigger.output.PipelineUrl }}
In the above YAML just replace the url
with the pipeline URL we created above, also make sure the key values under inputset
exactly matches with the pipeline variable names.
-
Now go to your git provider and add this workflow yaml and save it, make sure it's public incase it's in private repo make sure you have the git integration setup.
-
Once the file is created in your git repo, copy the full URL to the file. For example,
https://github.com/harness-community/idp-samples/blob/main/tutorial-jira-ticket-catalog-ingestion.yaml
.
- In the left navigation, select Create, and then select Register Software Component.
- Enter the URL to your new
workflow.yaml
.
- Click Import.
-
Now go to the workflow and select the workflow you just added.
-
Add the values, under
template key
, make sure you add one of the mentioned template key, for eg., here we usedcom.pyxis.greenhopper.jira:gh-simplified-agility-kanban
.
- Create Additional Info Card
- Add UI Picker to dynamically fetch data in workflows
Create Additional Info Card
In case you want to display the same information you have ingested on your Overview page as an additional card, follow the steps below.
- Go to the Layout Page and under Admin and add the following for Services and Save it.
- component: EntityAdditionalInfoCard
specs:
props:
title: JIRA PROJECT
items:
- label: JIRA PROJECT KEY
value: <+metadata.projectKey>
type: string
style:
bold: true
gridProps:
md: 6
- Now go to the Software Component in the Catalog and you'll find an additional info card populated with information we ingested using the API above. You can read more about additional info card
Create UI Picker to dynamically values in Workflows
In case you need to use the data present in your Catalog as an input for the Workflows, you can do so by using the EntityFieldPicker.
Here's an example workflow template that uses the jira projectName
for the corresponding new service being created.
## Example template.yaml
...
projectName:
title: Project-Name
type: string
description: Name of the project in JIRA
ui:field: EntityFieldPicker
ui:displayField: metadata.projectName
ui:options:
catalogFilter:
kind:
- Component
- Service
...
The ui:displayField
fetches all the projectName
names from the Catalog.
### Complete Example of a service onboarding template.yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
# some metadata about the template itself
metadata:
name: react-app
title: Create a new service
description: A template to create a new service
tags:
- nextjs
- react
- javascript
# these are the steps which are rendered in the frontend with the form input
spec:
owner: debabrata.panigrahi@harness.io
type: service
parameters:
- title: Service Details
required:
- template_type
- public_template_url
- owner
properties:
template_type:
title: Type of the Template
type: string
description: Type of the Template
public_template_url:
title: Give a Public template URL
type: string
description: Give a Public Cookiecutter Template
projectName:
title: Project-Name
type: string
description: Name of the project in JIRA
ui:field: EntityFieldPicker
ui:displayField: metadata.projectName
ui:options:
catalogFilter:
kind:
- Component
- Service
# This field is hidden but needed to authenticate the request to trigger the pipeline
token:
title: Harness Token
type: string
ui:widget: password
ui:field: HarnessAuthToken
# here's the steps that are executed in series in the scaffolder backend
steps:
- id: trigger
name: Creating your react app
action: trigger:harness-custom-pipeline
input:
url: "Your PIPELINE URL"
inputset:
project_name: ${{ parameters.projectName }}
template_type: ${{ parameters.template_type }}
public_template_url: ${{ parameters.public_template_url }}
apikey: ${{ parameters.token }}
# some outputs which are saved along with the job for use in the frontend
output:
links:
- title: Pipeline Details
url: ${{ steps.trigger.output.PipelineUrl }}