I have to use Java to programmatically create a GitHub repository and push code to it. Please advise on the best method to use. Also please share any code snippet or related links for the utility.
I referred jgit library, has anyone used it? I also referred hub, gh and command line utility.
You can use the GitHub Rest API.
Generate a Personal Access Token from Settings > Developers Settings > Personal Access Tokens
Once generated use that to call the endpoint -
https://api.github.com/user/repo
with body
{"name": "REPO_NAME"}
and Header
Authorization: token PERSONAL_ACCESS_TOKEN
Example Curl:
curl -H "Authorization: token PERSONAL_ACCESS TOKEN" https://api.github.com/user/repos -d '{"name": "REPO_NAME"}'
Reference Doc: https://docs.github.com/en/rest/repos/repos?apiVersion=2022-11-28#create-a-repository-for-the-authenticated-user
The gitlab4j api is a great library to do so : https://github.com/gitlab4j/gitlab4j-api
<!-- https://mvnrepository.com/artifact/org.gitlab4j/gitlab4j-api -->
<dependency>
<groupId>org.gitlab4j</groupId>
<artifactId>gitlab4j-api</artifactId>
<version>5.0.1</version>
</dependency>
I'm using to read files from repo, commit and create merge requests :
try {
var branchName = "BRANCH-" + random.nextLong();
var action = new CommitAction();
action.withContent(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(data))
.withFilePath(JSON_FILE_PATH).setAction(Action.UPDATE);
try (var glapi = new GitLabApi(GIT_HOSTNAME, token)) {
glapi.enableRequestResponseLogging(java.util.logging.Level.INFO);
glapi.getCommitsApi().createCommit(REPO_NAME, branchName, message, VERSION, null, null, action);
return glapi.getMergeRequestApi().createMergeRequest(DB_REPO_NAME, branchName, VERSION, message,
message, ADMIN_USER_ID);
}
} catch (Exception ex) {
throw new DataException(ex);
}
how to create a new repo, a new master branch and your first commit :
try (var glapi = new GitLabApi("https://gitlab.com/", token)) {
var projectApi = glapi.getProjectApi();
var project = projectApi.createProject("my-repo");
// my-repo created
var action = new CommitAction();
action.withContent("### ignore some files ###").withFilePath(".gitignore").setAction(Action.CREATE);
glapi.getCommitsApi().createCommit("my-repo", "master", "my first commit", "master", "author#mail.com",
"author", action);
// yoru first commit
}
for github you can use https://github.com/hub4j/github-api
#Test
public void testCreateRepoPublic() throws Exception {
initGithubInstance();
GHUser myself = gitHub.getMyself();
String repoName = "test-repo-public";
GHRepository repo = gitHub.createRepository(repoName).private_(false).create();
try {
assertThat(repo.isPrivate(), is(false));
repo.setPrivate(true);
assertThat(myself.getRepository(repoName).isPrivate(), is(true));
repo.setPrivate(false);
assertThat(myself.getRepository(repoName).isPrivate(), is(false));
} finally {
repo.delete();
}
}
commiting multiple files :
var repo = github.getRepository("my-repo");
GHRef mainRef = repo.getRef("heads/master");
String mainTreeSha = repo.getTreeRecursive("master", 1).getSha();
GHTreeBuilder treeBuilder = repo.createTree().baseTree(mainTreeSha);
treeBuilder.add("file1.txt", Files.readAllBytes(Path.of("file1.txt"), false);
treeBuilder.add("file2.json", Files.readAllBytes(Path.of("file2.json"), false);
treeBuilder.add("dir1/dir2/file3.xml", Files.readAllBytes(Path.of("dir1/dir2/file3.xml"), false);
String treeSha = treeBuilder.create().getSha();
GHCommit commit = repo.createCommit()
.tree(treeSha)
.message("adding multiple files example")
.author("author", "author#mail.com", new Date())
.committer("committer", "committer#mail.com", new Date())
.parent(mainRef.getObject().getSha())
.create();
String commitSha = commit.getSHA1();
mainRef.updateTo(commitSha);
Using eclipse jgit
<!-- https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit -->
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>6.2.0.202206071550-r</version>
</dependency>
Examples :
// to use basic auth
var credentials = new UsernamePasswordCredentialsProvider("user", "password");
// to clone a repository
Git.cloneRepository().setURI("https://github.com/my-repo.git").setCredentialsProvider(credentials).call();
// to init a new repository
Git.init().setDirectory(new File("/opt/my-repo")).setInitialBranch("master").call();
// to use a cloned repo
var git = Git.open(new File("/opt/my-repo"));
// to pull changes from remote
git.pull().setCredentialsProvider(credentials).call();
// to stage one file
git.add().setUpdate(true).addFilepattern("dir/file.txt").call();
// to stage all files in a directory
git.add().setUpdate(true).addFilepattern("dir").call();
// to create a commit with the staged files
git.commit().setMessage("just adding some files.").call();
// to push changes to remote
git.push().call();
I tried the jgit to add files to the GitHub repo. Commit is getting created, but the files are not added, In addfilepattern - I tried "." as well. Below is my code snippet:
Git.cloneRepository().setURI("https://github.com/"+org+"/"+repo+".git").setCredentialsProvider(credentialsProvider).setDirectory(new File(Gitpath)).setCloneAllBranches(true).call();
Git.init().setDirectory(new File(Gitpath)).setInitialBranch("main").call();
var git = Git.open(new File(Gitpath));
git.add().setUpdate(true).addFilepattern(directoryName+fileName).call();
git.commit().setMessage("Adding files.").call();
git.push().setCredentialsProvider(credentialsProvider).call();
Related
I am trying to write a java code , where I can update a file , and create a branch and then a PR out of this Branch in github. I am using this below library.
<!-- https://mvnrepository.com/artifact/org.eclipse.mylyn.github/org.eclipse.egit.github.core -->
<dependency>
<groupId>org.eclipse.mylyn.github</groupId>
<artifactId>org.eclipse.egit.github.core</artifactId>
<version>2.1.5</version>
</dependency>
I am able to connect to github using GitHubClient.java , and fetched the repository. But not able to create a branch and raise a PR through this library, I am not sure which class/method to use for creating branch and raise the PR
private String loadRepository(GitHubClient client, Repository repo) throws IOException {
System.out.println("\n\nScanning repository " + repo.getName());
ContentsService contentService = new ContentsService(client);
List<RepositoryContents> test = contentService.getContents(repo, "/pom.xml");
for (RepositoryContents content : test) {
String fileConent = content.getContent();
String pomXml = new String(Base64.decodeBase64(fileConent.getBytes()));
String s = t1(loadXMLFromString(pomXml)); // Updated the pom file, stroed in var s
// TODO , create a branch with this updated pom and raise PR
return s;
}
return null;
}
I am planning to integrate the TFS with another application using websevice.
I am new to TFS.so I downloaded the TFS Java SDK 2010.I have been writing s sample program to checkin file into TFS. but not successful. On internet also not much helpful post for Java side SDK samples.
Below is the code I have written:-
public static void main(String[] args) {
// TODO Auto-generated method stub
TFSTeamProjectCollection tpc = SnippetSettings.connectToTFS(); //got the connection to TFS
VersionControlClient vcc = tpc.getVersionControlClient();
//WorkspaceInfo wi = Workstation.Current.GetLocalWorkspaceInfo(Environment.CurrentDirectory);
//vcc.get
String[] paths =new String[1];
paths[0]="D:\\Tools\testfile.txt"; //wants to checkin this local file
Workspace ws = vcc.createWorkspace(null,"Testworkspacename3", null, "","Testcomment",null, null); // this is workspace created at path local C:\ProgramData\Microsoft Team Foundation Local Workspaces
int item = ws.pendAdd(paths, true, null, LockLevel.NONE, GetOptions.GET_ALL, PendChangesOptions.GET_LATEST_ON_CHECKOUT); // this line gives me 0 count. so this is problematic . 0 means nothing is being added.
PendingSet pd = ws.getPendingChanges();
PendingChange[] pendingChanges = pd.getPendingChanges();
ws.checkIn(pendingChanges, "samashti comment");
Project project = tpc.getWorkItemClient().getProjects().get(SnippetSettings.PROJECT_NAME);
System.out.println();
Please help here...what is the wrong here. Can some one provide me correct working sample for new file checkin and existing file checkin using JAVA.
Just refer these steps below:
Connect to team project collection
Get version control client
Create a new workspace
Add file to workspace
Get pending changes
Check in pending changes
Below are some links about TFS SDK for JAVA for your reference:
https://github.com/gocd/gocd/blob/master/tfs-impl/src/com/thoughtworks/go/tfssdk/TfsSDKCommand.java
https://github.com/jenkinsci/tfs-plugin/blob/master/src/main/java/hudson/plugins/tfs/commands/NewWorkspaceCommand.java
Please see the code snippet for creating and mapping workspace as per TFS-SDK-14.0.3
public static Workspace createAndMapWorkspace(final TFSTeamProjectCollection tpc) {
final String workspaceName = "SampleVCWorkspace" + System.currentTimeMillis(); //$NON-NLS-1$
Workspace workspace = null;
// Get the workspace
workspace = tpc.getVersionControlClient().tryGetWorkspace(ConsoleSettings.MAPPING_LOCAL_PATH);
// Create and map the workspace if it does not exist
if (workspace == null) {
workspace = tpc.getVersionControlClient().createWorkspace(
null,
workspaceName,
"Sample workspace comment", //$NON-NLS-1$
WorkspaceLocation.SERVER,
null,
WorkspacePermissionProfile.getPrivateProfile());
// Map the workspace
final WorkingFolder workingFolder = new WorkingFolder(
ConsoleSettings.MAPPING_SERVER_PATH,
LocalPath.canonicalize(ConsoleSettings.MAPPING_LOCAL_PATH));
workspace.createWorkingFolder(workingFolder);
}
System.out.println("Workspace '" + workspaceName + "' now exists and is mapped"); //$NON-NLS-1$ //$NON-NLS-2$
return workspace;
}
Contex
I'm trying to detect possible file rename that occurred after last commit, in a working copy.
On my example, I have a clean working copy and I do that:
git mv old.txt new.txt
Running $ git status shows the expected result:
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# renamed: old.txt -> new.txt
I tried
Using a StatusCommand, I can see old.txt in the removed list, and new.txt in the added list.
But I can't find a way to link them together.
I'm aware of the existence of RenameDetector, but it works using DiffEntry, and I don't know how to get DiffEntries between HEAD and the Working Copy.
Never mind, found the answer.
JGit's API is very complicated..
TreeWalk tw = new TreeWalk(repository);
tw.setRecursive(true);
tw.addTree(CommitUtils.getHead(repository).getTree());
tw.addTree(new FileTreeIterator(repository));
RenameDetector rd = new RenameDetector(repository);
rd.addAll(DiffEntry.scan(tw));
List<DiffEntry> lde = rd.compute(tw.getObjectReader(), null);
for (DiffEntry de : lde) {
if (de.getScore() >= rd.getRenameScore()) {
System.out.println("file: " + de.getOldPath() + " copied/moved to: " + de.getNewPath());
}
}
(This snippet also use Gitective library)
In a case that someone wants to use path filter when getting DiffEntry, new and old path should be provided.
List<DiffEntry> diffs = git.diff()
.setOldTree(prepareTreeParser(repository, oldCommit))
.setNewTree(prepareTreeParser(repository, newCommit))
.setPathFilter(PathFilterGroup.createFromStrings(new String[]{"new/b.txt","b.txt"}))
.call();
RenameDetector rd = new RenameDetector(repository);
rd.addAll(diffs);
diffs = rd.compute();
If you want code of tree parser method:
private static AbstractTreeIterator prepareTreeParser(Repository repository, String objectId) throws IOException {
try (RevWalk walk = new RevWalk(repository)) {
RevCommit commit = walk.parseCommit(repository.resolve(objectId));
RevTree tree = walk.parseTree(commit.getTree().getId());
CanonicalTreeParser treeParser = new CanonicalTreeParser();
try (ObjectReader reader = repository.newObjectReader()) {
treeParser.reset(reader, tree.getId());
}
walk.dispose();
return treeParser;
}
}
I would like to create a git repository browser with jgit. But i don't know how to get the last modified date and the last commit message for a file. Here is my current code for the browser:
File directory = new File("/Users/sdorra/.scm/repositories/git/scm-git");
Repository repository =
RepositoryCache.open(RepositoryCache.FileKey.lenient(directory,
FS.DETECTED), true);
try
{
ObjectId revId = repository.resolve(Constants.HEAD);
DirCache cache = new DirCache(directory, FS.DETECTED);
TreeWalk treeWalk = new TreeWalk(repository);
treeWalk.addTree(new RevWalk(repository).parseTree(revId));
treeWalk.addTree(new DirCacheIterator(cache));
while (treeWalk.next())
{
System.out.println("---------------------------");
System.out.append("name: ").println(treeWalk.getNameString());
System.out.append("path: ").println(treeWalk.getPathString());
ObjectLoader loader = repository.open(treeWalk.getObjectId(0));
System.out.append("directory: ").println(loader.getType()
== Constants.OBJ_TREE);
System.out.append("size: ").println(loader.getSize());
// ???
System.out.append("last modified: ").println("???");
System.out.append("message: ").println("???");
}
}
finally
{
if (repository != null)
{
repository.close();
}
}
It is possible to get the last commit of a file?
Note: My git repository is a bare repository without working copy.
You're using lower level JGit API, why don't you use LogCommand via the org.eclipse.jgit.api package? Then use addPath(...), call()...
After that, you should get a list of RevCommit's for the specified path.
I can't see on the wiki where checking out is documented. Ideally, I would like to check out a file "example/folder/file.xml", if not just the folder... and then when the application closes down or otherwise, be able to commit back in changes to this file. How do I do this?
As SVNKit developer, I would recommend you to prefer new API based on SvnOperationFactory. The old API (based on SVNClientManager) will be operational still but all new SVN features will come only to the new API.
final SvnOperationFactory svnOperationFactory = new SvnOperationFactory();
try {
final SvnCheckout checkout = svnOperationFactory.createCheckout();
checkout.setSingleTarget(SvnTarget.fromFile(workingCopyDirectory));
checkout.setSource(SvnTarget.fromURL(url));
//... other options
checkout.run();
} finally {
svnOperationFactory.dispose();
}
You cannot check out a file in Subversion. You have to check out a folder.
To check out a folder with one or more files:
SVNClientManager ourClientManager = SVNClientManager.newInstance(null,
repository.getAuthenticationManager());
SVNUpdateClient updateClient = ourClientManager.getUpdateClient();
updateClient.setIgnoreExternals(false);
updateClient.doCheckout(url, destPath, revision, revision,
isRecursive);
To commit a previously checked out folder:
SVNClientManager ourClientManager = SVNClientManager.newInstance(null,
repository.getAuthenticationManager());
ourClientManager.getWCClient().doInfo(wcPath, SVNRevision.HEAD);
ourClientManager.getCommitClient().doCommit
(new File[] { wcPath }, keepLocks, commitMessage, false, true);
I also used the code snippet proposed by Dmitry Pavlenko and I had no problems.
But it took nearly 30 minutes to checkout or update a repo struture of 35 MB.
It's not useable in my usecase (simply checking out a directory structure as part of the content/documents/media of a web application).
Or have I made some errors?
final ISVNAuthenticationManager authManager = SVNWCUtil.createDefaultAuthenticationManager(name, password);
final SVNURL svnUrl = SVNURL.create(url.getProtocol(), name, url.getHost(), 443, url.getPath(), true);
SVNRepository svnRepo= SVNRepositoryFactory.create(svnUrl);
svnRepo.setAuthenticationManager(authManager);
svnOperationFactory.setAuthenticationManager(authManager);
SVNDirEntry entry = svnRepo.info(".", -1);
long remoteRevision = entry.getRevision();
if (!workingCopyDirectory.exists()) {
workingCopyDirectory.mkdirs();
}
final SvnCheckout checkout = svnOperationFactory.createCheckout();
checkout.setSource(SvnTarget.fromURL(svnUrl));
checkout.setSingleTarget(SvnTarget.fromFile(workingCopyDirectory));
remoteRevision = checkout.run();