Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GraphQL query to get file info from GitHub repository

I would like to use GitHub repository for posts in my Gatsby site. Right now I'm using two queries, first to get the names of the files:

{
  viewer {
    repository(name: "repository-name") {
      object(expression: "master:") {
        id
        ... on Tree {
          entries {
            name
          }
        }
      }
      pushedAt
    }
  }
}

And the second to get the contents of the files:

{
  viewer {
    repository(name: "repository-name") {
      object(expression: "master:file.md") {
        ... on Blob {
          text
        }
      }
    }
  }
}

Is there any way to get information about when each file was created and last updated with GraphQL? Right now I can get only pushedAt for the whole repository and not individual files.

like image 397
jupiteror Avatar asked Jun 09 '20 05:06

jupiteror


1 Answers

You can use the following query to get the file content and at the same time getting the last commit for this file. This way you also get the fields pushedAt, committedDate and authorDate depending on what you need :

{
  repository(owner: "torvalds", name: "linux") {
    content: object(expression: "master:Makefile") {
      ... on Blob {
        text
      }
    }
    info: ref(qualifiedName: "master") {
      target {
        ... on Commit {
          history(first: 1, path: "Makefile") {
            nodes {
              author {
                email
              }
              message
              pushedDate
              committedDate
              authoredDate
            }
            pageInfo {
              endCursor
            }
            totalCount
          }
        }
      }
    }
  }
}

Note that we need to also get the endCursor field in order to get the first commit on the file (to get the file creation date)

For instance on the Linux repo, for the Makefile file it gives:

"pageInfo": {
  "endCursor": "b29482fde649c72441d5478a4ea2c52c56d97a5e 0"
}
"totalCount": 1806

So there are 1806 commit for this file

In order to get the first commit, a query referencing the last cursor which would be b29482fde649c72441d5478a4ea2c52c56d97a5e 1804:

{
  repository(owner: "torvalds", name: "linux") {
    info: ref(qualifiedName: "master") {
      target {
        ... on Commit {
          history(first: 1, after:"b29482fde649c72441d5478a4ea2c52c56d97a5e 1804", path: "Makefile") {
            nodes {
              author {
                email
              }
              message
              pushedDate
              committedDate
              authoredDate
            }
          }
        }
      }
    }
  }
}

which returns the first commit of this file.

I don't have any source about the cursor string format "b29482fde649c72441d5478a4ea2c52c56d97a5e 1804", I've tested with some other repositories with files with more than 1000 commits and it seems that it's always formatted like :

<static hash> <incremented_number>

which avoid to iterate over all the commits in case that there is more than 100 commits referencing your file

Here is an implementation in javascript using graphql.js :

const graphql = require('graphql.js');

const token = "YOUR_TOKEN";
const queryVars = { name: "linux", owner: "torvalds" };
const file = "Makefile";
const branch = "master";

var graph = graphql("https://api.github.com/graphql", {
  headers: {
    "Authorization": `Bearer ${token}`,
    'User-Agent': 'My Application'
  },
  asJSON: true
});

graph(`
    query ($name: String!, $owner: String!){
      repository(owner: $owner, name: $name) {
        content: object(expression: "${branch}:${file}") {
          ... on Blob {
            text
          }
        }
        info: ref(qualifiedName: "${branch}") {
          target {
            ... on Commit {
              history(first: 1, path: "${file}") {
                nodes {
                  author {
                    email
                  }
                  message
                  pushedDate
                  committedDate
                  authoredDate
                }
                pageInfo {
                  endCursor
                }
                totalCount
              }
            }
          }
        }
      }
    }
`)(queryVars).then(function(response) {
  console.log(JSON.stringify(response, null, 2));
  var totalCount = response.repository.info.target.history.totalCount;
  if (totalCount > 1) {
    var cursorPrefix = response.repository.info.target.history.pageInfo.endCursor.split(" ")[0];
    var nextCursor = `${cursorPrefix} ${totalCount-2}`;
    console.log(`total count : ${totalCount}`);
    console.log(`cursorPrefix : ${cursorPrefix}`);
    console.log(`get element after cursor : ${nextCursor}`);

    graph(`
      query ($name: String!, $owner: String!){
        repository(owner: $owner, name: $name) {
          info: ref(qualifiedName: "${branch}") {
            target {
              ... on Commit {
                history(first: 1, after:"${nextCursor}", path: "${file}") {
                  nodes {
                    author {
                      email
                    }
                    message
                    pushedDate
                    committedDate
                    authoredDate
                  }
                }
              }
            }
          }
        }
      }`)(queryVars).then(function(response) {
        console.log("first commit info");
        console.log(JSON.stringify(response, null, 2));
      }).catch(function(error) {
        console.log(error);
      });
  }
}).catch(function(error) {
  console.log(error);
});
like image 169
Bertrand Martel Avatar answered Oct 18 '22 07:10

Bertrand Martel