Integrating Git And GitHub Using Java

Integrating Git And GitHub Using Java

Automating the local and remote repository creation.

In this blog post I will be teaching how one can automatically create local git and remote GitHub repository by just using java program. This java program can also create the readme.md file and it will also perform the first commit and first push from local git repository to remote GitHub repository.

We will be doing this with the help GitHub APIs and with some java libraries. GitHub provides lots of great APIs based on REST and GraphQL architecture. To works with GitHub APIs we need a Personal Access Token with required privileges. When you are going to create a personal access token then GitHub will ask for what are the privileges that you want to give to the token. Below is the screenshot that shows all the checks that are required. Screenshot from 2022-11-06 13-27-12.png


Java Setup

Run java -version and javac -version from terminal and make sure your versions are up to date. This is the output that i get when i run these commands.

Screenshot from 2022-11-06 19-48-58.png

I'm using Linux for this tutorial so I will only be telling the setup procedures that will work with Linux based OS. It might also works on other Operating System and if it is not then it will require some googling skills.

This tutorial also requires that you have added a SSH key to you GitHub account and also using ssh based repository URLs. And if not then this tutorial will help you in adding the ssh key to your account.


Code

Now every thing is setup, lets go the coding part :)

We need a external JSON library because we will be working with json data while creating remote repository. We will json-simple, download it and add it to your CLASSPATH.

We will create two java files, one will work as entry point for our script and second will have the implementation that will do our work. So, lets create files, Main.java and Integration.java. Main.java will work as entry point and Integration.java will have implementations.

Integration.java

Lets first talk about the code that will be written in Integration.java. Create a public class named as Integration. This class will consist of methods that will help us to create local and remote repositories.

public class Integration {

}

Lets create a method named Run inside Integration class that will used to run terminal commands. It will return true if the command run successfully and false if there is any error occurs while running the commands.

public boolean Run(String[] commands) throws InterruptedException {
    ProcessBuilder processBuilder = new ProcessBuilder(commands);
    processBuilder.directory(new File(System.getProperty("user.dir")));
    try {
         Process process = processBuilder.start();
         BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
         String line;
         while ((line = reader.readLine()) != null) {
             System.out.println("[SUCCESS] -> " + line);
         }

         BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
         String errorLine;
         while ((errorLine = errorReader.readLine()) != null) {
             System.out.println("[INFO] -> " + errorLine);
         }

         int exitCode = process.waitFor();
         if (exitCode != 0) {
             System.out.println("[ERROR_CODE] -> " + String.valueOf(exitCode));
             return false;
         }

     } catch (IOException e) {
         e.printStackTrace();
         return false;
     }
     return true;
}

We also need a method that will help us in creating files because we also wants that our program to create readme.md file. This method also return boolean result.

private boolean CreateReadmeFile(String name) {
        try {
            FileWriter writer = new FileWriter(System.getProperty("user.dir") + "/readme.md", true);
            writer.write("# " + name);
            writer.write("\r\n"); // write new line
            writer.write("### This file generated by GGI");
            writer.close();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

Its time to create a method that will help us in creating local git repository, creating a readme file, performing the first commit and the first push to the remote repository.

public boolean CreateLocalRepo(String ssh_url, String name) throws InterruptedException {
        System.out.println("Creating Local Repository...");
        String[] c1 = { "git", "init" };
        String[] c2 = { "git", "add", "readme.md" };
        String[] c3 = { "git", "commit", "-m", "'first commit'" };
        String[] c4 = { "git", "branch", "-M", "main" };
        String[] c5 = { "git", "remote", "add", "origin", ssh_url };
        String[] c6 = { "git", "push", "-u", "origin", "main" };

        boolean isCreated = CreateReadmeFile(name);
        if (isCreated) {
            if (Run(c1)) {
                if (Run(c2)) {
                    if (Run(c3)) {
                        if (Run(c4)) {
                            if (Run(c5)) {
                                if (Run(c6)) {
                                    System.out.println("Local repository has been successfully created");
                                    return true;
                                }
                            }
                        }
                    }
                }
            }
        }
        System.out.println("[ERROR] -> Something went wrong while setting up local repo...");
        return false;
    }

Now, finally we create a method that will create a remote GitHub repository. But before that we need Container that will help us to work with JSON.

private ContainerFactory containerFactory = new ContainerFactory() {
        @Override
        public List<Object> creatArrayContainer() {
            return new LinkedList<Object>();
        }

        @Override
        public Map<String, Object> createObjectContainer() {
            return new LinkedHashMap<String, Object>();
        }
    };

    public String CreateRemoteRepo(String name, String desc, String token)
            throws org.json.simple.parser.ParseException {
        System.out.println("Creating Remote Repository on Github...");
        HashMap<String, Object> body = new HashMap<String, Object>();
        body.put("name", name);
        body.put("description", desc);
        body.put("homepage", "https://github.com");
        body.put("private", false);
        body.put("is_template", false);

        JSONObject obj = new JSONObject();
        obj.putAll(body);

        String str = obj.toJSONString();

        String uri = "https://api.github.com/user/repos";
        HttpRequest req = HttpRequest.newBuilder()
                .uri(URI.create(uri))
                .header("Accept", "application/vnd.github+json")
                .header("Authorization", "Bearer " + token)
                .POST(HttpRequest.BodyPublishers.ofString(str))
                .version(Version.HTTP_2)
                .build();

        HttpClient client = HttpClient.newBuilder()
                .build();
        String ssh_url = "";
        try {
            HttpResponse<String> response = client.send(req, BodyHandlers.ofString());
            System.out.println(response.statusCode());
            Map<?, ?> bodyObj;
            bodyObj = (Map<?, ?>) new JSONParser().parse(response.body(), containerFactory);
            ssh_url = (String) bodyObj.get("ssh_url");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return ssh_url;
    }


Main.java

Now we will create Main class and use the methods of Integration class.

public class Main {
    public static void main(String[] args) {
        Integration integrate = new Integration();
        String name_of_repo = "Demo";
        String description_of_repo = "<Replace it with actual description of repository>";
        String personal_access_token = "<Replace it with token that you have already created>";

        try {
            String ssh_utl = integrate.CreateRemoteRepo(name_of_repo, description_of_repo, personal_access_token);
            integrate.CreateLocalRepo(ssh_utl, name_of_repo);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

}

Here we are with all the implementation. Below is the complete code with imports.

Complete Code:

Integration.java

import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpClient.Version;
import java.net.http.HttpResponse.BodyHandlers;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.json.simple.JSONObject;
import org.json.simple.parser.ContainerFactory;
import org.json.simple.parser.JSONParser;

public class Integration {

    public boolean Run(String[] commands) throws InterruptedException {
        ProcessBuilder processBuilder = new ProcessBuilder(commands);
        processBuilder.directory(new File(System.getProperty("user.dir")));
        try {
            Process process = processBuilder.start();
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println("[SUCCESS] -> " + line);
            }

            BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            String errorLine;
            while ((errorLine = errorReader.readLine()) != null) {
                System.out.println("[INFO] -> " + errorLine);
            }

            int exitCode = process.waitFor();
            if (exitCode != 0) {
                System.out.println("[ERROR_CODE] -> " + String.valueOf(exitCode));
                return false;
            }

        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    private boolean CreateReadmeFile(String name) {
        try {
            FileWriter writer = new FileWriter(System.getProperty("user.dir") + "/readme.md", true);
            writer.write("# " + name);
            writer.write("\r\n"); // write new line
            writer.write("### This file generated by GGI");
            writer.close();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    public boolean CreateLocalRepo(String ssh_url, String name) throws InterruptedException {
        System.out.println("Creating Local Repository...");
        String[] c1 = { "git", "init" };
        String[] c2 = { "git", "add", "readme.md" };
        String[] c3 = { "git", "commit", "-m", "'first commit'" };
        String[] c4 = { "git", "branch", "-M", "main" };
        String[] c5 = { "git", "remote", "add", "origin", ssh_url };
        String[] c6 = { "git", "push", "-u", "origin", "main" };

        boolean isCreated = CreateReadmeFile(name);
        if (isCreated) {
            if (Run(c1)) {
                if (Run(c2)) {
                    if (Run(c3)) {
                        if (Run(c4)) {
                            if (Run(c5)) {
                                if (Run(c6)) {
                                    System.out.println("Local repository has been successfully created");
                                    return true;
                                }
                            }
                        }
                    }
                }
            }
        }
        System.out.println("[ERROR] -> Something went wrong while setting up local repo...");
        return false;
    }

    private ContainerFactory containerFactory = new ContainerFactory() {
        @Override
        public List<Object> creatArrayContainer() {
            return new LinkedList<Object>();
        }

        @Override
        public Map<String, Object> createObjectContainer() {
            return new LinkedHashMap<String, Object>();
        }
    };

    public String CreateRemoteRepo(String name, String desc, String token)
            throws org.json.simple.parser.ParseException {
        System.out.println("Creating Remote Repository on Github...");
        HashMap<String, Object> body = new HashMap<String, Object>();
        body.put("name", name);
        body.put("description", desc);
        body.put("homepage", "https://github.com");
        body.put("private", false);
        body.put("is_template", false);

        JSONObject obj = new JSONObject();
        obj.putAll(body);

        String str = obj.toJSONString();

        String uri = "https://api.github.com/user/repos";
        HttpRequest req = HttpRequest.newBuilder()
                .uri(URI.create(uri))
                .header("Accept", "application/vnd.github+json")
                .header("Authorization", "Bearer " + token)
                .POST(HttpRequest.BodyPublishers.ofString(str))
                .version(Version.HTTP_2)
                .build();

        HttpClient client = HttpClient.newBuilder()
                .build();
        String ssh_url = "";
        try {
            HttpResponse<String> response = client.send(req, BodyHandlers.ofString());
            System.out.println(response.statusCode());
            Map<?, ?> bodyObj;
            bodyObj = (Map<?, ?>) new JSONParser().parse(response.body(), containerFactory);
            ssh_url = (String) bodyObj.get("ssh_url");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return ssh_url;
    }
}

Main.java

import org.json.simple.parser.ParseException;

public class Main {
    public static void main(String[] args) {
        Integration integrate = new Integration();
        String name_of_repo = "Demo";
        String description_of_repo = "<Replace it with actual description of repository>";
        String personal_access_token = "<Replace it with token that you have already created>";

        try {
            String ssh_utl = integrate.CreateRemoteRepo(name_of_repo, description_of_repo, personal_access_token);
            integrate.CreateLocalRepo(ssh_utl, name_of_repo);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

If you are using vscode then you directly run this script by just clicking at run button. But if not using the vscode then first use javac to create a binary out of it and then use java to execute those binaries.

I hope this will works for you and if you have any suggestions then feel free to point it out.

Thank You.