/** * There are two things we need to check * * <ul> * <li>files created or modified since last build time, we only need to check the source folder * <li>file deleted since last build time, we have to compare source and destination folder * </ul> */ @Override public boolean pollChanges( AbstractProject project, Launcher launcher, FilePath workspace, TaskListener listener) throws IOException, InterruptedException { long start = System.currentTimeMillis(); PrintStream log = launcher.getListener().getLogger(); log.println("FSSCM.pollChange: " + path); AllowDeleteList allowDeleteList = new AllowDeleteList(project.getRootDir()); // we will only delete a file if it is listed in the allowDeleteList // ie. we will only delete a file if it is copied by us if (allowDeleteList.fileExists()) { allowDeleteList.load(); } else { // watch list save file doesn't exist // we will assuem all existing files are under watch // ie. everything can be deleted Set<String> existingFiles = workspace.act(new RemoteListDir()); allowDeleteList.setList(existingFiles); } RemoteFolderDiff.PollChange callable = new RemoteFolderDiff.PollChange(); setupRemoteFolderDiff(callable, project, allowDeleteList.getList()); boolean changed = workspace.act(callable); String str = callable.getLog(); if (str.length() > 0) log.println(str); log.println("FSSCM.pollChange return " + changed); log.println( "FSSCM.poolChange completed in " + formatDurration(System.currentTimeMillis() - start)); return changed; }
@Override public boolean checkout( AbstractBuild build, Launcher launcher, FilePath workspace, BuildListener listener, File changelogFile) throws IOException, InterruptedException { long start = System.currentTimeMillis(); PrintStream log = launcher.getListener().getLogger(); log.println("FSSCM.checkout " + path + " to " + workspace); Boolean b = Boolean.TRUE; AllowDeleteList allowDeleteList = new AllowDeleteList(build.getProject().getRootDir()); if (clearWorkspace) { log.println("FSSCM.clearWorkspace..."); workspace.deleteRecursive(); } // we will only delete a file if it is listed in the allowDeleteList // ie. we will only delete a file if it is copied by us if (allowDeleteList.fileExists()) { allowDeleteList.load(); } else { // watch list save file doesn't exist // we will assuem all existing files are under watch // ie. everything can be deleted Set<String> existingFiles = workspace.act(new RemoteListDir()); allowDeleteList.setList(existingFiles); } RemoteFolderDiff.CheckOut callable = new RemoteFolderDiff.CheckOut(); setupRemoteFolderDiff(callable, build.getProject(), allowDeleteList.getList()); List<FolderDiff.Entry> list = workspace.act(callable); // maintain the watch list for (FolderDiff.Entry entry : list) { if (FolderDiff.Entry.Type.DELETED.equals(entry.getType())) { allowDeleteList.remove(entry.getFilename()); } else { // added or modified allowDeleteList.add(entry.getFilename()); } } allowDeleteList.save(); // raw log String str = callable.getLog(); if (str.length() > 0) log.println(str); ChangelogSet.XMLSerializer handler = new ChangelogSet.XMLSerializer(); ChangelogSet changeLogSet = new ChangelogSet(build, list); handler.save(changeLogSet, changelogFile); log.println("FSSCM.check completed in " + formatDurration(System.currentTimeMillis() - start)); return b; }
@Override public void perform(Run<?, ?> build, FilePath ws, Launcher launcher, TaskListener listener) throws InterruptedException { if (artifacts.length() == 0) { listener.error(Messages.ArtifactArchiver_NoIncludes()); build.setResult(Result.FAILURE); return; } if (onlyIfSuccessful && build.getResult() != null && build.getResult().isWorseThan(Result.UNSTABLE)) { listener.getLogger().println(Messages.ArtifactArchiver_SkipBecauseOnlyIfSuccessful()); return; } listener.getLogger().println(Messages.ArtifactArchiver_ARCHIVING_ARTIFACTS()); try { String artifacts = build.getEnvironment(listener).expand(this.artifacts); Map<String, String> files = ws.act(new ListFiles(artifacts, excludes, defaultExcludes, caseSensitive)); if (!files.isEmpty()) { build .pickArtifactManager() .archive(ws, launcher, BuildListenerAdapter.wrap(listener), files); if (fingerprint) { new Fingerprinter(artifacts).perform(build, ws, launcher, listener); } } else { Result result = build.getResult(); if (result != null && result.isBetterOrEqualTo(Result.UNSTABLE)) { // If the build failed, don't complain that there was no matching artifact. // The build probably didn't even get to the point where it produces artifacts. listenerWarnOrError(listener, Messages.ArtifactArchiver_NoMatchFound(artifacts)); String msg = null; try { msg = ws.validateAntFileMask( artifacts, FilePath.VALIDATE_ANT_FILE_MASK_BOUND, caseSensitive); } catch (Exception e) { listenerWarnOrError(listener, e.getMessage()); } if (msg != null) listenerWarnOrError(listener, msg); } if (!allowEmptyArchive) { build.setResult(Result.FAILURE); } return; } } catch (IOException e) { Util.displayIOException(e, listener); e.printStackTrace(listener.error(Messages.ArtifactArchiver_FailedToArchive(artifacts))); build.setResult(Result.FAILURE); return; } }
/** * Start from scratch and clone the whole repository. Cloning into an existing directory is not * allowed, so the workspace is first deleted entirely, then <tt>git clone</tt> is performed. * * @param remoteConfig remote config * @throws GitException if deleting or cloning the workspace fails */ public void clone(final RemoteConfig remoteConfig) throws GitException { listener.getLogger().println("Cloning repository " + remoteConfig.getName()); final int[] gitVer = getGitVersion(); // TODO: Not here! try { workspace.deleteRecursive(); } catch (Exception e) { e.printStackTrace(listener.error("Failed to clean the workspace")); throw new GitException("Failed to delete workspace", e); } // Assume only 1 URL for this repository final String source = remoteConfig.getURIs().get(0).toPrivateString(); try { workspace.act( new FileCallable<String>() { private static final long serialVersionUID = 1L; public String invoke(File workspace, VirtualChannel channel) throws IOException { final ArgumentListBuilder args = new ArgumentListBuilder(); args.add("clone"); if ((gitVer[0] >= 1) && (gitVer[1] >= 7)) { args.add("--progress"); } if (reference != null) { File referencePath = new File(reference); if (referencePath.exists() && referencePath.isDirectory()) { args.add("--reference", reference); } } args.add("-o", remoteConfig.getName()); args.add(source); args.add(workspace.getAbsolutePath()); return launchCommandIn(args, null); } }); } catch (Exception e) { throw new GitException("Could not clone " + source, e); } }
public void labelBuild(TaskListener listener, String name, String description) throws Exception { // Expand label name and description name = expand.format(name, false); description = expand.format(description, false); TaggingTask task = new TaggingTask(name, description); task.setListener(listener); task.setCredential(credential); task.setWorkspace(workspace); task.setBuildChange(buildChange); // Invoke the Label Task FilePath buildWorkspace = build.getWorkspace(); buildWorkspace.act(task); // save label if (!tags.contains(name)) { tags.add(name); getRun().save(); } }
@Override public void perform( Run<?, ?> run, FilePath buildWorkspace, Launcher launcher, TaskListener listener) throws InterruptedException, IOException { TagAction tagAction = (TagAction) run.getAction(TagAction.class); String credential = tagAction.getCredential(); Workspace workspace = tagAction.getWorkspace(); String client = tagAction.getClient(); // Setup Unshelve Task RemoveClientTask task = new RemoveClientTask(client); task.setListener(listener); task.setCredential(credential); // Set workspace used for the Task Workspace ws = task.setEnvironment(run, workspace, buildWorkspace); task.setWorkspace(ws); buildWorkspace.act(task); }
/** * Downloads and extracts the basic Android SDK on a given Node, if it hasn't already been done. * * @param node Node to install the SDK on. * @return Path where the SDK is installed, regardless of whether it was installed right now. * @throws SdkUnavailableException If the Android SDK is not available on this platform. */ private static FilePath installBasicSdk(final BuildListener listener, Node node) throws SdkUnavailableException, IOException, InterruptedException { // Locate where the SDK should be installed to on this node final FilePath installDir = Utils.getSdkInstallDirectory(node); // Get the OS-specific download URL for the SDK AndroidInstaller installer = AndroidInstaller.fromNode(node); final URL downloadUrl = installer.getUrl(SDK_VERSION); // Download the SDK, if required boolean wasNowInstalled = installDir.act( new FileCallable<Boolean>() { public Boolean invoke(File f, VirtualChannel channel) throws InterruptedException, IOException { String msg = Messages.DOWNLOADING_SDK_FROM(downloadUrl); return installDir.installIfNecessaryFrom(downloadUrl, listener, msg); } private static final long serialVersionUID = 1L; }); if (wasNowInstalled) { // If the SDK was required, pull files up from the intermediate directory installDir.listDirectories().get(0).moveAllChildrenTo(installDir); // Java's ZipEntry doesn't preserve the executable bit... if (installer == AndroidInstaller.MAC_OS_X) { setPermissions(installDir.child("tools")); } // Success! log(listener.getLogger(), Messages.BASE_SDK_INSTALLED()); } return installDir; }
@Override public boolean checkout( final AbstractBuild build, Launcher launcher, final FilePath workspace, final BuildListener listener, File changelogFile) throws IOException, InterruptedException { listener .getLogger() .println( "Checkout:" + workspace.getName() + " / " + workspace.getRemote() + " - " + workspace.getChannel()); final String projectName = build.getProject().getName(); final int buildNumber = build.getNumber(); final String gitExe = getDescriptor().getGitExe(); final String buildnumber = "hudson-" + projectName + "-" + buildNumber; final BuildData buildData = getBuildData(build.getPreviousBuild(), true); if (buildData != null && buildData.lastBuild != null) { listener.getLogger().println("Last Built Revision: " + buildData.lastBuild.revision); } EnvVars tmp = new EnvVars(); try { tmp = build.getEnvironment(listener); } catch (InterruptedException e) { listener.error("Interrupted exception getting environment .. using empty environment"); } final EnvVars environment = tmp; final String singleBranch = getSingleBranch(build); final Revision revToBuild = workspace.act( new FileCallable<Revision>() { private static final long serialVersionUID = 1L; public Revision invoke(File localWorkspace, VirtualChannel channel) throws IOException { FilePath ws = new FilePath(localWorkspace); listener .getLogger() .println( "Checkout:" + ws.getName() + " / " + ws.getRemote() + " - " + ws.getChannel()); IGitAPI git = new GitAPI(gitExe, ws, listener, environment); if (git.hasGitRepo()) { // It's an update listener.getLogger().println("Fetching changes from the remote Git repository"); for (RemoteConfig remoteRepository : getRepositories()) { fetchFrom(git, localWorkspace, listener, remoteRepository); } } else { listener.getLogger().println("Cloning the remote Git repository"); // Go through the repositories, trying to clone from one // boolean successfullyCloned = false; for (RemoteConfig rc : remoteRepositories) { try { git.clone(rc); successfullyCloned = true; break; } catch (GitException ex) { listener.error( "Error cloning remote repo '%s' : %s", rc.getName(), ex.getMessage()); if (ex.getCause() != null) { listener.error("Cause: %s", ex.getCause().getMessage()); } // Failed. Try the next one listener.getLogger().println("Trying next repository"); } } if (!successfullyCloned) { listener.error("Could not clone from a repository"); throw new GitException("Could not clone"); } // Also do a fetch for (RemoteConfig remoteRepository : getRepositories()) { fetchFrom(git, localWorkspace, listener, remoteRepository); } if (git.hasGitModules()) { git.submoduleInit(); git.submoduleUpdate(); } } IBuildChooser buildChooser = new BuildChooser(GitSCM.this, git, new GitUtils(listener, git), buildData); Collection<Revision> candidates = buildChooser.getCandidateRevisions(false, singleBranch); if (candidates.size() == 0) return null; return candidates.iterator().next(); } }); if (revToBuild == null) { // getBuildCandidates should make the last item the last build, so a re-build // will build the last built thing. listener.error("Nothing to do"); return false; } listener.getLogger().println("Commencing build of " + revToBuild); Object[] returnData; // Changelog, BuildData if (mergeOptions.doMerge()) { if (!revToBuild.containsBranchName(mergeOptions.getMergeTarget())) { returnData = workspace.act( new FileCallable<Object[]>() { private static final long serialVersionUID = 1L; public Object[] invoke(File localWorkspace, VirtualChannel channel) throws IOException { EnvVars environment; try { environment = build.getEnvironment(listener); } catch (Exception e) { listener.error("Exception reading environment - using empty environment"); environment = new EnvVars(); } IGitAPI git = new GitAPI(gitExe, new FilePath(localWorkspace), listener, environment); IBuildChooser buildChooser = new BuildChooser(GitSCM.this, git, new GitUtils(listener, git), buildData); // Do we need to merge this revision onto MergeTarget // Only merge if there's a branch to merge that isn't // us.. listener .getLogger() .println( "Merging " + revToBuild + " onto " + mergeOptions.getMergeTarget()); // checkout origin/blah ObjectId target = git.revParse(mergeOptions.getMergeTarget()); git.checkout(target.name()); try { git.merge(revToBuild.getSha1().name()); } catch (Exception ex) { listener .getLogger() .println( "Branch not suitable for integration as it does not merge cleanly"); // We still need to tag something to prevent // repetitive builds from happening - tag the // candidate // branch. git.checkout(revToBuild.getSha1().name()); git.tag(buildnumber, "Hudson Build #" + buildNumber); buildChooser.revisionBuilt(revToBuild, buildNumber, Result.FAILURE); return new Object[] {null, buildChooser.getData()}; } if (git.hasGitModules()) { git.submoduleUpdate(); } // Tag the successful merge git.tag(buildnumber, "Hudson Build #" + buildNumber); StringBuilder changeLog = new StringBuilder(); if (revToBuild.getBranches().size() > 0) listener .getLogger() .println("Warning : There are multiple branch changesets here"); try { for (Branch b : revToBuild.getBranches()) { Build lastRevWas = buildData == null ? null : buildData.getLastBuildOfBranch(b.getName()); if (lastRevWas != null) { changeLog.append( putChangelogDiffsIntoFile( git, b.name, lastRevWas.getSHA1().name(), revToBuild.getSha1().name())); } } } catch (GitException ge) { changeLog.append("Unable to retrieve changeset"); } Build buildData = buildChooser.revisionBuilt(revToBuild, buildNumber, null); GitUtils gu = new GitUtils(listener, git); buildData.mergeRevision = gu.getRevisionForSHA1(target); // Fetch the diffs into the changelog file return new Object[] {changeLog, buildChooser.getData()}; } }); BuildData returningBuildData = (BuildData) returnData[1]; build.addAction(returningBuildData); return changeLogResult((String) returnData[0], changelogFile); } } // No merge returnData = workspace.act( new FileCallable<Object[]>() { private static final long serialVersionUID = 1L; public Object[] invoke(File localWorkspace, VirtualChannel channel) throws IOException { IGitAPI git = new GitAPI(gitExe, new FilePath(localWorkspace), listener, environment); IBuildChooser buildChooser = new BuildChooser(GitSCM.this, git, new GitUtils(listener, git), buildData); // Straight compile-the-branch listener.getLogger().println("Checking out " + revToBuild); git.checkout(revToBuild.getSha1().name()); // if( compileSubmoduleCompares ) if (doGenerateSubmoduleConfigurations) { SubmoduleCombinator combinator = new SubmoduleCombinator(git, listener, localWorkspace, submoduleCfg); combinator.createSubmoduleCombinations(); } if (git.hasGitModules()) { git.submoduleInit(); // Git submodule update will only 'fetch' from where it // regards as 'origin'. However, // it is possible that we are building from a // RemoteRepository with changes // that are not in 'origin' AND it may be a new module that // we've only just discovered. // So - try updating from all RRs, then use the submodule // Update to do the checkout for (RemoteConfig remoteRepository : getRepositories()) { fetchFrom(git, localWorkspace, listener, remoteRepository); } // Update to the correct checkout git.submoduleUpdate(); } // Tag the successful merge git.tag(buildnumber, "Hudson Build #" + buildNumber); StringBuilder changeLog = new StringBuilder(); int histories = 0; try { for (Branch b : revToBuild.getBranches()) { Build lastRevWas = buildData == null ? null : buildData.getLastBuildOfBranch(b.getName()); if (lastRevWas != null) { listener.getLogger().println("Recording changes in branch " + b.getName()); changeLog.append( putChangelogDiffsIntoFile( git, b.name, lastRevWas.getSHA1().name(), revToBuild.getSha1().name())); histories++; } else { listener.getLogger().println("No change to record in branch " + b.getName()); } } } catch (GitException ge) { changeLog.append("Unable to retrieve changeset"); } if (histories > 1) listener .getLogger() .println("Warning : There are multiple branch changesets here"); buildChooser.revisionBuilt(revToBuild, buildNumber, null); if (getClean()) { listener.getLogger().println("Cleaning workspace"); git.clean(); } // Fetch the diffs into the changelog file return new Object[] {changeLog.toString(), buildChooser.getData()}; } }); build.addAction((Action) returnData[1]); return changeLogResult((String) returnData[0], changelogFile); }
@Override public boolean pollChanges( final AbstractProject project, Launcher launcher, final FilePath workspace, final TaskListener listener) throws IOException, InterruptedException { // Poll for changes. Are there any unbuilt revisions that Hudson ought to build ? final String gitExe = getDescriptor().getGitExe(); AbstractBuild lastBuild = (AbstractBuild) project.getLastBuild(); if (lastBuild != null) { listener.getLogger().println("[poll] Last Build : #" + lastBuild.getNumber()); } final BuildData buildData = getBuildData(lastBuild, false); if (buildData != null && buildData.lastBuild != null) { listener.getLogger().println("[poll] Last Built Revision: " + buildData.lastBuild.revision); } /* TODO: Breaks serialization somehow. EnvVars tmp = new EnvVars(); try { tmp = lastBuild.getEnvironment(listener); } catch (InterruptedException e) { listener.error("Interrupted exception getting environment .. using empty environment"); } final EnvVars environment = tmp; */ final String singleBranch = getSingleBranch(lastBuild); // listener.getLogger().println("[poll] Branch: " + singleBranch); boolean pollChangesResult = workspace.act( new FileCallable<Boolean>() { private static final long serialVersionUID = 1L; public Boolean invoke(File localWorkspace, VirtualChannel channel) throws IOException { FilePath ws = new FilePath(localWorkspace); IGitAPI git = new GitAPI(gitExe, ws, listener, new EnvVars()); IBuildChooser buildChooser = new BuildChooser(GitSCM.this, git, new GitUtils(listener, git), buildData); if (git.hasGitRepo()) { // Fetch updates for (RemoteConfig remoteRepository : getRepositories()) { fetchFrom(git, localWorkspace, listener, remoteRepository); } Collection<Revision> candidates = buildChooser.getCandidateRevisions(true, singleBranch); return (candidates.size() > 0); } else { listener .getLogger() .println("No Git repository yet, an initial checkout is required"); return true; } } }); return pollChangesResult; }
/** {@inheritDoc} */ @Override public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { Result threshold = onlyStable ? Result.SUCCESS : Result.UNSTABLE; if (build.getResult().isWorseThan(threshold)) { listener .getLogger() .println( "Skipping Cobertura coverage report as build was not " + threshold.toString() + " or better ..."); return true; } listener.getLogger().println("[Cobertura] Publishing Cobertura coverage report..."); final FilePath[] moduleRoots = build.getModuleRoots(); final boolean multipleModuleRoots = moduleRoots != null && moduleRoots.length > 1; final FilePath moduleRoot = multipleModuleRoots ? build.getWorkspace() : build.getModuleRoot(); final File buildCoberturaDir = build.getRootDir(); FilePath buildTarget = new FilePath(buildCoberturaDir); FilePath[] reports = new FilePath[0]; try { reports = moduleRoot.act(new ParseReportCallable(coberturaReportFile)); // if the build has failed, then there's not // much point in reporting an error if (build.getResult().isWorseOrEqualTo(Result.FAILURE) && reports.length == 0) { return true; } } catch (IOException e) { Util.displayIOException(e, listener); e.printStackTrace(listener.fatalError("Unable to find coverage results")); build.setResult(Result.FAILURE); } if (reports.length == 0) { String msg = "[Cobertura] No coverage results were found using the pattern '" + coberturaReportFile + "' relative to '" + moduleRoot.getRemote() + "'." + " Did you enter a pattern relative to the correct directory?" + " Did you generate the XML report(s) for Cobertura?"; listener.getLogger().println(msg); if (failNoReports) { build.setResult(Result.FAILURE); } else { listener.getLogger().println("[Cobertura] Skipped cobertura reports."); } return true; } for (int i = 0; i < reports.length; i++) { final FilePath targetPath = new FilePath(buildTarget, "coverage" + (i == 0 ? "" : i) + ".xml"); try { reports[i].copyTo(targetPath); } catch (IOException e) { Util.displayIOException(e, listener); e.printStackTrace( listener.fatalError( "Unable to copy coverage from " + reports[i] + " to " + buildTarget)); build.setResult(Result.FAILURE); } } listener.getLogger().println("Publishing Cobertura coverage results..."); Set<String> sourcePaths = new HashSet<String>(); CoverageResult result = null; for (File coberturaXmlReport : getCoberturaReports(build)) { try { result = CoberturaCoverageParser.parse(coberturaXmlReport, result, sourcePaths); } catch (IOException e) { Util.displayIOException(e, listener); e.printStackTrace(listener.fatalError("Unable to parse " + coberturaXmlReport)); build.setResult(Result.FAILURE); } } if (result != null) { listener.getLogger().println("Cobertura coverage report found."); result.setOwner(build); final FilePath paintedSourcesPath = new FilePath(new File(build.getProject().getRootDir(), "cobertura")); paintedSourcesPath.mkdirs(); if (sourcePaths.contains(".")) { sourcePaths.remove("."); for (FilePath f : reports) { FilePath p = f.getParent(); if (p != null && p.isDirectory()) { sourcePaths.add(p.getRemote()); } } } SourceCodePainter painter = new SourceCodePainter( paintedSourcesPath, sourcePaths, result.getPaintedSources(), listener, getSourceEncoding()); moduleRoot.act(painter); final CoberturaBuildAction action = CoberturaBuildAction.load( build, result, healthyTarget, unhealthyTarget, getOnlyStable(), getFailUnhealthy(), getFailUnstable(), getAutoUpdateHealth(), getAutoUpdateStability()); build.getActions().add(action); Set<CoverageMetric> failingMetrics = failingTarget.getFailingMetrics(result); if (!failingMetrics.isEmpty()) { listener.getLogger().println("Code coverage enforcement failed for the following metrics:"); float oldStabilityPercent; float setStabilityPercent; for (CoverageMetric metric : failingMetrics) { oldStabilityPercent = failingTarget.getObservedPercent(result, metric); setStabilityPercent = failingTarget.getSetPercent(result, metric); listener .getLogger() .println( " " + metric.getName() + "'s stability is " + roundDecimalFloat(oldStabilityPercent * 100f) + " and set mininum stability is " + roundDecimalFloat(setStabilityPercent * 100f) + "."); } if (!getFailUnstable()) { listener.getLogger().println("Setting Build to unstable."); build.setResult(Result.UNSTABLE); } else { listener.getLogger().println("Failing build due to unstability."); build.setResult(Result.FAILURE); } } if (getFailUnhealthy()) { Set<CoverageMetric> unhealthyMetrics = unhealthyTarget.getFailingMetrics(result); if (!unhealthyMetrics.isEmpty()) { listener.getLogger().println("Unhealthy for the following metrics:"); float oldHealthyPercent; float setHealthyPercent; for (CoverageMetric metric : unhealthyMetrics) { oldHealthyPercent = unhealthyTarget.getObservedPercent(result, metric); setHealthyPercent = unhealthyTarget.getSetPercent(result, metric); listener .getLogger() .println( " " + metric.getName() + "'s health is " + roundDecimalFloat(oldHealthyPercent * 100f) + " and set minimum health is " + roundDecimalFloat(setHealthyPercent * 100f) + "."); } listener.getLogger().println("Failing build because it is unhealthy."); build.setResult(Result.FAILURE); } } if (build.getResult() == Result.SUCCESS) { if (getAutoUpdateHealth()) { setNewPercentages(result, true, listener); } if (getAutoUpdateStability()) { setNewPercentages(result, false, listener); } } } else { listener .getLogger() .println( "No coverage results were successfully parsed. Did you generate " + "the XML report(s) for Cobertura?"); build.setResult(Result.FAILURE); } return true; }
@Override public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, final BuildListener listener) throws InterruptedException { // during matrix build, the push back would happen at the very end only once for the whole // matrix, // not for individual configuration build. if (build instanceof MatrixRun) { return true; } SCM scm = build.getProject().getScm(); if (!(scm instanceof GitSCM)) { return false; } final GitSCM gitSCM = (GitSCM) scm; if (gitSCM.getUseShallowClone()) { listener.getLogger().println("GitPublisher disabled while using shallow clone."); return true; } final String projectName = build.getProject().getName(); final FilePath workspacePath = build.getWorkspace(); final int buildNumber = build.getNumber(); final Result buildResult = build.getResult(); // If pushOnlyIfSuccess is selected and the build is not a success, don't push. if (pushOnlyIfSuccess && buildResult.isWorseThan(Result.SUCCESS)) { listener .getLogger() .println( "Build did not succeed and the project is configured to only push after a successful build, so no pushing will occur."); return true; } else { final String gitExe = gitSCM.getGitExe(build.getBuiltOn(), listener); EnvVars tempEnvironment; try { tempEnvironment = build.getEnvironment(listener); } catch (IOException e) { e.printStackTrace(listener.error("Failed to build up environment")); tempEnvironment = new EnvVars(); } String confName = gitSCM.getGitConfigNameToUse(); if ((confName != null) && (!confName.equals(""))) { tempEnvironment.put("GIT_COMMITTER_NAME", confName); tempEnvironment.put("GIT_AUTHOR_NAME", confName); } String confEmail = gitSCM.getGitConfigEmailToUse(); if ((confEmail != null) && (!confEmail.equals(""))) { tempEnvironment.put("GIT_COMMITTER_EMAIL", confEmail); tempEnvironment.put("GIT_AUTHOR_EMAIL", confEmail); } final EnvVars environment = tempEnvironment; final FilePath workingDirectory = gitSCM.workingDirectory(workspacePath, environment); boolean pushResult = true; // If we're pushing the merge back... if (pushMerge) { boolean mergeResult; try { mergeResult = workingDirectory.act( new FileCallable<Boolean>() { private static final long serialVersionUID = 1L; public Boolean invoke(File workspace, VirtualChannel channel) throws IOException { IGitAPI git = new GitAPI(gitExe, new FilePath(workspace), listener, environment); // We delete the old tag generated by the SCM plugin String buildnumber = "jenkins-" + projectName + "-" + buildNumber; git.deleteTag(buildnumber); // And add the success / fail state into the tag. buildnumber += "-" + buildResult.toString(); git.tag(buildnumber, "Jenkins Build #" + buildNumber); PreBuildMergeOptions mergeOptions = gitSCM.getMergeOptions(); if (mergeOptions.doMerge() && buildResult.isBetterOrEqualTo(Result.SUCCESS)) { RemoteConfig remote = mergeOptions.getMergeRemote(); listener .getLogger() .println( "Pushing HEAD to branch " + mergeOptions.getMergeTarget() + " of " + remote.getName() + " repository"); git.push(remote, "HEAD:" + mergeOptions.getMergeTarget()); } else { // listener.getLogger().println("Pushing result " + buildnumber + " to // origin repository"); // git.push(null); } return true; } }); } catch (Throwable e) { e.printStackTrace(listener.error("Failed to push merge to origin repository")); build.setResult(Result.FAILURE); mergeResult = false; } if (!mergeResult) { pushResult = false; } } if (isPushTags()) { boolean allTagsResult = true; for (final TagToPush t : tagsToPush) { boolean tagResult = true; if (t.getTagName() == null) { listener.getLogger().println("No tag to push defined"); tagResult = false; } if (t.getTargetRepoName() == null) { listener.getLogger().println("No target repo to push to defined"); tagResult = false; } if (tagResult) { final String tagName = environment.expand(t.getTagName()); final String targetRepo = environment.expand(t.getTargetRepoName()); try { tagResult = workingDirectory.act( new FileCallable<Boolean>() { private static final long serialVersionUID = 1L; public Boolean invoke(File workspace, VirtualChannel channel) throws IOException { IGitAPI git = new GitAPI(gitExe, new FilePath(workspace), listener, environment); RemoteConfig remote = gitSCM.getRepositoryByName(targetRepo); if (remote == null) { listener .getLogger() .println("No repository found for target repo name " + targetRepo); return false; } if (t.isCreateTag()) { if (git.tagExists(tagName)) { listener .getLogger() .println( "Tag " + tagName + " already exists and Create Tag is specified, so failing."); return false; } git.tag(tagName, "Jenkins Git plugin tagging with " + tagName); } else if (!git.tagExists(tagName)) { listener .getLogger() .println( "Tag " + tagName + " does not exist and Create Tag is not specified, so failing."); return false; } listener .getLogger() .println("Pushing tag " + tagName + " to repo " + targetRepo); git.push(remote, tagName); return true; } }); } catch (Throwable e) { e.printStackTrace( listener.error("Failed to push tag " + tagName + " to " + targetRepo)); build.setResult(Result.FAILURE); tagResult = false; } } if (!tagResult) { allTagsResult = false; } } if (!allTagsResult) { pushResult = false; } } if (isPushBranches()) { boolean allBranchesResult = true; for (final BranchToPush b : branchesToPush) { boolean branchResult = true; if (b.getBranchName() == null) { listener.getLogger().println("No branch to push defined"); return false; } if (b.getTargetRepoName() == null) { listener.getLogger().println("No branch repo to push to defined"); return false; } final String branchName = environment.expand(b.getBranchName()); final String targetRepo = environment.expand(b.getTargetRepoName()); if (branchResult) { try { branchResult = workingDirectory.act( new FileCallable<Boolean>() { private static final long serialVersionUID = 1L; public Boolean invoke(File workspace, VirtualChannel channel) throws IOException { IGitAPI git = new GitAPI(gitExe, new FilePath(workspace), listener, environment); RemoteConfig remote = gitSCM.getRepositoryByName(targetRepo); if (remote == null) { listener .getLogger() .println("No repository found for target repo name " + targetRepo); return false; } listener .getLogger() .println( "Pushing HEAD to branch " + branchName + " at repo " + targetRepo); git.push(remote, "HEAD:" + branchName); return true; } }); } catch (Throwable e) { e.printStackTrace( listener.error("Failed to push branch " + branchName + " to " + targetRepo)); build.setResult(Result.FAILURE); branchResult = false; } } if (!branchResult) { allBranchesResult = false; } } if (!allBranchesResult) { pushResult = false; } } if (isPushNotes()) { boolean allNotesResult = true; for (final NoteToPush b : notesToPush) { boolean noteResult = true; if (b.getnoteMsg() == null) { listener.getLogger().println("No note to push defined"); return false; } b.setEmptyTargetRepoToOrigin(); final String noteMsg = environment.expand(b.getnoteMsg()); final String noteNamespace = environment.expand(b.getnoteNamespace()); final String targetRepo = environment.expand(b.getTargetRepoName()); final boolean noteReplace = b.getnoteReplace(); if (noteResult) { try { noteResult = workingDirectory.act( new FileCallable<Boolean>() { private static final long serialVersionUID = 1L; public Boolean invoke(File workspace, VirtualChannel channel) throws IOException { IGitAPI git = new GitAPI(gitExe, new FilePath(workspace), listener, environment); RemoteConfig remote = gitSCM.getRepositoryByName(targetRepo); if (remote == null) { listener .getLogger() .println("No repository found for target repo name " + targetRepo); return false; } listener .getLogger() .println( "Adding note \"" + noteMsg + "\" to namespace \"" + noteNamespace + "\""); if (noteReplace) git.addNote(noteMsg, noteNamespace); else git.appendNote(noteMsg, noteNamespace); git.push(remote, "refs/notes/*"); return true; } }); } catch (Throwable e) { e.printStackTrace( listener.error( "Failed to add note \"" + noteMsg + "\" to \"" + noteNamespace + "\"")); build.setResult(Result.FAILURE); noteResult = false; } } if (!noteResult) { allNotesResult = false; } } if (!allNotesResult) { pushResult = false; } } return pushResult; } }
/** * Serves a file from the file system (Maps the URL to a directory in a file system.) * * @param icon The icon file name, like "folder-open.gif" * @param serveDirIndex True to generate the directory index. False to serve "index.html" * @deprecated as of 1.297 Instead of calling this method explicitly, just return the {@link * DirectoryBrowserSupport} object from the {@code doXYZ} method and let Stapler generate a * response for you. */ public void serveFile( StaplerRequest req, StaplerResponse rsp, FilePath root, String icon, boolean serveDirIndex) throws IOException, ServletException, InterruptedException { // handle form submission String pattern = req.getParameter("pattern"); if (pattern == null) pattern = req.getParameter("path"); // compatibility with Hudson<1.129 if (pattern != null) { rsp.sendRedirect2(pattern); return; } String path = getPath(req); if (path.replace('\\', '/').indexOf("/../") != -1) { // don't serve anything other than files in the artifacts dir rsp.sendError(HttpServletResponse.SC_BAD_REQUEST); return; } // split the path to the base directory portion "abc/def/ghi" which doesn't include any // wildcard, // and the GLOB portion "**/*.xml" (the rest) StringBuilder _base = new StringBuilder(); StringBuilder _rest = new StringBuilder(); int restSize = -1; // number of ".." needed to go back to the 'base' level. boolean zip = false; // if we are asked to serve a zip file bundle boolean plain = false; // if asked to serve a plain text directory listing { boolean inBase = true; StringTokenizer pathTokens = new StringTokenizer(path, "/"); while (pathTokens.hasMoreTokens()) { String pathElement = pathTokens.nextToken(); // Treat * and ? as wildcard unless they match a literal filename if ((pathElement.contains("?") || pathElement.contains("*")) && inBase && !(new FilePath(root, (_base.length() > 0 ? _base + "/" : "") + pathElement) .exists())) inBase = false; if (pathElement.equals("*zip*")) { // the expected syntax is foo/bar/*zip*/bar.zip // the last 'bar.zip' portion is to causes browses to set a good default file name. // so the 'rest' portion ends here. zip = true; break; } if (pathElement.equals("*plain*")) { plain = true; break; } StringBuilder sb = inBase ? _base : _rest; if (sb.length() > 0) sb.append('/'); sb.append(pathElement); if (!inBase) restSize++; } } restSize = Math.max(restSize, 0); String base = _base.toString(); String rest = _rest.toString(); // this is the base file/directory FilePath baseFile = new FilePath(root, base); if (baseFile.isDirectory()) { if (zip) { rsp.setContentType("application/zip"); baseFile.zip(rsp.getOutputStream(), rest); return; } if (plain) { rsp.setContentType("text/plain;charset=UTF-8"); OutputStream os = rsp.getOutputStream(); try { for (String kid : baseFile.act(new SimpleChildList())) { os.write(kid.getBytes("UTF-8")); os.write('\n'); } os.flush(); } finally { os.close(); } return; } if (rest.length() == 0) { // if the target page to be displayed is a directory and the path doesn't end with '/', // redirect StringBuffer reqUrl = req.getRequestURL(); if (reqUrl.charAt(reqUrl.length() - 1) != '/') { rsp.sendRedirect2(reqUrl.append('/').toString()); return; } } FileCallable<List<List<Path>>> glob = null; if (rest.length() > 0) { // the rest is Ant glob pattern glob = new PatternScanner(rest, createBackRef(restSize)); } else if (serveDirIndex) { // serve directory index glob = new ChildPathBuilder(); } if (glob != null) { // serve glob req.setAttribute("it", this); List<Path> parentPaths = buildParentPath(base, restSize); req.setAttribute("parentPath", parentPaths); req.setAttribute("backPath", createBackRef(restSize)); req.setAttribute("topPath", createBackRef(parentPaths.size() + restSize)); req.setAttribute("files", baseFile.act(glob)); req.setAttribute("icon", icon); req.setAttribute("path", path); req.setAttribute("pattern", rest); req.setAttribute("dir", baseFile); req.getView(this, "dir.jelly").forward(req, rsp); return; } // convert a directory service request to a single file service request by serving // 'index.html' baseFile = baseFile.child(indexFileName); } // serve a single file if (!baseFile.exists()) { rsp.sendError(HttpServletResponse.SC_NOT_FOUND); return; } boolean view = rest.equals("*view*"); if (rest.equals("*fingerprint*")) { rsp.forward(Hudson.getInstance().getFingerprint(baseFile.digest()), "/", req); return; } ContentInfo ci = baseFile.act(new ContentInfo()); if (LOGGER.isLoggable(Level.FINE)) LOGGER.fine( "Serving " + baseFile + " with lastModified=" + ci.lastModified + ", contentLength=" + ci.contentLength); InputStream in = baseFile.read(); if (view) { // for binary files, provide the file name for download rsp.setHeader("Content-Disposition", "inline; filename=" + baseFile.getName()); // pseudo file name to let the Stapler set text/plain rsp.serveFile(req, in, ci.lastModified, -1, ci.contentLength, "plain.txt"); } else { rsp.serveFile(req, in, ci.lastModified, -1, ci.contentLength, baseFile.getName()); } }
@Override public boolean perform(final AbstractBuild build, Launcher launcher, final BuildListener listener) throws IOException, InterruptedException { FilePath ws = build.getWorkspace(); return ws.act( new FileCallable<Boolean>() { // if 'file' is on a different node, this FileCallable will // be transfered to that node and executed there. public Boolean invoke(File workspace, VirtualChannel channel) { // f and file represents the same thing File git_home_directory = getGitHome(workspace); if (git_home_directory == null) { listener .getLogger() .println( "Failed to find GIT_HOME in " + workspace.getAbsolutePath() + File.separatorChar + GerritNotifier.this.git_home); build.setResult(Result.ABORTED); return false; } Repository repo = getRepository(git_home_directory); if (repo == null) { listener .getLogger() .println( "Failed to read repository from " + git_home_directory.getAbsolutePath()); build.setResult(Result.ABORTED); return false; } ObjectId head = getHead(repo); if (head == null) { listener .getLogger() .println( "HEAD is null for " + repo.getDirectory().getAbsolutePath() + ", are you sure that you're using git?"); build.setResult(Result.ABORTED); return null; } try { Result r = build.getResult(); EnvVars vars = null; try { vars = build.getEnvironment(listener); } catch (InterruptedException e) { listener.getLogger().println(e.getMessage()); e.printStackTrace(); } String buildUrl = "No build url."; if (vars.containsKey("BUILD_URL")) { buildUrl = vars.get("BUILD_URL"); } if (r.isBetterOrEqualTo(Result.SUCCESS)) { listener.getLogger().println("Approving " + head.name()); verifyGerrit(approve_value, buildUrl, head.name()); } else if (r.isBetterOrEqualTo(Result.UNSTABLE)) { listener.getLogger().println("Rejecting unstable " + head.name()); verifyGerrit(reject_value, "Build is unstable " + buildUrl, head.name()); } else { listener.getLogger().println("Rejecting failed " + head.name()); verifyGerrit(reject_value, "Build failed " + buildUrl, head.name()); } } catch (IOException e) { listener.getLogger().println(e.getMessage()); e.printStackTrace(listener.getLogger()); build.setResult(Result.ABORTED); return false; } return true; } }); }
private void checkVersions() throws InterruptedException, IOException { updated = false; solutionDir.act( new FileCallable<Void>() { public Void invoke(File file, VirtualChannel vc) throws IOException, InterruptedException { try { final String root = file.getAbsolutePath(); DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); final DocumentBuilder builder = dbFactory.newDocumentBuilder(); Files.walkFileTree( Paths.get(file.getPath()), new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if (file.getFileName().toString().equalsIgnoreCase("packages.config")) { log.info( String.format( "Checking packages file: %s", file.toAbsolutePath().toString())); try { Document doc = builder.parse(file.toFile()); doc.getDocumentElement().normalize(); NodeList elems = doc.getElementsByTagName("package"); for (int idx = 0; idx < elems.getLength(); idx++) { Element p = (Element) elems.item(idx); String id = p.getAttribute("id"); String version = p.getAttribute("version"); String latest = getPackageVersion(root, id); if (latest == null || !version.equals(latest)) { log.info( String.format( "Package %s v%s should update to v%s.", id, version, latest)); updated = true; return FileVisitResult.TERMINATE; } } } catch (SAXException ex) { log.error(ex.toString()); } } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { log.error(exc.toString()); return FileVisitResult.CONTINUE; } }); } catch (ParserConfigurationException ex) { log.error(ex.toString()); } return null; } }); }
@Override public boolean pollChanges( final AbstractProject project, Launcher launcher, final FilePath workspace, final TaskListener listener) throws IOException, InterruptedException { // Poll for changes. Are there any unbuilt revisions that Hudson ought to build ? final String gitExe = getDescriptor().getGitExe(); listener.getLogger().println("Using strategy: " + choosingStrategy); AbstractBuild lastBuild = (AbstractBuild) project.getLastBuild(); if (lastBuild != null) { listener.getLogger().println("[poll] Last Build : #" + lastBuild.getNumber()); } final BuildData buildData = getBuildData(lastBuild, false); if (buildData != null && buildData.lastBuild != null) { listener.getLogger().println("[poll] Last Built Revision: " + buildData.lastBuild.revision); } final String singleBranch = getSingleBranch(lastBuild); boolean pollChangesResult = workspace.act( new FileCallable<Boolean>() { private static final long serialVersionUID = 1L; public Boolean invoke(File localWorkspace, VirtualChannel channel) throws IOException { EnvVars environment = new EnvVars(System.getenv()); IGitAPI git = new GitAPI(gitExe, new FilePath(localWorkspace), listener, environment); IBuildChooser buildChooser = createBuildChooser(git, listener, buildData); if (git.hasGitRepo()) { // Repo is there - do a fetch listener.getLogger().println("Fetching changes from the remote Git repositories"); // Fetch updates for (RemoteConfig remoteRepository : getRepositories()) { fetchFrom(git, localWorkspace, listener, remoteRepository); } listener.getLogger().println("Polling for changes in"); Collection<Revision> candidates = buildChooser.getCandidateRevisions(true, singleBranch); return (candidates.size() > 0); } else { listener .getLogger() .println("No Git repository yet, an initial checkout is required"); return true; } } }); return pollChangesResult; }
private String getUrlForPath(FilePath path) throws IOException, InterruptedException { return path.act(new GetUrlForPath(createAuthenticationProvider())); }
@Override public boolean perform( final AbstractBuild build, final Launcher launcher, final BuildListener listener) throws IOException, InterruptedException { listener.getLogger().println("Docker Build"); FilePath fpChild = new FilePath(build.getWorkspace(), dockerFileDirectory); final String tagToUse = getTag(build, launcher, listener); final String url = getUrl(build); // Marshal the builder across the wire. DockerClient client = getDockerClient(build); final DockerClient.Builder builder = DockerClient.builder().fromClient(client); BuildCommandResponse response = fpChild.act( new FilePath.FileCallable<BuildCommandResponse>() { public BuildCommandResponse invoke(File f, VirtualChannel channel) throws IOException, InterruptedException { try { listener .getLogger() .println( "Docker Build : build with tag " + tagToUse + " at path " + f.getAbsolutePath()); DockerClient client = builder.readTimeout(3600000).build(); File dockerFile; // Be lenient and allow the user to just specify the path. if (f.isFile()) dockerFile = f; else dockerFile = new File(f, "Dockerfile"); return client.createBuildCommand().dockerFile(dockerFile).tag(tagToUse).execute(); } catch (DockerException e) { throw Throwables.propagate(e); } } }); listener.getLogger().println("Docker Build Response : " + response); Optional<String> id = response.imageId(); if (!id.isPresent()) return false; build.addAction( new DockerBuildImageAction( url, id.get(), tagToUse, cleanupWithJenkinsJobDelete, pushOnSuccess)); build.save(); if (pushOnSuccess) { listener.getLogger().println("Pushing " + tagToUse); if (!tagToUse.toLowerCase().equals(tagToUse)) { listener .getLogger() .println( "ERROR: Docker will refuse to push tag name " + tagToUse + " because it uses upper case."); } Identifier identifier = Identifier.fromCompoundString(tagToUse); String repositoryName = identifier.repository.name; PushCommandResponse pushResponse = client.createPushCommand().name(repositoryName).execute(); listener.getLogger().println("Docker Push Response : " + pushResponse); } if (cleanImages) { // For some reason, docker delete doesn't delete all tagged // versions, despite force = true. // So, do it multiple times (protect against infinite looping). listener.getLogger().println("Cleaning local images"); int delete = 100; while (delete != 0) { int count = client.image(id.get()).removeCommand().force(true).execute().size(); if (count == 0) delete = 0; else delete--; } } listener.getLogger().println("Docker Build Done"); return true; }