How to use Azure DevOps REST API to Update File? - azure-devops

I'm trying to Update a test.json file hosted on a Azure DevOps Repo. I'm using a Logic App. Having trouble identifying the order of operations from the documentation.
I think I need to...
Issue a GET HTTP request to the Items endpoint:
https://dev.azure.com/myOrg/myProject/_apis/git/repositories/myRepoID/items?scopePath=/data/test.json&$format=json&api-version=6.0
Response:
{
"count": 1,
"value": [
{
"objectId": "<longGUID>",
"gitObjectType": "blob",
"commitId": "<longGUID>",
"path": "/data/test.json",
"url": "https://dev.azure.com/myOrg/longGUID/_apis/git/repositories/myRepoID/items?path=%2Fdata%2Ftest.json&versionType=Branch&versionOptions=None"
}
]
}
Use the objectId in the response to issue a POST HTTP request to the Pushes endpoint
Body:
{
"refUpdates": [
{
"name": "refs/heads/main",
"oldObjectId": "<longGuid from previous response>"
}
],
"commits": [
{
"changes": [
{
"changeType": "edit",
"item": {
"path": "/data/test.json"
},
"newContent": {
"content": "CHECK CHECK!",
"contentType": "rawtext"
}
}
],
"comment": "My commit message"
}
]
}
Error:
Status 409 Conflict
{
"$id": "1",
"innerException": null,
"message": "TF401028: The reference 'refs/heads/main' has already been updated by another client, so you cannot update it. Please try again.",
"typeName": "Microsoft.TeamFoundation.Git.Server.GitReferenceStaleException, Microsoft.TeamFoundation.Git.Server",
"typeKey": "GitReferenceStaleException",
"errorCode": 0,
"eventId": 3000
}
Questions:
Am I correct on the order of operations?
How do I overcome this issue?
FIX: (Thank you #Leo_Liu-MSFT)
GET request to https://dev.azure.com/myOrg/myProject/_apis/git/repositories/repoID/commits?searchCriteria.$top=1&searchCriteria.itemVersion.version=main&api-version=6.0
POST request to https://dev.azure.com/myOrg/myProject/_apis/git/repositories/repoID/pushes
Body:
{
"commits": [
{
"changes": [
{
"changeType": "edit",
"item": {
"path": "<Your File To Update>"
},
"newContent": {
"content": "CHECK CHECK!",
"contentType": "rawtext"
}
}
],
"comment": "<YOUR COMMIT MSG>"
}
],
"refUpdates": [
{
"name": "refs/heads/main",
"oldObjectId": "<commitId from previous response>"
}
]
}

How to use Azure DevOps REST API to Update File?
The oldObjectId in the request body is not the value of the objectId.
It should be the the latest commit SHA for the branch main.
Go to the code page > Files
Choose a repository and branch
Select the root level (repository name) > History
Click … of the first commit > Copy full SHA
And the value should be create a new branch 0000000000000000000000000000000000000000 when used to create a new branch.

Related

How to check if a changeType is "merge" or "branch" when retrieving git changes through Azure DevOps REST Api

I am fetching Git changes from Azure DevOps REST Api and want to distinguish if a specific commit was a merge/branch operation. The default changeTypes are: add, edit, delete and I couldn't find any reference for "merge" or "branch".
Is there a built in way to achieve this?
My query uses the following syntax from the official doc:
GET https://{instance}/{collection}/_apis/git/repositories/{repositoryId}/commits/{commitId}?api-version=4.1
And the response is like:
{
"parents": [],
"treeId": "7fa1a3523ffef51c525ea476bffff7d648b8cb3d",
"push": {
"pushedBy": {
"id": "8c8c7d32-6b1b-47f4-b2e9-30b477b5ab3d",
"displayName": "Chuck Reinhart",
"uniqueName": "fabrikamfiber3#hotmail.com",
"url": "https://fabrikam:8080/tfs/_apis/Identities/8c8c7d32-6b1b-47f4-b2e9-30b477b5ab3d",
"imageUrl": "https://fabrikam:8080/tfs/_api/_common/identityImage?id=8c8c7d32-6b1b-47f4-b2e9-30b477b5ab3d"
},
"pushId": 1,
"date": "2014-01-29T23:33:15.2434002Z"
},
"commitId": "be67f8871a4d2c75f13a51c1d3c30ac0d74d4ef4",
"author": {
"name": "Chuck Reinhart",
"email": "fabrikamfiber3#hotmail.com",
"date": "2014-01-29T23:32:09Z"
},
"committer": {
"name": "Chuck Reinhart",
"email": "fabrikamfiber3#hotmail.com",
"date": "2014-01-29T23:32:09Z"
},
"comment": "First cut\n",
"changeCounts": {
"Add": 2
},
"changes": [
{
"item": {
"gitObjectType": "blob",
"path": "/.gitattributes",
"url": "https://fabrikam:8080/tfs/_apis/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249/items/.gitattributes?versionType=Commit"
},
"changeType": "add"
},
{
"item": {
"gitObjectType": "blob",
"path": "/.gitignore",
"url": "https://fabrikam:8080/tfs/_apis/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249/items/.gitignore?versionType=Commit"
},
"changeType": "add"
}
],
"url": "https://fabrikam:8080/tfs/_apis/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249/commits/be67f8871a4d2c75f13a51c1d3c30ac0d74d4ef4",
"remoteUrl": "https://fabrikam:8080/tfs/_git/Fabrikam-Fiber-Git/commit/be67f8871a4d2c75f13a51c1d3c30ac0d74d4ef4",
"_links": {
"self": {
"href": "https://fabrikam:8080/tfs/_apis/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249/commits/be67f8871a4d2c75f13a51c1d3c30ac0d74d4ef4"
},
"repository": {
"href": "https://fabrikam:8080/tfs/_apis/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249"
},
"changes": {
"href": "https://fabrikam:8080/tfs/_apis/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249/commits/be67f8871a4d2c75f13a51c1d3c30ac0d74d4ef4/changes"
},
"web": {
"href": "https://fabrikam:8080/tfs/_git/Fabrikam-Fiber-Git/commit/be67f8871a4d2c75f13a51c1d3c30ac0d74d4ef4"
},
"tree": {
"href": "https://fabrikam:8080/tfs/_apis/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249/trees/7fa1a3523ffef51c525ea476bffff7d648b8cb3d"
}
}
}
If there is no built in way to achieve this, should the parent be used as a guidance? Like if it is empty it is a 'branch' operation and if there is two entries in it it is a 'merge'?
Update 1
I can see in the documentation referenced above that there are merge and branch changeTypes, but when I query a change that was merged the result only contains edit or add.
You will have to use the parents collection to determine whether it was a merge. Since normal commits just have 1 parent, more than 1 indicates a merge.
From the git documentation here
A commit object may have any number of parents. With exactly one parent, it is an ordinary commit. Having more than one parent makes the commit a merge between several lines of history. Initial (root) commits have no parents.

Unable to retrieve the changeCounts properties for a git Pull Request in AzureDevOps using the REST api

I am trying to find (roughly) the number of lines of code that has been changed in a Pull Request using the Azure DevOps REST Api. The documentation suggests that it is possible but I have been unable to get it to work.
The api's return a GitCommitRef[] as a response and inside the GitCommitRef there is a changeCounts property, but this mostly appears to be missing from most responses.
Things I have tried\observed:
1. List of commits for a pull request
I can get a list of the commits for a pull request, but this does not include the changeCounts
Request
https://{{coreServer}}/{{organization}}/{{project}}/_apis/git/repositories/{{repositoryId}}/pullRequests/{{pullRequestId}}/commits?api-version=6.0
Response
{
"count": 3,
"value": [
{
"commitId": "0b415...669fda",
"author": {
"name": "name",
"email": "name#email.com",
"date": "2021-11-02T03:34:23Z"
},
"committer": {
"name": "name",
"email": "name#email.com",
"date": "2021-11-02T03:34:23Z"
},
"comment": "checkin commit",
"url": "https://dev.azure.com/{{organization}}/{{project}}/_apis/git/repositories/5f32ff...2a97ac1/commits/0b415...669fda"
},
2. Getting a list of commits for a repository does return the changeCounts
So I thought, okay I will just retrieve each commit and get the counts that way, but I cannot get it to honour the searchCriteria, so if I ask for a specific commit I still get all the commits on the repo
https://{{coreServer}}/{{organization}}/{{project}}/_apis/git/repositories/{{repositoryId}}/commits?searchCriteria.compareVersion.version=67...4b4&searchCriteria.compareVersion.versionType=commit&api-version=6.0
Response
{
"count": 100,
"value": [
{
"commitId": "71...a93a",
"author": {
"name": "name",
"email": "name#email.com",
"date": "2021-11-07T23:59:52Z"
},
"committer": {
"name": "name",
"email": "name#email.com",
"date": "2021-11-07T23:59:52Z"
},
"comment": "Merged PR 11087: did some work",
"commentTruncated": true,
"changeCounts": {
"Add": 0,
"Edit": 1,
"Delete": 0
},
3. Specifying the commit id does not return the changeCounts either
If I specify the commit id when retrieving a commit that, only returns the commit but not the changeCounts
https://{{coreServer}}/{{organization}}/{{project}}/_apis/git/repositories/{{repositoryId}}/commits?searchCriteria.ids=0b...fda&api-version=6.0
Response
{
"count": 1,
"value": [
{
"commitId": "0b...da",
"author": {
"name": "name",
"email": "name#email.com",
"date": "2021-11-02T03:34:23Z"
},
"committer": {
"name": "name",
"email": "name#email.com",
"date": "2021-11-02T03:34:23Z"
},
"comment": "did some work",
"url": "https://dev.azure.com/{{organization}}/{{project}}/_apis/git/repositories/5f...ac1/commits/0b...da"
}
]
}
Anyone have an idea why the api's do not seem to be working for me?

No token in request - Account Linking with new Actions SDK

I am building an action with the new Actions Builder and everything is going pretty smoothly. I just setup account linking and can successfully link my account, however, once I do link my account there is no token included in the subsequent requests for me to use, even though the account linking status is in the request as "LINKED". Can anyone shed any light on why I am not seeing a token?
For reference, here is a version of one of my requests.
{
"requestJson": {
"handler": {
"name": "main"
},
"intent": {
"name": "actions.intent.MAIN",
"params": {},
"query": "Talk to my new app"
},
"scene": {
"name": "actions.scene.START_CONVERSATION",
"slotFillingStatus": "UNSPECIFIED",
"slots": {},
"next": {
"name": "ListPrompt"
}
},
"session": {
"id": "ABwppHE7M6NS8KdyjljEptrtZZ5GkE3qDdaiwjYbL9ehrA-t_c-ZsCrZ_WhN0ZTG5lXXXXXXhU6Im5vgeSwow",
"params": {},
"typeOverrides": [],
"languageCode": ""
},
"user": {
"locale": "en-US",
"params": {},
"accountLinkingStatus": "LINKED",
"verificationStatus": "VERIFIED",
"packageEntitlements": [],
"lastSeenTime": "2020-07-13T12:02:42Z"
},
"home": {
"params": {}
},
"device": {
"capabilities": [
"SPEECH",
"RICH_RESPONSE",
"LONG_FORM_AUDIO"
]
}
}
}
The Google docs for the Account Linking with the new Actions Builder have now been updated with additional information. The token is now provided within the headers of the incoming request. Details of how to find and decode this can be found at https://developers.google.com/assistant/identity/google-sign-in#handle_data_access_requests

How can I trigger a `action.intent.INTENT_NAME` intent from my webhook?

I want to create a chatbot with Dialogflow and Google Assistant along with Google Transactions API for enabling a user to order a chocolate box. For now my agent contains the following four intents:
Default Welcome Intent (text response: Hello, do you want to buy a chocolate box?)
Default Fallback Intent
Int1 (training phrase: Yes, I want, fulfilment: enabled webhook call)
Int2 (event: actions_intent_TRANSACTION_REQUIREMENTS_CHECK )
I am using Dialogflow Json instead of Node.js to connect my agent with Transactions API. I want to test that the user meets the transaction requirements (when ordering the chocolate box) by using the actions.intent.TRANSACTION_REQUIREMENTS_CHECK action of Google actions. For this reason, following Google docs, when Int1 is triggered I am using a webhook which connect Google Assistant to the following python script (back-end):
from flask import Flask, render_template, request, jsonify
from flask_cors import CORS
import requests
app = Flask(__name__)
CORS(app)
#app.route("/", methods=['POST'])
def index():
data = request.get_json()
intent = data["queryResult"]["intent"]["displayName"]
if (intent == 'Int1'):
return jsonify({ "data": {
"google": {
"expectUserResponse": True,
"isSsml": False,
"noInputPrompts": [],
"systemIntent": {
"data": {
"#type": "type.googleapis.com/google.actions.v2.TransactionRequirementsCheckSpec",
"paymentOptions": {
"actionProvidedOptions": {
"displayName": "VISA-1234",
"paymentType": "PAYMENT_CARD"
}
}
},
"intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK"
}
}
}
})
else:
return jsonify({'message': 'HERE'})
if __name__== "__main__":
app.run(debug=True)
The json which I return above when intent = 'Int1' is the one specified at Google docs for "Checking requirements with your own payment method".
According to Google docs, this must be done next:
Receiving the result of a requirements check
After the Assistant fulfills the intent, it sends your fulfillment a
request with the actions.intent.TRANSACTION_REQUIREMENTS_CHECK intent
with the result of the check.
To properly handle this request, declare a Dialogflow intent that's
triggered by the actions_intent_TRANSACTION_REQUIREMENTS_CHECK event.
For this reason, I defined Int2 and as its event the actions_intent_TRANSACTION_REQUIREMENTS_CHECK.
However, I do not receive anything at my back-end like a result of the check and therefore I do not know if the action actions.intent.TRANSACTION_REQUIREMENTS_CHECK is really triggered. Why is this happening?
In general, how can I trigger one actions.intent.INTENT_NAME intent from my webhook/back-end?
When I am using the v2 version of Dialogflow, I am getting the following info/message about the webhook on Dialogflow when Int1 is triggered:
"webhookStatus": {
"code": 3,
"message": "Webhook call failed. Error: Failed to parse webhook JSON response: Cannot find field: data in message google.cloud.dialogflow.v2.WebhookResponse."
}
In the same case, I am getting the following info/message about the webhook on Google Assistant simulator when Int1 is triggered:
"responseMetadata": {
"status": {
"code": 14,
"message": "Webhook error (206)"
}
Finally, let me mention that I am testing all this with Python and ngrok at my local computer so perhaps this poses a problem because at the beginning of Google docs the following is mentioned:
Warning: The Actions Web Simulator should not be used to test an app
with transactions. Please use an Assistant-enabled Android or iOS
device to accurately test your app during development.
I finally solved this problem.
I had to replace the key "data" in the json which I was sending back when Int1 was triggered with the key "payload". In other words, I had to adjust my fulfilment response to the v2 version of Dialogflow.
Therefore, now I do get a second post request at my back-end which is sent because of the trigger of actions.intent.TRANSACTION_REQUIREMENTS_CHECK and of Int2.
Specifically, I get the following:
{
"responseId": "*****************************",
"queryResult": {
"queryText": "actions_intent_TRANSACTION_REQUIREMENTS_CHECK",
"parameters": {},
"allRequiredParamsPresent": true,
"fulfillmentText": "HERE",
"fulfillmentMessages": [
{
"text": {
"text": [
"HERE"
]
}
}
],
"outputContexts": [
{
"name": "*****************************"
},
{
"name": "*****************************"
},
{
"name": "*****************************"
},
{
"name": "*****************************"
},
{
"name": "*****************************"
},
{
"name": "*****************************",
"parameters": {
"TRANSACTION_REQUIREMENTS_CHECK_RESULT": {
"#type": "type.googleapis.com/google.actions.v2.TransactionRequirementsCheckResult",
"resultType": "OK"
}
}
}
],
"intent": {
"name": "*****************************",
"displayName": "Int2"
},
"intentDetectionConfidence": 1,
"diagnosticInfo": {},
"languageCode": "en-us"
},
"originalDetectIntentRequest": {
"source": "google",
"version": "2",
"payload": {
"isInSandbox": true,
"surface": {
"capabilities": [
{
"name": "actions.capability.WEB_BROWSER"
},
{
"name": "actions.capability.MEDIA_RESPONSE_AUDIO"
},
{
"name": "actions.capability.SCREEN_OUTPUT"
},
{
"name": "actions.capability.AUDIO_OUTPUT"
}
]
},
"inputs": [
{
"rawInputs": [
{
"inputType": "KEYBOARD"
}
],
"arguments": [
{
"extension": {
"#type": "type.googleapis.com/google.actions.v2.TransactionRequirementsCheckResult",
"resultType": "OK"
},
"name": "TRANSACTION_REQUIREMENTS_CHECK_RESULT"
}
],
"intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK"
}
],
"user": {
"lastSeen": "2018-05-16T11:15:14Z",
"locale": "en-US",
"userId": "*****************************"
},
"conversation": {
"conversationId": "1526470000479",
"type": "ACTIVE",
"conversationToken": "[]"
},
"availableSurfaces": [
{
"capabilities": [
{
"name": "actions.capability.SCREEN_OUTPUT"
},
{
"name": "actions.capability.AUDIO_OUTPUT"
}
]
}
]
}
},
"session": "*****************************"
}
I think your response object is incorrect. the intent attribute should be inside the systemIntent object
"data": {
"google": {
"expectUserResponse": true,
"isSsml": false,
"noInputPrompts": [],
"systemIntent": {
"intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK",
"data": {
"#type": "type.googleapis.com/google.actions.v2.TransactionRequirementsCheckSpec",
"paymentOptions": {
"actionProvidedOptions": {
"displayName": "VISA-1234",
"paymentType": "PAYMENT_CARD"
}
}
}
}
}
}

How to create a pull request in a Bitbucket using api 1.0

I am trying to create an automation pipeline and in that, I want to create a pull request in bitbucket from my jenkins job. I found some document where I can create a pull request using rest api. But that is for api 2.0. I have old bitbucket and I am not sure which api version I have to use.
Thanks,
You can create a pull request in Bitbucket using the REST API 1.0 doing the following:
curl -s --user USER:PASS --request POST --data #- --header Content-Type:application/json https://BITBUCKET-SERVER/rest/api/1.0/projects/TO-PROJECT/repos/TO-REPOSITORY/pull-requests << EOF
{
"title": "SOME-TITTLE",
"description": "SOME-DESCRIPTION",
"state": "OPEN",
"open": true,
"closed": false,
"fromRef": {
"id": "refs/heads/FROM-BRANCH",
"repository": {
"slug": "FROM-REPO",
"name": null,
"project": {
"key": "FROM-PROJECT"
}
}
},
"toRef": {
"id": "refs/heads/TO-BRANCH",
"repository": {
"slug": "TO-REPO",
"name": null,
"project": {
"key": "TO-PROJECT"
}
}
},
"locked": false,
"reviewers": [
{
"user": {
"name": "REVIEWER"
}
}
]
}