若是你也有一個老舊的Java Web應用,由於各類緣由,代碼庫中的代碼是不完整的,因此每次上線只能增量部署,或者研發規範裏就要求增量部署,在這種狀況下如何實現自動化的編譯和部署呢?下面給出一個可行的方案:java
一、部署前,將須要部署的代碼合併到deliver分支git
二、比較deliver分支和master分支的差別,獲得差別列表以後,用於後續的編譯maven
三、編譯差別文件時,須要將應用所依賴的jar,已經部署的class文件等加入到CLASSPATHide
四、若是各測試環境也使用這一套自動部署的方案,可能還須要考慮剝離環境相關的配置到配置文件中,並根據環境分目錄存放,具體能夠參考maven的profile機制測試
核心代碼(代碼結構請自行優化 :D):fetch
一、比較兩個分支的差別(忽略whitespace帶來的差別):優化
try (Git git = Git.open(gitRepoFile); ByteArrayOutputStream out = new ByteArrayOutputStream(); DiffFormatter df = new DiffFormatter(out);) { Repository repository = git.getRepository(); ObjectReader reader = repository.newObjectReader(); String branchName = repository.getBranch(); ObjectId masterId = repository.resolve("remotes/origin/master^{tree}"); ObjectId branchId = repository.resolve(branchName + "^{tree}"); CanonicalTreeParser masterTreeParser = new CanonicalTreeParser(); masterTreeParser.reset(reader, masterId); CanonicalTreeParser branchTreeParser = new CanonicalTreeParser(); branchTreeParser.reset(reader, branchId); List<DiffEntry> diffs = git.diff() .setNewTree(branchTreeParser) .setOldTree(masterTreeParser) .call(); Map<String, List<String>> diffFileMap = new HashMap<>(); List<String> changeFileList = new ArrayList<>(); List<String> deleteFileList = new ArrayList<>(); df.setDiffComparator(RawTextComparator.WS_IGNORE_ALL); df.setRepository(git.getRepository()); for (DiffEntry diffEntry : diffs) { df.format(diffEntry); FileHeader fileHeader = df.toFileHeader(diffEntry); @SuppressWarnings("unchecked") List<HunkHeader> hunks = (List<HunkHeader>) fileHeader.getHunks(); int changedSize = 0; for (HunkHeader hunkHeader : hunks) { EditList editList = hunkHeader.toEditList(); for (Edit edit : editList) { changedSize += edit.getLengthA() + edit.getLengthB(); } } if (changedSize > 0) { ChangeType changeType = diffEntry.getChangeType(); if (ChangeType.DELETE.equals(changeType)) { String oldFilePath = diffEntry.getOldPath(); log.info("{}|{}", changeType.name(), oldFilePath); deleteFileList.add(oldFilePath); } else { String newFilePath = diffEntry.getNewPath(); log.info("{}|{}", changeType.name(), newFilePath); changeFileList.add(newFilePath); } } } diffFileMap.put("change", changeFileList); diffFileMap.put("delete", deleteFileList); return diffFileMap; }
二、編譯:ui
Iterable<String> options = Arrays.asList( "-classpath", classpath, "-encoding", encoding, "-source", jdkVersion, "-target", jdkVersion, "-d", targetPath); JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); log.info("classpath:{}", classpath); log.info("targetPath:{}", targetPath); try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);) { Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(fileList); DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>(); CompilationTask compilationTask = compiler .getTask(null, fileManager, diagnostics, options, null, compilationUnits); if (!compilationTask.call()) { log.error("JavaCompiler Build failed:"); for (Diagnostic<?> diagnostic : diagnostics.getDiagnostics()) { long line = diagnostic.getLineNumber(); String source = diagnostic.getSource() != null ? diagnostic.getSource().toString() : ""; String kind = diagnostic.getKind().name(); String message = diagnostic.getMessage(null); log.info("{} on line:{} in {}.", kind, line, source); log.info("message:{}", message); } return false; } }
要實現完整的功能,還須要根據應用的具體狀況完善,好比:從運行環境同步刪除代碼庫中刪除的文件;從代碼庫拉取文件時,用fetch,reset的方式;還能夠藉助Marathon、Mesos、Docker運行應用等。spa