Rename a file with github api? - rename

I thought that the update file method of the Github API could be used to rename a file (by providing the new path as parameter) but it does not seem to work.
The only way to rename is to delete the file and to create a similar one with the new name?

I thought that the update file method of the Github API could be used to rename a file (by providing the new path as parameter) but it does not seem to work.
There's no way to rename a file with a single request to the API.
The only way to rename is to delete the file and to create a similar one with the new name?
That's one way, but the downside is that you get two commits in the history (one for the delete, and one for the create).
A different way is to use the low-level Git API:
https://developer.github.com/v3/git/
With that, you can modify the tree entry containing the blob to list it under a different name, then create a new commit for that tree, and finally update the branch to point to that new commit. The whole process requires more API requests, but you get a single commit for the rename.

I found this article useful: Renaming files using the GitHub api but it didn't work for me completely. It was duplicating files.
Since deleting files is available just through changing the tree I came up with such replacement of the tree in step 3 of that article:
{
"base_tree": "{yourbaseTreeSHA}",
"tree": [
{
"path": "archive/TF/service/DEV/service_SVCAAA03v3DEV.tf',
"mode": "100644",
"type": "blob",
"sha": "{yourFileTreeSHA}"",
},
{
"path": "TF/service/DEV/service_SVCAAA03v3DEV.tf",
"mode": "100644",
"type": "blob",
"sha": null,
}
],
}
and it really does the trick.
So to have the rename/move of the file done you need to do 5 calls to GitHub API but the result is awesome:
view of the commit on github

With the help of the following articles, I figured out how to rename a file with Github API.
node package: github-api
Commit directly to GitHub via API with Octokit
Commit a file with the GitHub API
First, find and store the tree that latest commit.
# Gem octokir.rb 4.2.0 and Github API v3
api = Octokit::Client.new(access_token: "")
ref = 'heads/master'
repo = 'repo/name'
master_ref = api.ref repo, ref
last_commit = api.commit(repo, master_ref[:object][:sha])
last_tree = api.tree(repo, last_commit[:sha], recursive: true)
Use The harder way described in article Commit a file with the
GitHub API to create a new tree. Then, do the rename just like the
nodeJs version does and create a new tree based on the below changes.
changed_tree = last_tree[:tree].map(&:to_hash).reject { |blob| blob[:type] == 'tree' }
changed_tree.each { |blob| blob[:path] = new_name if blob[:path] == old_name }
changed_tree.each { |blob| blob.delete(:url) && blob.delete(:size) }
new_tree = api.create_tree(repo, changed_tree)
Create a new commit then point the HEAD to it.
new_commit = api.create_commit(repo, "Rename #{File.basename(old_name)} to #{File.basename(new_name)}", new_tree[:sha], last_commit[:sha])
api.update_ref(repo, ref, new_commit.sha)
That's all.

For those who end up here looking for more options, there is a better way to rename a file/folder. Please refer to the below link:
Rename a file using GitHub api
Works for folder rename as well. There you would need to specify the folder path for new and old using the same payload structure as in the sample request in above link.

Related

repos/{org}/{repo}/git/trees/{sha} to query files in repo returns element with type=commit - how to deal with that?

I have some code to retrieve a list of files from a repository (using REST API v3) and it worked great for many cases, but now I've hit a problem where it didn't work. Looking into this, I found that one of the elements of the response had this:
{
"mode": "160000",
"path": "folderA/folderB/folderC",
"sha": "84419db012d987a1705eea28055b278c17411a93",
"type": "commit"
}
If I look at that path using the browser, the folder is shown as:
- so after some confusion and embarrassement, I looked at things and concluded this must be a submodule (indeed it is mentioned in /.gitmodules.
I wonder how to best deal with that when I want to retrieve everything: currently my plan is to use path-entry to find a matching [submodule "path"] and then retrieve the tree from the repo using ther url from .gitmodules and sha from the response that I quoted. There is a path in .gitmodules, too - I guess that's just redundant? (Would be grateful for any other comments and suggestions. Maybe there is an easier approach to get thinghs?)
Also, I did not find doc about this - so is submodule the only reason for having commit in the respone, or could there be other cases to consider?
Update: it worked as I described! But I'm really concerned I might be hit by other unexpected items in the reply, so the question is really about documentation regarding the items in a response to querying the tress-API.

can you delete a repo via pygithub?

Can you delete a repo using pygithub?
For example, as shown in this example, you can delete a file like so:
repo = g.get_repo("userName/repoName")
contents = repo.get_contents("filename.txt", ref="test")
repo.delete_file(contents.path, "remove test", contents.sha, branch="test")
Is there something analogous for deleting entire repos? If not, how can one do this via the github API?
The pygithub documentation does include a delete() method, which calls the exact GitHub repo DELETE API delete /repos/{owner}/{repo}
So it should be possible to call that method, as in PyGithub/PyGithub tests/Repository.py
g=Github('token')
repo = self.g.get_user().get_repo("TestPyGithub")
repo.delete()

Retrieve all repositories that contain a file in a path within a repository

I'm currently using Octokit.Net in attempt to search and find repositories that meet a specific criteria:
Repositories that include Android somewhere.
Includes any .xml files within a path matching res/layout
Has a minimum of 100 stars
etc
The goal is to find Android repositories over 100 stars that include any .xml files in the res/layout path.
To do this, I've tried to create two separate requests, one in which I use a SearchRepositoriesRequest to find repositories that match the Android characteristics and stars.
var request = new SearchRepositoriesRequest("android")
{
Stars = Range.GreaterThan(100),
In = new[] { InQualifier.Readme, InQualifier.Description, InQualifier.Name },
SortField = RepoSearchSort.Stars,
};
I then add these repositories to a RepositoryCollection and use it within the SearchCodeRequest which my hope is that within each of these repositories I can then search for the Extension, Language, Path, and more.
var request1 = new SearchCodeRequest()
{
Repos = repositoryCollection,
In = new[] { CodeInQualifier.File, CodeInQualifier.Path },
Language = Language.Xml,
Size = Range.GreaterThan(100),
Path = "res/layout",
Extension = "xml",
};
Generally speaking, is there a way to search a collection of repositories that includes a generic file in a path?
I'm more or less seeing the same results from the Advanced GitHub Search. Sadly this makes me think this isn't possible today with GitHub v3 API.
I did find some limitations within various blogs and similar that seem like this might not be possible?
Considerations for code search
Due to the complexity of searching code, there are a few restrictions on how searches are performed:
Only the default branch is considered. In most cases, this will be the master branch.
Only files smaller than 384 KB are searchable.
You must always include at least one search term when searching source code. For example, searching for language:go is not valid, while amazing language:go is.

Github API to download a zipball/tarball which includes LFS files

I am retrieving a tarball from Github using the v3 API, i.e. https://api.github.com/repos/my-account/my-project/tarball/my-ref.
However, this project uses Git-LFS for some files, and the resulting archive doesn't contain the files but the LFS link:
version https://git-lfs.github.com/spec/v1
oid sha256:fc03a2eadf6ac4872de8ad96a865ed05c45c416c5ad40c9efa3c4bcbe5d0dc9e
size 1284
What can I do in order to get an archive having the LFS links replaced by the real file content?
The Git-lfs API shows how and where to make requests.
In your case, assuming you know the OID you're looking for (it's stored in the pointer) you should:
POST https://github.com/your-account/your-repo/objects with something like:
{
"operation": "download",
"objects": [
{
"oid": "fc03a2eadf6ac4872de8ad96a865ed05c45c416c5ad40c9efa3c4bcbe5d0dc9e",
"size": 1284
}
]
}
Maybe you can ommit the size part - it's not really specified. Also you can request several OIDs together in the batch request
The response will look something like this and will contain download links to the blobs themselves if they exist or some error for each of them (the response as a whole always returns as 200 if you are authenticated).

JGit: Is there a thread safe way to add and update files

The easy way to add or update files in JGit is like this:
git.add().addFilepattern(file).call()
But that assumes that the file exists in the Git working directory.
If I have a multi-threaded setup (using Scala and Akka), is there a way to work only on a bare repository, writing the data directly to JGit, avoiding having to first write the file in the working directory?
For getting the file, that seems to work with:
git.getRepository().open(objId).getBytes()
Is there something similar for adding or updating files?
"Add" is a high-level abstraction that places a file in the index. In a bare repository, you lack an index, so this is not a 1:1 correspondence between the functionality. Instead, you can create a file in a new commit. To do this, you would use an ObjectInserter to add objects to the repository (one per thread, please). Then you would:
Add the contents of the file to the repository, as a blob, by inserting its bytes (or providing an InputStream).
Create a tree that includes the new file, by using a TreeFormatter.
Create a commit that points to the tree, by using a CommitBuilder.
For example, to create a new commit (with no parents) that contains only your file:
ObjectInserter repoInserter = repository.newObjectInserter();
ObjectId blobId;
try
{
// Add a blob to the repository
ObjectId blobId = repoInserter.insert(OBJ_BLOB, "Hello World!\n".getBytes());
// Create a tree that contains the blob as file "hello.txt"
TreeFormatter treeFormatter = new TreeFormatter();
treeFormatter.append("hello.txt", FileMode.TYPE_FILE, blobId);
ObjectId treeId = treeFormatter.insertTo(repoInserter);
// Create a commit that contains this tree
CommitBuilder commit = new CommitBuilder();
PersonIdent ident = new PersonIdent("Me", "me#example.com");
commit.setCommitter(ident);
commit.setAuthor(ident);
commit.setMessage("This is a new commit!");
commit.setTreeId(treeId);
ObjectId commitId = repositoryInserter.insert(commit);
repoInserter.flush();
}
finally
{
repoInserter.release();
}
Now you can git checkout the commit id returned as commitId.

Resources