From baa3a41ba28a1da7de093c0c57e4b424401b872c Mon Sep 17 00:00:00 2001 From: Muhammad Tamir Date: Thu, 19 Jun 2025 19:22:48 +0700 Subject: [PATCH] All Git Basic Function --- app/src/main/java/org/yuemi/App.java | 2 + .../org/yuemi/commands/CommandRegistrar.java | 16 ++ .../org/yuemi/commands/GitRootCommand.java | 34 ++++ .../yuemi/commands/SubcommandExecutor.java | 7 + .../org/yuemi/commands/SubcommandHandler.java | 44 ++++++ .../subcommands/GitAddSubcommand.java | 63 ++++++++ .../subcommands/GitCommitSubcommand.java | 42 +++++ .../subcommands/GitFetchSubcommand.java | 50 ++++++ .../subcommands/GitHelpSubcommand.java | 30 ++++ .../subcommands/GitInitSubcommand.java | 38 +++++ .../subcommands/GitPullSubcommand.java | 50 ++++++ .../subcommands/GitPushSubcommand.java | 50 ++++++ .../subcommands/GitRemoteSubcommand.java | 65 ++++++++ .../subcommands/GitResetSubcommand.java | 55 +++++++ .../subcommands/GitStatusSubcommand.java | 68 ++++++++ .../main/java/org/yuemi/git/GitManager.java | 146 ++++++++++++++++++ app/src/main/resources/gitignore.txt | 14 ++ app/src/main/resources/plugin.yml | 9 +- 18 files changed, 777 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/org/yuemi/commands/CommandRegistrar.java create mode 100644 app/src/main/java/org/yuemi/commands/GitRootCommand.java create mode 100644 app/src/main/java/org/yuemi/commands/SubcommandExecutor.java create mode 100644 app/src/main/java/org/yuemi/commands/SubcommandHandler.java create mode 100644 app/src/main/java/org/yuemi/commands/subcommands/GitAddSubcommand.java create mode 100644 app/src/main/java/org/yuemi/commands/subcommands/GitCommitSubcommand.java create mode 100644 app/src/main/java/org/yuemi/commands/subcommands/GitFetchSubcommand.java create mode 100644 app/src/main/java/org/yuemi/commands/subcommands/GitHelpSubcommand.java create mode 100644 app/src/main/java/org/yuemi/commands/subcommands/GitInitSubcommand.java create mode 100644 app/src/main/java/org/yuemi/commands/subcommands/GitPullSubcommand.java create mode 100644 app/src/main/java/org/yuemi/commands/subcommands/GitPushSubcommand.java create mode 100644 app/src/main/java/org/yuemi/commands/subcommands/GitRemoteSubcommand.java create mode 100644 app/src/main/java/org/yuemi/commands/subcommands/GitResetSubcommand.java create mode 100644 app/src/main/java/org/yuemi/commands/subcommands/GitStatusSubcommand.java create mode 100644 app/src/main/java/org/yuemi/git/GitManager.java create mode 100644 app/src/main/resources/gitignore.txt diff --git a/app/src/main/java/org/yuemi/App.java b/app/src/main/java/org/yuemi/App.java index 073bb17..9a32815 100644 --- a/app/src/main/java/org/yuemi/App.java +++ b/app/src/main/java/org/yuemi/App.java @@ -1,11 +1,13 @@ package org.yuemi; import org.bukkit.plugin.java.JavaPlugin; +import org.yuemi.commands.CommandRegistrar; public class App extends JavaPlugin { @Override public void onEnable() { getLogger().info("Yuemi Git Plugin enabled."); + new CommandRegistrar(this).registerAll(); } @Override diff --git a/app/src/main/java/org/yuemi/commands/CommandRegistrar.java b/app/src/main/java/org/yuemi/commands/CommandRegistrar.java new file mode 100644 index 0000000..6b3673b --- /dev/null +++ b/app/src/main/java/org/yuemi/commands/CommandRegistrar.java @@ -0,0 +1,16 @@ +package org.yuemi.commands; + +import org.bukkit.plugin.java.JavaPlugin; + +public class CommandRegistrar { + + private final JavaPlugin plugin; + + public CommandRegistrar(JavaPlugin plugin) { + this.plugin = plugin; + } + + public void registerAll() { + plugin.getCommand("git").setExecutor(new GitRootCommand(plugin)); + } +} diff --git a/app/src/main/java/org/yuemi/commands/GitRootCommand.java b/app/src/main/java/org/yuemi/commands/GitRootCommand.java new file mode 100644 index 0000000..1b8e1b3 --- /dev/null +++ b/app/src/main/java/org/yuemi/commands/GitRootCommand.java @@ -0,0 +1,34 @@ +package org.yuemi.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.java.JavaPlugin; +import org.yuemi.commands.SubcommandHandler; +import org.yuemi.commands.subcommands.GitHelpSubcommand; + +public class GitRootCommand implements CommandExecutor { + + private final JavaPlugin plugin; + private final SubcommandHandler handler; + + public GitRootCommand(JavaPlugin plugin) { + this.plugin = plugin; + this.handler = new SubcommandHandler(plugin); + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (args.length == 0) { + new GitHelpSubcommand(plugin).execute(sender, args); + return true; + } + + + String subcommand = args[0].toLowerCase(); + String[] subArgs = java.util.Arrays.copyOfRange(args, 1, args.length); + + handler.handle(sender, subcommand, subArgs); + return true; + } +} diff --git a/app/src/main/java/org/yuemi/commands/SubcommandExecutor.java b/app/src/main/java/org/yuemi/commands/SubcommandExecutor.java new file mode 100644 index 0000000..41e100e --- /dev/null +++ b/app/src/main/java/org/yuemi/commands/SubcommandExecutor.java @@ -0,0 +1,7 @@ +package org.yuemi.commands; + +import org.bukkit.command.CommandSender; + +public interface SubcommandExecutor { + void execute(CommandSender sender, String[] args); +} diff --git a/app/src/main/java/org/yuemi/commands/SubcommandHandler.java b/app/src/main/java/org/yuemi/commands/SubcommandHandler.java new file mode 100644 index 0000000..07f2c51 --- /dev/null +++ b/app/src/main/java/org/yuemi/commands/SubcommandHandler.java @@ -0,0 +1,44 @@ +package org.yuemi.commands; + +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.java.JavaPlugin; +import org.yuemi.commands.subcommands.GitAddSubcommand; +import org.yuemi.commands.subcommands.GitCommitSubcommand; +import org.yuemi.commands.subcommands.GitPushSubcommand; +import org.yuemi.commands.subcommands.GitResetSubcommand; +import org.yuemi.commands.subcommands.GitInitSubcommand; +import org.yuemi.commands.subcommands.GitRemoteSubcommand; +import org.yuemi.commands.subcommands.GitFetchSubcommand; +import org.yuemi.commands.subcommands.GitPullSubcommand; +import org.yuemi.commands.subcommands.GitStatusSubcommand; +import org.yuemi.commands.subcommands.GitHelpSubcommand; +import java.util.HashMap; +import java.util.Map; + +public class SubcommandHandler { + + private final Map commands = new HashMap<>(); + + public SubcommandHandler(JavaPlugin plugin) { + commands.put("add", new GitAddSubcommand(plugin)); + commands.put("commit", new GitCommitSubcommand(plugin)); + commands.put("push", new GitPushSubcommand(plugin)); + commands.put("reset", new GitResetSubcommand(plugin)); + commands.put("init", new GitInitSubcommand(plugin)); + commands.put("remote", new GitRemoteSubcommand(plugin)); + commands.put("fetch", new GitFetchSubcommand(plugin)); + commands.put("pull", new GitPullSubcommand(plugin)); + commands.put("status", new GitStatusSubcommand(plugin)); + commands.put("help", new GitHelpSubcommand(plugin)); + } + + public void handle(CommandSender sender, String name, String[] args) { + SubcommandExecutor executor = commands.get(name.toLowerCase()); + if (executor == null) { + sender.sendMessage("§cUnknown subcommand: " + name); + return; + } + + executor.execute(sender, args); + } +} diff --git a/app/src/main/java/org/yuemi/commands/subcommands/GitAddSubcommand.java b/app/src/main/java/org/yuemi/commands/subcommands/GitAddSubcommand.java new file mode 100644 index 0000000..27b1032 --- /dev/null +++ b/app/src/main/java/org/yuemi/commands/subcommands/GitAddSubcommand.java @@ -0,0 +1,63 @@ +package org.yuemi.commands.subcommands; + +import org.yuemi.commands.SubcommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.java.JavaPlugin; +import org.yuemi.git.GitManager; +import java.util.List; +import java.util.ArrayList; +import java.io.File; + +public class GitAddSubcommand implements SubcommandExecutor { + + private final JavaPlugin plugin; + + public GitAddSubcommand(JavaPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void execute(CommandSender sender, String[] args) { + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { + File repoFolder = new File("."); // Default to root + List filesToAdd = new ArrayList<>(); + + // Parse args + for (String arg : args) { + if (arg.equals(".")) { + // Use server root, add everything + repoFolder = new File("."); + } else if (arg.startsWith("--path=")) { + repoFolder = new File(arg.substring("--path=".length())); + } else if (arg.startsWith("--include=")) { + filesToAdd.add(arg.substring("--include=".length())); + } else if (!arg.startsWith("--")) { + // Add as literal file path + filesToAdd.add(arg); + } + } + + try { + if (!repoFolder.exists() || !repoFolder.isDirectory()) { + sender.sendMessage("§cInvalid path: " + repoFolder.getAbsolutePath()); + return; + } + + GitManager git = new GitManager(repoFolder); + + if (filesToAdd.isEmpty()) { + git.addAll(); + sender.sendMessage("§aStaged ALL files in: §f" + repoFolder.getCanonicalPath()); + } else { + git.addFiles(filesToAdd); + sender.sendMessage("§aStaged specific files in: §f" + repoFolder.getCanonicalPath()); + filesToAdd.forEach(f -> sender.sendMessage("§7- §f" + f)); + } + } catch (Exception e) { + sender.sendMessage("§cGit add failed: " + e.getMessage()); + e.printStackTrace(); + } + }); + } + +} diff --git a/app/src/main/java/org/yuemi/commands/subcommands/GitCommitSubcommand.java b/app/src/main/java/org/yuemi/commands/subcommands/GitCommitSubcommand.java new file mode 100644 index 0000000..19a917c --- /dev/null +++ b/app/src/main/java/org/yuemi/commands/subcommands/GitCommitSubcommand.java @@ -0,0 +1,42 @@ +package org.yuemi.commands.subcommands; + +import org.yuemi.commands.SubcommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.java.JavaPlugin; +import org.yuemi.git.GitManager; + +import java.io.File; + +public class GitCommitSubcommand implements SubcommandExecutor { + + private final JavaPlugin plugin; + + public GitCommitSubcommand(JavaPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void execute(CommandSender sender, String[] args) { + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { + File repoFolder = new File("."); + String message = "Commit from Minecraft"; + + for (String arg : args) { + if (arg.startsWith("--path=")) { + repoFolder = new File(arg.substring("--path=".length())); + } else if (arg.startsWith("--message=") || arg.startsWith("-m=")) { + message = arg.contains("=") ? arg.split("=", 2)[1] : message; + } + } + + try { + GitManager git = new GitManager(repoFolder); + git.commit(message); + sender.sendMessage("§aCommitted: §f" + message); + } catch (Exception e) { + sender.sendMessage("§cGit commit failed: " + e.getMessage()); + e.printStackTrace(); + } + }); + } +} diff --git a/app/src/main/java/org/yuemi/commands/subcommands/GitFetchSubcommand.java b/app/src/main/java/org/yuemi/commands/subcommands/GitFetchSubcommand.java new file mode 100644 index 0000000..1023a82 --- /dev/null +++ b/app/src/main/java/org/yuemi/commands/subcommands/GitFetchSubcommand.java @@ -0,0 +1,50 @@ +package org.yuemi.commands.subcommands; + +import org.yuemi.commands.SubcommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.java.JavaPlugin; +import org.yuemi.git.GitManager; + +import java.io.File; + +public class GitFetchSubcommand implements SubcommandExecutor { + + private final JavaPlugin plugin; + + public GitFetchSubcommand(JavaPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void execute(CommandSender sender, String[] args) { + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { + File repoFolder = new File("."); + String username = null; + String token = null; + + for (String arg : args) { + if (arg.startsWith("--path=")) { + repoFolder = new File(arg.substring("--path=".length())); + } else if (arg.startsWith("--username=")) { + username = arg.substring("--username=".length()); + } else if (arg.startsWith("--token=")) { + token = arg.substring("--token=".length()); + } + } + + if (username == null || token == null) { + sender.sendMessage("§cUsage: /git fetch --username=... --token=..."); + return; + } + + try { + GitManager git = new GitManager(repoFolder); + git.fetch(username, token); + sender.sendMessage("§aFetched remote updates."); + } catch (Exception e) { + sender.sendMessage("§cGit fetch failed: " + e.getMessage()); + e.printStackTrace(); + } + }); + } +} diff --git a/app/src/main/java/org/yuemi/commands/subcommands/GitHelpSubcommand.java b/app/src/main/java/org/yuemi/commands/subcommands/GitHelpSubcommand.java new file mode 100644 index 0000000..5934bbc --- /dev/null +++ b/app/src/main/java/org/yuemi/commands/subcommands/GitHelpSubcommand.java @@ -0,0 +1,30 @@ +package org.yuemi.commands.subcommands; + +import org.yuemi.commands.SubcommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.java.JavaPlugin; +import org.yuemi.commands.SubcommandExecutor; + +public class GitHelpSubcommand implements SubcommandExecutor { + + private final JavaPlugin plugin; + + public GitHelpSubcommand(JavaPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void execute(CommandSender sender, String[] args) { + sender.sendMessage("§2==== GitCraft Command Help ===="); + sender.sendMessage("§a/git init §7--path= §8→ Initialize repo in folder"); + sender.sendMessage("§a/git remote --add|--set-url|--remove --url= §7[--path=dir]"); + sender.sendMessage("§a/git add [file1 file2 ...] §7or §a/git add . §7[--path=dir]"); + sender.sendMessage("§a/git reset [--hard|file] §7[--path=dir]"); + sender.sendMessage("§a/git commit -m= §7[--path=dir]"); + sender.sendMessage("§a/git status §7[--path=dir]"); + sender.sendMessage("§a/git fetch --username= --token= §7[--path=dir]"); + sender.sendMessage("§a/git pull --username= --token= §7[--path=dir]"); + sender.sendMessage("§a/git push --username= --token= §7[--path=dir]"); + sender.sendMessage("§a/git help §8→ Shows this message"); + } +} diff --git a/app/src/main/java/org/yuemi/commands/subcommands/GitInitSubcommand.java b/app/src/main/java/org/yuemi/commands/subcommands/GitInitSubcommand.java new file mode 100644 index 0000000..1d4aadf --- /dev/null +++ b/app/src/main/java/org/yuemi/commands/subcommands/GitInitSubcommand.java @@ -0,0 +1,38 @@ +package org.yuemi.commands.subcommands; + +import org.yuemi.commands.SubcommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.java.JavaPlugin; +import org.yuemi.git.GitManager; + +import java.io.File; + +public class GitInitSubcommand implements SubcommandExecutor { + + private final JavaPlugin plugin; + + public GitInitSubcommand(JavaPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void execute(CommandSender sender, String[] args) { + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { + File repoFolder = new File("."); + for (String arg : args) { + if (arg.startsWith("--path=")) { + repoFolder = new File(arg.substring("--path=".length())); + } + } + + try { + GitManager git = new GitManager(repoFolder); + git.initRepo(plugin); + sender.sendMessage("§aInitialized Git repository at: §f" + repoFolder.getAbsolutePath()); + } catch (Exception e) { + sender.sendMessage("§cGit init failed: " + e.getMessage()); + e.printStackTrace(); + } + }); + } +} diff --git a/app/src/main/java/org/yuemi/commands/subcommands/GitPullSubcommand.java b/app/src/main/java/org/yuemi/commands/subcommands/GitPullSubcommand.java new file mode 100644 index 0000000..1488c75 --- /dev/null +++ b/app/src/main/java/org/yuemi/commands/subcommands/GitPullSubcommand.java @@ -0,0 +1,50 @@ +package org.yuemi.commands.subcommands; + +import org.yuemi.commands.SubcommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.java.JavaPlugin; +import org.yuemi.git.GitManager; + +import java.io.File; + +public class GitPullSubcommand implements SubcommandExecutor { + + private final JavaPlugin plugin; + + public GitPullSubcommand(JavaPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void execute(CommandSender sender, String[] args) { + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { + File repoFolder = new File("."); + String username = null; + String token = null; + + for (String arg : args) { + if (arg.startsWith("--path=")) { + repoFolder = new File(arg.substring("--path=".length())); + } else if (arg.startsWith("--username=")) { + username = arg.substring("--username=".length()); + } else if (arg.startsWith("--token=")) { + token = arg.substring("--token=".length()); + } + } + + if (username == null || token == null) { + sender.sendMessage("§cUsage: /git pull --username=... --token=..."); + return; + } + + try { + GitManager git = new GitManager(repoFolder); + git.pull(username, token); + sender.sendMessage("§aPulled and merged from origin."); + } catch (Exception e) { + sender.sendMessage("§cGit pull failed: " + e.getMessage()); + e.printStackTrace(); + } + }); + } +} diff --git a/app/src/main/java/org/yuemi/commands/subcommands/GitPushSubcommand.java b/app/src/main/java/org/yuemi/commands/subcommands/GitPushSubcommand.java new file mode 100644 index 0000000..8154399 --- /dev/null +++ b/app/src/main/java/org/yuemi/commands/subcommands/GitPushSubcommand.java @@ -0,0 +1,50 @@ +package org.yuemi.commands.subcommands; + +import org.yuemi.commands.SubcommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.java.JavaPlugin; +import org.yuemi.git.GitManager; + +import java.io.File; + +public class GitPushSubcommand implements SubcommandExecutor { + + private final JavaPlugin plugin; + + public GitPushSubcommand(JavaPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void execute(CommandSender sender, String[] args) { + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { + File repoFolder = new File("."); + String username = null; + String token = null; + + for (String arg : args) { + if (arg.startsWith("--path=")) { + repoFolder = new File(arg.substring("--path=".length())); + } else if (arg.startsWith("--username=")) { + username = arg.substring("--username=".length()); + } else if (arg.startsWith("--token=")) { + token = arg.substring("--token=".length()); + } + } + + if (username == null || token == null) { + sender.sendMessage("§cUsage: /git push --username=... --token=..."); + return; + } + + try { + GitManager git = new GitManager(repoFolder); + git.push(username, token); + sender.sendMessage("§aPushed to remote."); + } catch (Exception e) { + sender.sendMessage("§cGit push failed: " + e.getMessage()); + e.printStackTrace(); + } + }); + } +} diff --git a/app/src/main/java/org/yuemi/commands/subcommands/GitRemoteSubcommand.java b/app/src/main/java/org/yuemi/commands/subcommands/GitRemoteSubcommand.java new file mode 100644 index 0000000..a00ca50 --- /dev/null +++ b/app/src/main/java/org/yuemi/commands/subcommands/GitRemoteSubcommand.java @@ -0,0 +1,65 @@ +package org.yuemi.commands.subcommands; + +import org.yuemi.commands.SubcommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.java.JavaPlugin; +import org.yuemi.git.GitManager; + +import java.io.File; + +public class GitRemoteSubcommand implements SubcommandExecutor { + + private final JavaPlugin plugin; + + public GitRemoteSubcommand(JavaPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void execute(CommandSender sender, String[] args) { + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { + File repoFolder = new File("."); + String url = null; + String mode = "add"; + + for (String arg : args) { + if (arg.startsWith("--path=")) { + repoFolder = new File(arg.substring("--path=".length())); + } else if (arg.startsWith("--url=")) { + url = arg.substring("--url=".length()); + } else if (arg.equalsIgnoreCase("--add")) { + mode = "add"; + } else if (arg.equalsIgnoreCase("--set-url")) { + mode = "set"; + } else if (arg.equalsIgnoreCase("--remove")) { + mode = "remove"; + } + } + + try { + GitManager git = new GitManager(repoFolder); + + switch (mode) { + case "add": + if (url == null) throw new IllegalArgumentException("Missing --url"); + git.addRemote(url); + sender.sendMessage("§aAdded remote origin: " + url); + break; + case "set": + if (url == null) throw new IllegalArgumentException("Missing --url"); + git.setRemoteUrl(url); + sender.sendMessage("§aUpdated remote origin URL to: " + url); + break; + case "remove": + git.removeRemote(); + sender.sendMessage("§aRemoved remote origin."); + break; + } + + } catch (Exception e) { + sender.sendMessage("§cGit remote failed: " + e.getMessage()); + e.printStackTrace(); + } + }); + } +} diff --git a/app/src/main/java/org/yuemi/commands/subcommands/GitResetSubcommand.java b/app/src/main/java/org/yuemi/commands/subcommands/GitResetSubcommand.java new file mode 100644 index 0000000..f5b50c5 --- /dev/null +++ b/app/src/main/java/org/yuemi/commands/subcommands/GitResetSubcommand.java @@ -0,0 +1,55 @@ +package org.yuemi.commands.subcommands; + +import org.yuemi.commands.SubcommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.java.JavaPlugin; +import org.yuemi.git.GitManager; +import org.eclipse.jgit.api.ResetCommand.ResetType; + +import java.io.File; + +public class GitResetSubcommand implements SubcommandExecutor { + + private final JavaPlugin plugin; + + public GitResetSubcommand(JavaPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void execute(CommandSender sender, String[] args) { + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { + File repoFolder = new File("."); // Default path + ResetType resetType = ResetType.MIXED; // default is soft reset (unstage) + + if (args.length >= 1 && args[0].startsWith("--path=")) { + String path = args[0].substring("--path=".length()); + repoFolder = new File(path); + } + + try { + GitManager git = new GitManager(repoFolder); + + if (args.length >= 1 && args[0].equalsIgnoreCase("--hard")) { + resetType = ResetType.HARD; + git.reset(resetType); + sender.sendMessage("§cHard reset performed."); + return; + } + + if (args.length >= 1 && !args[0].startsWith("--")) { + String file = args[0]; + git.resetFile(file); + sender.sendMessage("§aUnstaged file: §f" + file); + return; + } + + git.reset(resetType); + sender.sendMessage("§aReset staged changes."); + } catch (Exception e) { + sender.sendMessage("§cGit reset failed: " + e.getMessage()); + e.printStackTrace(); + } + }); + } +} diff --git a/app/src/main/java/org/yuemi/commands/subcommands/GitStatusSubcommand.java b/app/src/main/java/org/yuemi/commands/subcommands/GitStatusSubcommand.java new file mode 100644 index 0000000..4a776aa --- /dev/null +++ b/app/src/main/java/org/yuemi/commands/subcommands/GitStatusSubcommand.java @@ -0,0 +1,68 @@ +package org.yuemi.commands.subcommands; + +import org.yuemi.commands.SubcommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.yuemi.git.GitManager; +import org.eclipse.jgit.api.Status; + +import java.io.File; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class GitStatusSubcommand implements SubcommandExecutor { + + private final JavaPlugin plugin; + + public GitStatusSubcommand(JavaPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void execute(CommandSender sender, String[] args) { + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { + File repoFolder = new File("."); + + for (String arg : args) { + if (arg.startsWith("--path=")) { + repoFolder = new File(arg.substring("--path=".length())); + } + } + + try { + GitManager git = new GitManager(repoFolder); + Status status = git.getStatus(); + + Stream changes = Stream.concat( + status.getUncommittedChanges().stream().map(f -> "Uncommitted: " + f), + Stream.concat( + status.getUntracked().stream().map(f -> "Untracked: " + f), + status.getModified().stream().map(f -> "Modified: " + f) + ) + ); + + List messages = changes.collect(Collectors.toList()); + + if (messages.isEmpty()) { + sender.sendMessage("§aClean working directory."); + return; + } + + if (sender instanceof Player) { + messages.stream().limit(10).forEach(msg -> sender.sendMessage("§e" + msg)); + if (messages.size() > 10) { + sender.sendMessage("§7... and " + (messages.size() - 10) + " more."); + } + } else { + messages.forEach(msg -> sender.sendMessage("[GitStatus] " + msg)); + } + + } catch (Exception e) { + sender.sendMessage("§cGit status failed: " + e.getMessage()); + e.printStackTrace(); + } + }); + } +} diff --git a/app/src/main/java/org/yuemi/git/GitManager.java b/app/src/main/java/org/yuemi/git/GitManager.java new file mode 100644 index 0000000..d9b0782 --- /dev/null +++ b/app/src/main/java/org/yuemi/git/GitManager.java @@ -0,0 +1,146 @@ +package org.yuemi.git; + +import java.util.List; +import java.util.ArrayList; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; +import org.eclipse.jgit.api.ResetCommand.ResetType; +import org.eclipse.jgit.api.Status; +import org.eclipse.jgit.api.AddCommand; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.File; + +public class GitManager { + + private final File repoDir; + private Git git; + + public GitManager(File repoDir) { + this.repoDir = repoDir; + } + + private Git getOrOpenGit() throws Exception { + if (git == null) { + git = Git.open(repoDir); + } + return git; + } + + public boolean isCloned() { + return new File(repoDir, ".git").exists(); + } + + public void cloneRepo(String url) throws Exception { + this.git = Git.cloneRepository() + .setURI(url) + .setDirectory(repoDir) + .call(); + } + + public void addAll() throws Exception { + getOrOpenGit().add().addFilepattern(".").call(); + } + + public void addFiles(List files) throws Exception { + AddCommand add = getOrOpenGit().add(); + for (String file : files) { + add.addFilepattern(file); + } + add.call(); + } + + public void commit(String message) throws Exception { + getOrOpenGit() + .commit() + .setMessage(message) + .setAuthor("Minecraft", "mc@localhost") + .call(); + } + + public void push(String username, String token) throws Exception { + getOrOpenGit() + .push() + .setCredentialsProvider(new UsernamePasswordCredentialsProvider(username, token)) + .call(); + } + + public void checkout(String branch) throws Exception { + getOrOpenGit() + .checkout() + .setName(branch) + .call(); + } + + public void close() { + if (git != null) { + git.close(); + } + } + + public void reset(ResetType type) throws Exception { + getOrOpenGit().reset().setMode(type).call(); + } + + public void resetFile(String filePath) throws Exception { + getOrOpenGit().reset().addPath(filePath).call(); + } + + public void initRepo(JavaPlugin plugin) throws Exception { + if (git == null) { + git = Git.init().setDirectory(repoDir).call(); + } + + File gitignore = new File(repoDir, ".gitignore"); + if (!gitignore.exists()) { + try (InputStream in = plugin.getResource("gitignore.txt")) { + if (in != null) { + Files.copy(in, gitignore.toPath(), StandardCopyOption.REPLACE_EXISTING); + } + } + } + } + + + public void addRemote(String url) throws Exception { + getOrOpenGit().remoteAdd() + .setName("origin") + .setUri(new org.eclipse.jgit.transport.URIish(url)) + .call(); + } + + public void setRemoteUrl(String url) throws Exception { + getOrOpenGit().remoteSetUrl() + .setRemoteName("origin") + .setRemoteUri(new org.eclipse.jgit.transport.URIish(url)) + .call(); + } + + public void removeRemote() throws Exception { + getOrOpenGit().remoteRemove() + .setRemoteName("origin") + .call(); + } + + public void fetch(String username, String token) throws Exception { + getOrOpenGit() + .fetch() + .setCredentialsProvider(new UsernamePasswordCredentialsProvider(username, token)) + .call(); + } + + public void pull(String username, String token) throws Exception { + getOrOpenGit() + .pull() + .setCredentialsProvider(new UsernamePasswordCredentialsProvider(username, token)) + .call(); + } + + public Status getStatus() throws Exception { + return getOrOpenGit().status().call(); + } + +} diff --git a/app/src/main/resources/gitignore.txt b/app/src/main/resources/gitignore.txt new file mode 100644 index 0000000..a411fd7 --- /dev/null +++ b/app/src/main/resources/gitignore.txt @@ -0,0 +1,14 @@ +# Minecraft plugin defaults +logs/ +*.log +*.tmp +*.lock +*.bak +*.swp +cache/ +debug/ +.idea/ +*.iml +*.class +target/ +build/ diff --git a/app/src/main/resources/plugin.yml b/app/src/main/resources/plugin.yml index 8613261..0491cb8 100644 --- a/app/src/main/resources/plugin.yml +++ b/app/src/main/resources/plugin.yml @@ -5,9 +5,6 @@ authors: version: 1.0 api-version: 1.21 commands: - gitclone: - description: Clones a Git repository - gitcommit: - description: Commits all changes - gitpush: - description: Pushes to remote + git: + description: Git subcommand dispatcher + usage: /git