mark
mark

Reputation: 62722

How to fetch the commit given tag Id using Azure DevOps REST Api?

Given a short id of a tag I would like to get the full commit Id of that tag using the Azure DevOps REST Api.

For example, given:

C:\Dayforce\tip [master ≡]> git lg -1 58.0.0
7b3570ec9e7 |  (tag: 58.0.0) Some commit
C:\Dayforce\tip [master ≡]> git rev-parse 58.0.0
1c9615df48f868012cbc3dbe3552d98847c86fa2
C:\Dayforce\tip [master ≡]> git lg -1 1c9615df48f
7b3570ec9e7 |  (tag: 58.0.0) Some commit
C:\Dayforce\tip [master ≡]> git rev-parse 7b3570ec9e7
7b3570ec9e7af88f7d427e3df3fc41ee1d4c6cf1
C:\Dayforce\tip [master ≡]>

I am interested in a REST API for Azure DevOps that when given 1c9615df48f returns 7b3570ec9e7af88f7d427e3df3fc41ee1d4c6cf1 on this particular repository.

EDIT 1

The following function uses REST API to return the full commit Id given a short one:

filter Get-FullCommitIdByRestApi(
    [Parameter(Mandatory, ValueFromPipeline)][string[]]$CommitId,
    [Parameter(Mandatory)]$TeamProject,
    [Parameter(Mandatory)]$RepoName
)
{
    process
    {
        $CommitId | ForEach-Object {
            $cur = $_
            if ($cur.Length -lt 40)
            {
                $FromCommitId = $cur + '0' * (40 - $cur.Length)
                $ToCommitId = $cur + 'F' * (40 - $cur.Length)
                $url = "$TfsInstanceUrl/$TeamProject/_apis/git/repositories/$RepoName/commits?$TfsApiVersion&searchCriteria.fromCommitId=$FromCommitId&searchCriteria.toCommitId=$ToCommitId&searchCriteria.`$top=2" 
                $r = (Invoke-RestMethod $url -UseDefaultCredentials).value
                if (!$r)
                {
                    throw "Commit not found: $cur"
                }
                if ($r.Count -gt 1)
                {
                    throw "Commit too short: $cur"
                }
                $cur = $r.commitId
            }
            $cur
        }
    }
}

The problem is it fails if I give it a short tag Id.

Upvotes: 1

Views: 2567

Answers (3)

MaMazav
MaMazav

Reputation: 1885

EDIT: Notice @mark 's comment on this answer - the suggestion below works only for simple tags (i.e. tags that created by simply "git tag ..." command), but not for annotated tags ("git tag -a ... ...").

Use following call:

https://dev.azure.com/{organization}/{project}/_apis/git/repositories/{repositoryId}/refs?filter=tags/{tagName}&api-version=5.0-preview.1

Example response:

{
    "value": [{
            "name": "refs/tags/tagName",
            "objectId": "42635c0000000000000000000000000000000000",
            "creator": {
                ...
            },
            "url": "https://dev.azure.com/{organization}/00000000-4c33-497e-b831-000000000000/_apis/git/repositories/00000000-e61c-4741-9110-000000000000/refs?filter=tags%2FtagName"
        }
    ],
    "count": 1
}

The commit hash is in $response.value[0].objectId.

(Based on the following answer: https://stackoverflow.com/a/59608725/2463642).

Upvotes: 0

mark
mark

Reputation: 62722

I ended up with the following PS function:

function Get-RefCommitIdByRestApi(
    [Parameter(Mandatory)][ValidateSet('tag', 'head')]$kind,
    [Parameter(Mandatory)]$ref,
    [Parameter(Mandatory)]$TeamProject,
    [Parameter(Mandatory)]$RepoName,
    [switch]$PassThru
)
{
    $FullRefName = "${kind}s/$ref"
    $url = "$TfsInstanceUrl/$TeamProject/_apis/git/repositories/$RepoName/refs?api-version=5.0&filter=$FullRefName&`$top=2"
    $r = (Invoke-RestMethod $url -UseDefaultCredentials).value | Where-Object {
        $_.name -eq "refs/$FullRefName"
    }
    if (!$PassThru -and (!$r -or ($r -is [array])))
    {
        throw "$kind not found: $ref"
    }
    $res = $r.objectId
    if ($res -and $kind -eq 'tag')
    {
        # Could be an annotated tag, in which case the returned Id is that of the tag rather than of the commit.
        # Try to access the annotated tag information
        $url = "$TfsInstanceUrl/$TeamProject/_apis/git/repositories/$RepoName/annotatedtags/${res}?api-version=5.1-preview"
        try
        {
            $r = Invoke-RestMethod $url -UseDefaultCredentials
        }
        catch
        {
            $r = $null
        }
        if ($r)
        {
            if ($r.taggedObject.objectType -ne 'commit')
            {
                throw "The tagged object type $($r.taggedObject.objectType) is not supported. Report this bug to XYZ."
            }
            $res = $r.taggedObject.objectId
        }
    }
    $res
}

It handles correctly both bare and annotated tags as well as regular branches.

Upvotes: 1

LoLance
LoLance

Reputation: 28096

Given a short id of a tag I would like to get the full commit Id of that tag using the Azure DevOps REST Api.

Check Annotated Tags - Get:

GET https://dev.azure.com/{organization}/{project}/_apis/git/repositories/{repositoryId}/annotatedtags/{objectId}?api-version=5.1-preview.1

The response would contain the commit tagged by this tag:

    ...  

    "name": "tag1",
    "objectId": "8630dxxxxxxxxxx5f8a6f1a2c8e9d55c",
    "taggedObject": {
        "objectId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "objectType": "commit"
    },

The ObjectId here refers to ObjectId (Sha1Id) of tag. So the supported scenario is: When given 1c9615df48f868012cbc3dbe3552d98847c86fa2 returns 7b3570ec9e7af88f7d427e3df3fc41ee1d4c6cf1 on this repository.

As for Given a short id of a tag I would like to get the full commit Id of that tag using the Azure DevOps REST Api, it's not supported for now.

Upvotes: 1

Related Questions