Skip to content

Commit

Permalink
Add support for deleting files from tree (#1678)
Browse files Browse the repository at this point in the history
* issue #1484: Add support for deleting files from tree

* Reorder GHTreeBuilder.delete method definition

* Hardcode mode value for deletion

* Add missing javadoc

* Update src/main/java/org/kohsuke/github/GHTreeBuilder.java

* Update src/main/java/org/kohsuke/github/GHTreeBuilder.java

* Update src/main/java/org/kohsuke/github/GHTreeBuilder.java

---------

Co-authored-by: Liam Newman <[email protected]>
  • Loading branch information
davseitsev and bitwiseman authored Jun 29, 2023
1 parent 8e73065 commit c494891
Show file tree
Hide file tree
Showing 39 changed files with 1,711 additions and 1 deletion.
31 changes: 30 additions & 1 deletion src/main/java/org/kohsuke/github/GHTreeBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class GHTreeBuilder {
// Issue #636: Create Tree no longer accepts null value in sha field
@JsonInclude(Include.NON_NULL)
@SuppressFBWarnings("URF_UNREAD_FIELD")
private static final class TreeEntry {
private static class TreeEntry {

private final String path;
private final String mode;
Expand All @@ -37,6 +37,22 @@ private TreeEntry(String path, String mode, String type) {
}
}

private static class DeleteTreeEntry extends TreeEntry {
/**
* According to reference doc https://docs.github.com/en/rest/git/trees?apiVersion=2022-11-28#create-a-tree: if
* sha value is null then the file will be deleted. That's why in this DTO sha is always {@literal null} and is
* included to json.
*/
@JsonInclude
private final String sha = null;

private DeleteTreeEntry(String path) {
// The `mode` and `type` parameters are required by the API, but their values are ignored during delete.
// Supply reasonable placeholders.
super(path, "100644", "blob");
}
}

/**
* Instantiates a new GH tree builder.
*
Expand Down Expand Up @@ -162,6 +178,19 @@ public GHTreeBuilder add(String path, String content, boolean executable) {
return add(path, content.getBytes(StandardCharsets.UTF_8), executable);
}

/**
* Removes an entry with the given path from base tree.
*
* @param path
* the file path in the tree
* @return this GHTreeBuilder
*/
public GHTreeBuilder delete(String path) {
TreeEntry entry = new DeleteTreeEntry(path);
treeEntries.add(entry);
return this;
}

private String getApiTail() {
return String.format("/repos/%s/%s/git/trees", repo.getOwnerName(), repo.getName());
}
Expand Down
40 changes: 40 additions & 0 deletions src/test/java/org/kohsuke/github/GHTreeBuilderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,46 @@ public void testAdd() throws Exception {

}

/**
* Test delete.
*
* @throws Exception
* the exception
*/
@Test
public void testDelete() throws Exception {
// add test tree
treeBuilder.add(PATH_README, CONTENT_README, false);
treeBuilder.add(PATH_DATA1, CONTENT_DATA1, false);

GHCommit commit = updateTree();

assertThat(getFileSize(PATH_README), equalTo((long) CONTENT_README.length()));
assertThat(getFileSize(PATH_DATA1), equalTo((long) CONTENT_DATA1.length));

assertThat(commit.getCommitShortInfo().getAuthor().getEmail(), equalTo("[email protected]"));
assertThat(commit.getCommitShortInfo().getCommitter().getEmail(), equalTo("[email protected]"));

// remove a file from tree
mainRef = repo.getRef("heads/main");
treeBuilder = repo.createTree().baseTree(commit.getTree().getSha());
treeBuilder.delete(PATH_DATA1);

GHCommit deleteCommit = updateTree();

assertThat(getFileSize(PATH_README), equalTo((long) CONTENT_README.length()));

assertThat(deleteCommit.getCommitShortInfo().getAuthor().getEmail(), equalTo("[email protected]"));
assertThat(deleteCommit.getCommitShortInfo().getCommitter().getEmail(), equalTo("[email protected]"));

try {
getFileSize(PATH_DATA1);
fail("File " + PATH_DATA1 + " should not exist");
} catch (IOException e) {
assertThat(e.getMessage(), stringContainsInOrder(PATH_DATA1, "Not Found"));
}
}

private GHCommit updateTree() throws IOException {
String treeSha = treeBuilder.create().getSha();
GHCommit commit = new GHCommitBuilder(repo).message("Add files")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
{
"id": 654900107,
"node_id": "R_kgDOJwj7iw",
"name": "GHTreeBuilderTest",
"full_name": "hub4j-test-org/GHTreeBuilderTest",
"private": true,
"owner": {
"login": "hub4j-test-org",
"id": 1793410,
"node_id": "MDQ6VXNlcjE3OTM0MTA=",
"avatar_url": "https://avatars.githubusercontent.com/u/1793410?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/hub4j-test-org",
"html_url": "https://github.com/hub4j-test-org",
"followers_url": "https://api.github.com/users/hub4j-test-org/followers",
"following_url": "https://api.github.com/users/hub4j-test-org/following{/other_user}",
"gists_url": "https://api.github.com/users/hub4j-test-org/gists{/gist_id}",
"starred_url": "https://api.github.com/users/hub4j-test-org/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/hub4j-test-org/subscriptions",
"organizations_url": "https://api.github.com/users/hub4j-test-org/orgs",
"repos_url": "https://api.github.com/users/hub4j-test-org/repos",
"events_url": "https://api.github.com/users/hub4j-test-org/events{/privacy}",
"received_events_url": "https://api.github.com/users/hub4j-test-org/received_events",
"type": "User",
"site_admin": false
},
"html_url": "https://github.com/hub4j-test-org/GHTreeBuilderTest",
"description": null,
"fork": false,
"url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest",
"forks_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/forks",
"keys_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/teams",
"hooks_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/hooks",
"issue_events_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/issues/events{/number}",
"events_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/events",
"assignees_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/assignees{/user}",
"branches_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/branches{/branch}",
"tags_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/tags",
"blobs_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/statuses/{sha}",
"languages_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/languages",
"stargazers_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/stargazers",
"contributors_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/contributors",
"subscribers_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/subscribers",
"subscription_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/subscription",
"commits_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/contents/{+path}",
"compare_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/merges",
"archive_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/downloads",
"issues_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/issues{/number}",
"pulls_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/pulls{/number}",
"milestones_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/milestones{/number}",
"notifications_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/labels{/name}",
"releases_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/releases{/id}",
"deployments_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/deployments",
"created_at": "2023-06-17T09:21:30Z",
"updated_at": "2023-06-17T09:21:30Z",
"pushed_at": "2023-06-20T05:28:20Z",
"git_url": "git://github.com/hub4j-test-org/GHTreeBuilderTest.git",
"ssh_url": "[email protected]:hub4j-test-org/GHTreeBuilderTest.git",
"clone_url": "https://github.com/hub4j-test-org/GHTreeBuilderTest.git",
"svn_url": "https://github.com/hub4j-test-org/GHTreeBuilderTest",
"homepage": null,
"size": 4,
"stargazers_count": 0,
"watchers_count": 0,
"language": null,
"has_issues": true,
"has_projects": true,
"has_downloads": true,
"has_wiki": false,
"has_pages": false,
"has_discussions": false,
"forks_count": 0,
"mirror_url": null,
"archived": false,
"disabled": false,
"open_issues_count": 0,
"license": null,
"allow_forking": true,
"is_template": false,
"web_commit_signoff_required": false,
"topics": [],
"visibility": "private",
"forks": 0,
"open_issues": 0,
"watchers": 0,
"default_branch": "main",
"permissions": {
"admin": true,
"maintain": true,
"push": true,
"triage": true,
"pull": true
},
"temp_clone_token": "AANV3AUXZXCI3AHCWHMMVFLESE5DS",
"allow_squash_merge": true,
"allow_merge_commit": true,
"allow_rebase_merge": true,
"allow_auto_merge": false,
"delete_branch_on_merge": false,
"allow_update_branch": false,
"use_squash_pr_title_as_default": false,
"squash_merge_commit_message": "COMMIT_MESSAGES",
"squash_merge_commit_title": "COMMIT_OR_PR_TITLE",
"merge_commit_message": "PR_TITLE",
"merge_commit_title": "MERGE_MESSAGE",
"network_count": 0,
"subscribers_count": 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{
"sha": "7e888a1cd95c3caf31a16ff21751a06a7feb039f",
"node_id": "MDY6Q29tbWl0NjU0OTAwMTA3OjdlODg4YTFjZDk1YzNjYWYzMWExNmZmMjE3NTFhMDZhN2ZlYjAzOWY=",
"commit": {
"author": {
"name": "author",
"email": "[email protected]",
"date": "2021-01-23T20:20:25Z"
},
"committer": {
"name": "committer",
"email": "[email protected]",
"date": "2021-01-23T20:20:25Z"
},
"message": "Add files",
"tree": {
"sha": "0efbfcf79def8e437d825e0116def4be6be56026",
"url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/git/trees/0efbfcf79def8e437d825e0116def4be6be56026"
},
"url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/git/commits/7e888a1cd95c3caf31a16ff21751a06a7feb039f",
"comment_count": 0,
"verification": {
"verified": false,
"reason": "unsigned",
"signature": null,
"payload": null
}
},
"url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/commits/7e888a1cd95c3caf31a16ff21751a06a7feb039f",
"html_url": "https://github.com/hub4j-test-org/GHTreeBuilderTest/commit/7e888a1cd95c3caf31a16ff21751a06a7feb039f",
"comments_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/commits/7e888a1cd95c3caf31a16ff21751a06a7feb039f/comments",
"author": null,
"committer": null,
"parents": [
{
"sha": "172349212fb19ffa4f33dcced3263c6963dc750a",
"url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/commits/172349212fb19ffa4f33dcced3263c6963dc750a",
"html_url": "https://github.com/hub4j-test-org/GHTreeBuilderTest/commit/172349212fb19ffa4f33dcced3263c6963dc750a"
}
],
"stats": {
"total": 2,
"additions": 2,
"deletions": 0
},
"files": [
{
"sha": "aed2973e4b8a7ff1b30ff5c4751e5a2b38989e74",
"filename": "data/val1.dat",
"status": "added",
"additions": 1,
"deletions": 0,
"changes": 1,
"blob_url": "https://github.com/hub4j-test-org/GHTreeBuilderTest/blob/7e888a1cd95c3caf31a16ff21751a06a7feb039f/data%2Fval1.dat",
"raw_url": "https://github.com/hub4j-test-org/GHTreeBuilderTest/raw/7e888a1cd95c3caf31a16ff21751a06a7feb039f/data%2Fval1.dat",
"contents_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/contents/data%2Fval1.dat?ref=7e888a1cd95c3caf31a16ff21751a06a7feb039f",
"patch": "@@ -0,0 +1 @@\n+\u0001\u0002\u0003\n\\ No newline at end of file"
},
{
"sha": "fbbc875b17d1e17da06b4ee8fda46e2596c41f3c",
"filename": "doc/readme.txt",
"status": "added",
"additions": 1,
"deletions": 0,
"changes": 1,
"blob_url": "https://github.com/hub4j-test-org/GHTreeBuilderTest/blob/7e888a1cd95c3caf31a16ff21751a06a7feb039f/doc%2Freadme.txt",
"raw_url": "https://github.com/hub4j-test-org/GHTreeBuilderTest/raw/7e888a1cd95c3caf31a16ff21751a06a7feb039f/doc%2Freadme.txt",
"contents_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/contents/doc%2Freadme.txt?ref=7e888a1cd95c3caf31a16ff21751a06a7feb039f",
"patch": "@@ -0,0 +1 @@\n+Thanks for using our application!"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"sha": "7f9b11d9512f639acc6d48439621026cf8410f3a",
"node_id": "MDY6Q29tbWl0NjU0OTAwMTA3OjdmOWIxMWQ5NTEyZjYzOWFjYzZkNDg0Mzk2MjEwMjZjZjg0MTBmM2E=",
"commit": {
"author": {
"name": "author",
"email": "[email protected]",
"date": "2021-01-23T20:20:25Z"
},
"committer": {
"name": "committer",
"email": "[email protected]",
"date": "2021-01-23T20:20:25Z"
},
"message": "Add files",
"tree": {
"sha": "f9a619cb835ac407e0a464618fc59386be70bd63",
"url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/git/trees/f9a619cb835ac407e0a464618fc59386be70bd63"
},
"url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/git/commits/7f9b11d9512f639acc6d48439621026cf8410f3a",
"comment_count": 0,
"verification": {
"verified": false,
"reason": "unsigned",
"signature": null,
"payload": null
}
},
"url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/commits/7f9b11d9512f639acc6d48439621026cf8410f3a",
"html_url": "https://github.com/hub4j-test-org/GHTreeBuilderTest/commit/7f9b11d9512f639acc6d48439621026cf8410f3a",
"comments_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/commits/7f9b11d9512f639acc6d48439621026cf8410f3a/comments",
"author": null,
"committer": null,
"parents": [
{
"sha": "7e888a1cd95c3caf31a16ff21751a06a7feb039f",
"url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/commits/7e888a1cd95c3caf31a16ff21751a06a7feb039f",
"html_url": "https://github.com/hub4j-test-org/GHTreeBuilderTest/commit/7e888a1cd95c3caf31a16ff21751a06a7feb039f"
}
],
"stats": {
"total": 1,
"additions": 0,
"deletions": 1
},
"files": [
{
"sha": "aed2973e4b8a7ff1b30ff5c4751e5a2b38989e74",
"filename": "data/val1.dat",
"status": "removed",
"additions": 0,
"deletions": 1,
"changes": 1,
"blob_url": "https://github.com/hub4j-test-org/GHTreeBuilderTest/blob/7e888a1cd95c3caf31a16ff21751a06a7feb039f/data%2Fval1.dat",
"raw_url": "https://github.com/hub4j-test-org/GHTreeBuilderTest/raw/7e888a1cd95c3caf31a16ff21751a06a7feb039f/data%2Fval1.dat",
"contents_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/contents/data%2Fval1.dat?ref=7e888a1cd95c3caf31a16ff21751a06a7feb039f",
"patch": "@@ -1 +0,0 @@\n-\u0001\u0002\u0003\n\\ No newline at end of file"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "val1.dat",
"path": "data/val1.dat",
"sha": "aed2973e4b8a7ff1b30ff5c4751e5a2b38989e74",
"size": 3,
"url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/contents/data/val1.dat?ref=main",
"html_url": "https://github.com/hub4j-test-org/GHTreeBuilderTest/blob/main/data/val1.dat",
"git_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/git/blobs/aed2973e4b8a7ff1b30ff5c4751e5a2b38989e74",
"download_url": "https://raw.githubusercontent.com/hub4j-test-org/GHTreeBuilderTest/main/data/val1.dat?token=AANV3AQG25IMIIRS2WYVBALESE4UY",
"type": "file",
"content": "AQID\n",
"encoding": "base64",
"_links": {
"self": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/contents/data/val1.dat?ref=main",
"git": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/git/blobs/aed2973e4b8a7ff1b30ff5c4751e5a2b38989e74",
"html": "https://github.com/hub4j-test-org/GHTreeBuilderTest/blob/main/data/val1.dat"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "readme.txt",
"path": "doc/readme.txt",
"sha": "fbbc875b17d1e17da06b4ee8fda46e2596c41f3c",
"size": 34,
"url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/contents/doc/readme.txt?ref=main",
"html_url": "https://github.com/hub4j-test-org/GHTreeBuilderTest/blob/main/doc/readme.txt",
"git_url": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/git/blobs/fbbc875b17d1e17da06b4ee8fda46e2596c41f3c",
"download_url": "https://raw.githubusercontent.com/hub4j-test-org/GHTreeBuilderTest/main/doc/readme.txt?token=AANV3AUAKUQF4Q66G35XPVLESE4UY",
"type": "file",
"content": "VGhhbmtzIGZvciB1c2luZyBvdXIgYXBwbGljYXRpb24hCg==\n",
"encoding": "base64",
"_links": {
"self": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/contents/doc/readme.txt?ref=main",
"git": "https://api.github.com/repos/hub4j-test-org/GHTreeBuilderTest/git/blobs/fbbc875b17d1e17da06b4ee8fda46e2596c41f3c",
"html": "https://github.com/hub4j-test-org/GHTreeBuilderTest/blob/main/doc/readme.txt"
}
}
Loading

0 comments on commit c494891

Please sign in to comment.