# HG changeset patch # User Nadia Burnasheva # Date 1697628624 -7200 # Node ID 7f82951e9391e72c427a6cf8bc625e36ce99d542 # Parent 53998d7080518fa59a3d5bf9de70fa169f72e179# Parent e6e3f80c9313f23389d644a8ca7faab2c4821009 merge default to development/2023.11.x branch diff -r 53998d708051 -r 7f82951e9391 .idea/artifacts/mercurial_vcs_worker.xml --- a/.idea/artifacts/mercurial_vcs_worker.xml Tue Oct 17 12:52:06 2023 +0200 +++ b/.idea/artifacts/mercurial_vcs_worker.xml Wed Oct 18 13:30:24 2023 +0200 @@ -12,8 +12,6 @@ - - diff -r 53998d708051 -r 7f82951e9391 .idea/artifacts/plugin.xml --- a/.idea/artifacts/plugin.xml Tue Oct 17 12:52:06 2023 +0200 +++ b/.idea/artifacts/plugin.xml Wed Oct 18 13:30:24 2023 +0200 @@ -13,8 +13,6 @@ - - @@ -22,8 +20,6 @@ - - diff -r 53998d708051 -r 7f82951e9391 .idea/libraries/IDEA_openapi.xml --- a/.idea/libraries/IDEA_openapi.xml Tue Oct 17 12:52:06 2023 +0200 +++ b/.idea/libraries/IDEA_openapi.xml Wed Oct 18 13:30:24 2023 +0200 @@ -3,6 +3,8 @@ + + diff -r 53998d708051 -r 7f82951e9391 .idea/libraries/Log4j.xml --- a/.idea/libraries/Log4j.xml Tue Oct 17 12:52:06 2023 +0200 +++ b/.idea/libraries/Log4j.xml Wed Oct 18 13:30:24 2023 +0200 @@ -4,6 +4,9 @@ + + + diff -r 53998d708051 -r 7f82951e9391 .idea/libraries/TeamCityAPI_agent.xml --- a/.idea/libraries/TeamCityAPI_agent.xml Tue Oct 17 12:52:06 2023 +0200 +++ b/.idea/libraries/TeamCityAPI_agent.xml Wed Oct 18 13:30:24 2023 +0200 @@ -3,6 +3,7 @@ + diff -r 53998d708051 -r 7f82951e9391 .idea/libraries/TeamCityAPI_common.xml --- a/.idea/libraries/TeamCityAPI_common.xml Tue Oct 17 12:52:06 2023 +0200 +++ b/.idea/libraries/TeamCityAPI_common.xml Wed Oct 18 13:30:24 2023 +0200 @@ -1,10 +1,22 @@ + + + + + + + + + + + + diff -r 53998d708051 -r 7f82951e9391 .idea/libraries/TeamCityAPI_server.xml --- a/.idea/libraries/TeamCityAPI_server.xml Tue Oct 17 12:52:06 2023 +0200 +++ b/.idea/libraries/TeamCityAPI_server.xml Wed Oct 18 13:30:24 2023 +0200 @@ -2,6 +2,24 @@ + + + + + + + + + + + + + + + + + + diff -r 53998d708051 -r 7f82951e9391 .idea/libraries/TeamCity_impl.xml --- a/.idea/libraries/TeamCity_impl.xml Tue Oct 17 12:52:06 2023 +0200 +++ b/.idea/libraries/TeamCity_impl.xml Wed Oct 18 13:30:24 2023 +0200 @@ -2,7 +2,11 @@ + + + + diff -r 53998d708051 -r 7f82951e9391 .idea/libraries/commons_codec_1_16_0.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/libraries/commons_codec_1_16_0.xml Wed Oct 18 13:30:24 2023 +0200 @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff -r 53998d708051 -r 7f82951e9391 .idea/libraries/commons_codec_1_4.xml --- a/.idea/libraries/commons_codec_1_4.xml Tue Oct 17 12:52:06 2023 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff -r 53998d708051 -r 7f82951e9391 .idea/libraries/commons_compress_1_5.xml --- a/.idea/libraries/commons_compress_1_5.xml Tue Oct 17 12:52:06 2023 +0200 +++ b/.idea/libraries/commons_compress_1_5.xml Wed Oct 18 13:30:24 2023 +0200 @@ -2,6 +2,7 @@ + diff -r 53998d708051 -r 7f82951e9391 .idea/libraries/jdom.xml diff -r 53998d708051 -r 7f82951e9391 .idea/misc.xml --- a/.idea/misc.xml Tue Oct 17 12:52:06 2023 +0200 +++ b/.idea/misc.xml Wed Oct 18 13:30:24 2023 +0200 @@ -1,8 +1,7 @@ - - - - - - - + + + + + + \ No newline at end of file diff -r 53998d708051 -r 7f82951e9391 lib/commons-codec-1.16.0.jar Binary file lib/commons-codec-1.16.0.jar has changed diff -r 53998d708051 -r 7f82951e9391 lib/commons-codec-1.4.jar Binary file lib/commons-codec-1.4.jar has changed diff -r 53998d708051 -r 7f82951e9391 mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentPluginConfig.java --- a/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentPluginConfig.java Tue Oct 17 12:52:06 2023 +0200 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentPluginConfig.java Wed Oct 18 13:30:24 2023 +0200 @@ -37,6 +37,8 @@ boolean runWithProfile(@NotNull AgentRunningBuild build); + boolean retryPullForIllegalPathComponent(@NotNull AgentRunningBuild build); + @NotNull File getTempDir(); } diff -r 53998d708051 -r 7f82951e9391 mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentPluginConfigImpl.java --- a/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentPluginConfigImpl.java Tue Oct 17 12:52:06 2023 +0200 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentPluginConfigImpl.java Wed Oct 18 13:30:24 2023 +0200 @@ -96,6 +96,11 @@ return Boolean.parseBoolean(build.getSharedConfigParameters().get("teamcity.hg.runCommandsWithProfile")); } + @Override + public boolean retryPullForIllegalPathComponent(@NotNull AgentRunningBuild build) { + return Boolean.parseBoolean(build.getSharedConfigParameters().getOrDefault("teamcity.hg.retryPullForIllegalPathComponent", "true")); + } + @Nullable public Integer parseTimeout(@Nullable String timeoutStr) { if (timeoutStr == null) diff -r 53998d708051 -r 7f82951e9391 mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialIncludeRuleUpdater.java --- a/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialIncludeRuleUpdater.java Tue Oct 17 12:52:06 2023 +0200 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialIncludeRuleUpdater.java Wed Oct 18 13:30:24 2023 +0200 @@ -23,6 +23,7 @@ import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.PullCommand; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.AbandonedTransactionFound; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.PathIllegalComponentException; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.UnrelatedRepositoryException; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.WrongSubrepoUrlException; import jetbrains.buildServer.buildTriggers.vcs.mercurial.ext.BeforeWorkingDirUpdateExtension; @@ -33,6 +34,7 @@ import jetbrains.buildServer.vcs.VcsException; import jetbrains.buildServer.vcs.VcsRoot; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; @@ -57,6 +59,7 @@ private int myPullTimeout; private final boolean myUseTraceback; private final boolean myProfile; + private final boolean myRetryPullForIllegalPathComponent; private final List myExtensions = new ArrayList<>(); protected final MercurialProgress myProgress; @@ -76,6 +79,7 @@ myPullTimeout = pluginConfig.getPullTimeout(build); myUseTraceback = pluginConfig.runWithTraceback(build); myProfile = pluginConfig.runWithProfile(build); + myRetryPullForIllegalPathComponent = pluginConfig.retryPullForIllegalPathComponent(build); myProgress = new MercurialBuildLogProgress(build.getBuildLogger().getFlowLogger("-1")); } @@ -126,16 +130,12 @@ if (mirrorRepo.containsRevision(revision)) { myLogger.message("Local mirror is already up-to-date"); } else { - PullCommand pull = mirrorRepo.pull().fromRepository(repositoryUrl) - .withTraceback(myUseTraceback) - .withProfile(myProfile) - .withTimeout(myPullTimeout); try { - pull.call(); + doPull(mirrorRepo, repositoryUrl, myToVersion); } catch (AbandonedTransactionFound e) { myLogger.message("Abandoned transaction found, trying to recover"); mirrorRepo.recover().call(); - pull.call(); + doPull(mirrorRepo, repositoryUrl, myToVersion); } } } @@ -154,17 +154,36 @@ myLogger.message("Repository already contains revision " + myToVersion); } else { try { - repo.pull().fromRepository(repositoryUrl) - .withTraceback(myUseTraceback) - .withProfile(myProfile) - .withTimeout(myPullTimeout) - .call(); + doPull(repo, repositoryUrl, myToVersion); } catch (UnrelatedRepositoryException e) { throw new UnrelatedRepositoryException(myAuthSettings.getRepositoryUrlWithHiddenPassword(repositoryUrl), workingDir); } } } + private void doPull(@NotNull HgRepo repo, @NotNull String repositoryUrl, @NotNull String revision) throws VcsException { + doPull(repo, repositoryUrl, revision, false); + } + + private void doPull(@NotNull HgRepo repo, @NotNull String repositoryUrl, @NotNull String revision, boolean explicitRevision) throws VcsException { + final PullCommand pullCommand = repo.pull().fromRepository(repositoryUrl) + .withTraceback(myUseTraceback) + .withProfile(myProfile) + .withTimeout(myPullTimeout); + if (explicitRevision) { + pullCommand.withNamedRevision(revision); + } + + try { + pullCommand.call(); + } catch (PathIllegalComponentException e) { + if (!myRetryPullForIllegalPathComponent || explicitRevision) { + throw e; + } + myLogger.message("Pull encountered illegal path component " + e.getComponent() + " retrying with explicit revision " + revision); + doPull(repo, repositoryUrl, revision, true); + } + } private void disableSharing(@NotNull File workingDir) { File dotHg = new File(workingDir, ".hg"); diff -r 53998d708051 -r 7f82951e9391 mercurial-common/mercurial-common.iml --- a/mercurial-common/mercurial-common.iml Tue Oct 17 12:52:06 2023 +0200 +++ b/mercurial-common/mercurial-common.iml Wed Oct 18 13:30:24 2023 +0200 @@ -1,6 +1,6 @@ - + @@ -11,6 +11,6 @@ - + \ No newline at end of file diff -r 53998d708051 -r 7f82951e9391 mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandResult.java --- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandResult.java Tue Oct 17 12:52:06 2023 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandResult.java Wed Oct 18 13:30:24 2023 +0200 @@ -242,6 +242,7 @@ checkMergeWithWorkDirAncestor(stderr); checkNothingToMerge(stderr); checkUnknownException(stderr); + checkPathIllegalComponent(stderr); } private void checkUnrelatedRepository(@NotNull final String stderr) throws UnrelatedRepositoryException { @@ -298,6 +299,16 @@ throw new UnknownMercurialException(stderr); } + private void checkPathIllegalComponent(@NotNull final String stderr) throws PathIllegalComponentException { + final String prefix = "abort: path contains illegal component: "; + int idx = stderr.indexOf(prefix); + if (idx != -1) { + int startIdx = idx + prefix.length(); + final String component = stderr.substring(startIdx); + throw new PathIllegalComponentException(component); + } + } + private static Set setOf(Integer... ints) { return new HashSet<>(asList(ints)); } diff -r 53998d708051 -r 7f82951e9391 mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PullCommand.java --- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PullCommand.java Tue Oct 17 12:52:06 2023 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PullCommand.java Wed Oct 18 13:30:24 2023 +0200 @@ -31,6 +31,8 @@ private int myTimeout; private boolean myTraceback; private boolean myProfile; + private ChangeSet myChangeSet; + private String myNamedRevision; public PullCommand(@NotNull CommandSettings commandSettings, @NotNull String hgPath, @@ -64,6 +66,16 @@ return this; } + public PullCommand withChangeSet(@NotNull ChangeSet changeSet) { + myChangeSet = changeSet; + return this; + } + + public PullCommand withNamedRevision(@NotNull String namedRevision) { + myNamedRevision = namedRevision; + return this; + } + public void call() throws VcsException { removeLocks(); @@ -84,6 +96,12 @@ cli.setHasProgress(true); } + if (myChangeSet != null) { + cli.addParameters("--rev", myChangeSet.getId()); + } else if (myNamedRevision != null) { + cli.addParameters("--rev", myNamedRevision); + } + String pullUrl = myAuthSettings.getRepositoryUrlWithCredentials(myPullUrl); cli.addParameter(pullUrl); runCommand(cli, settings); diff -r 53998d708051 -r 7f82951e9391 mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/exception/PathIllegalComponentException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/exception/PathIllegalComponentException.java Wed Oct 18 13:30:24 2023 +0200 @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2023 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception; + +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +public class PathIllegalComponentException extends VcsException { + + @NotNull private final String myComponent; + + public PathIllegalComponentException(@NotNull String component) { + super("Path contains illegal component: " + component); + myComponent = component; + } + + @NotNull + public String getComponent() { + return myComponent; + } +} diff -r 53998d708051 -r 7f82951e9391 mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java --- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java Tue Oct 17 12:52:06 2023 +0200 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java Wed Oct 18 13:30:24 2023 +0200 @@ -19,6 +19,7 @@ import jetbrains.buildServer.buildTriggers.vcs.AbstractVcsPropertiesProcessor; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.AbandonedTransactionFound; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.PathIllegalComponentException; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.UnrelatedRepositoryException; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.WrongSubrepoUrlException; import jetbrains.buildServer.log.Loggers; @@ -539,8 +540,12 @@ } } + private void syncRepository(@NotNull final HgVcsRoot root, @NotNull final ChangeSet cset) throws VcsException { + syncRepository(root, cset, false); + } + /* clone the repo if it doesn't exist, pull the repo if it doesn't contain specified changeSet */ - private void syncRepository(@NotNull final HgVcsRoot root, @NotNull final ChangeSet cset) throws VcsException { + private void syncRepository(@NotNull final HgVcsRoot root, @NotNull final ChangeSet cset, boolean explicitRevision) throws VcsException { File workingDir = getWorkingDir(root); lockWorkDir(workingDir); HgRepo repo = createRepo(root); @@ -552,14 +557,27 @@ repo.setDefaultPath(root.getRepository()); repo.setTeamCityConfig(root.getCustomHgConfigServer()); try { - repo.pull().fromRepository(root.getRepository()) + final PullCommand pullCommand = repo.pull().fromRepository(root.getRepository()) .withTimeout(myConfig.getPullTimeout()) - .withProfile(myConfig.runWithProfile(root)) - .call(); + .withProfile(myConfig.runWithProfile(root)); + if (explicitRevision) { + pullCommand.withChangeSet(cset); + } + pullCommand.call(); } catch (UnrelatedRepositoryException e) { Loggers.VCS.warn("Repository at " + root.getRepository() + " is unrelated, clone it again"); myMirrorManager.forgetDir(workingDir); syncRepository(root, cset); + } catch (PathIllegalComponentException e) { + final StringBuilder logMessage = new StringBuilder("Pulling from repository at ").append(root.getRepository()) + .append(" failed because of illegal path component ").append(e.getComponent()).append("."); + if (myConfig.retryPullForIllegalPathComponent() && !explicitRevision) { + logMessage.append(" Retrying with explicit pull for revision ").append(cset).append("."); + Loggers.VCS.warn(logMessage.toString()); + syncRepository(root, cset, true); + return; + } + Loggers.VCS.warn(logMessage.toString()); } } finally { unlockWorkDir(workingDir); @@ -581,11 +599,12 @@ public T syncRepository(@NotNull HgVcsRoot root, @NotNull SyncSettings settings, @Nullable OperationContext context) throws VcsException { boolean customWorkingDir = root.getCustomWorkingDir() != null; File workingDir = getWorkingDir(root); + boolean pullFromTip = false; int attemptsLeft = 3; VcsException lastError = null; while (attemptsLeft-- > 0) { try { - return syncRepositoryOnce(root, settings, workingDir, context); + return syncRepositoryOnce(root, settings, workingDir, context, pullFromTip); } catch (UnrelatedRepositoryException e) { if (customWorkingDir) throw new VcsException(e.getMessage() + ". VCS root uses a custom clone dir, manual recovery is required.", e); @@ -600,13 +619,26 @@ + workingDir.getAbsolutePath() + ". Clone it again, attempts left " + attemptsLeft); myMirrorManager.forgetDir(workingDir); lastError = e; + } catch (PathIllegalComponentException e) { + final StringBuilder logMessage = new StringBuilder("Pull failed because of illegal path component ").append(e.getComponent()) + .append(" for repository ").append(root.getRepository()).append(" at ").append(workingDir.getAbsolutePath()).append("."); + if (myConfig.retryPullForIllegalPathComponent()) { + logMessage.append(" Retrying with pull from tip revision, attempts left ").append(attemptsLeft); + pullFromTip = true; + } + Loggers.VCS.warn(logMessage.toString()); + lastError = e; } } throw lastError; } - private T syncRepositoryOnce(@NotNull HgVcsRoot root, @NotNull SyncSettings settings, @NotNull File workingDir, @Nullable OperationContext context) throws VcsException { + private T syncRepositoryOnce(@NotNull HgVcsRoot root, + @NotNull SyncSettings settings, + @NotNull File workingDir, + @Nullable OperationContext context, + boolean fromTip) throws VcsException { lockWorkDir(workingDir, settings.getProgressConsumer()); HgRepo repo = context != null ? context.createRepo(root) : createRepo(root); try { @@ -615,10 +647,13 @@ repo.setDefaultPath(root.getRepository()); repo.setTeamCityConfig(root.getCustomHgConfigServer()); resetBookmarks(repo); - repo.pull().fromRepository(root.getRepository()) + final PullCommand pullCommand = repo.pull().fromRepository(root.getRepository()) .withTimeout(myConfig.getPullTimeout()) - .withProfile(myConfig.runWithProfile(root)) - .call(); + .withProfile(myConfig.runWithProfile(root)); + if (fromTip) { + pullCommand.withNamedRevision("tip"); + } + pullCommand.call(); return settings.getCmd().call(); } finally { unlockWorkDir(workingDir); diff -r 53998d708051 -r 7f82951e9391 mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerHgRepo.java --- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerHgRepo.java Tue Oct 17 12:52:06 2023 +0200 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerHgRepo.java Wed Oct 18 13:30:24 2023 +0200 @@ -37,6 +37,7 @@ public class ServerHgRepo extends HgRepo { public final static HgVersion REVSET_HG_VERSION = new HgVersion(1, 7, 0); + public final static HgVersion MERGE_WITHOUT_CHANGED_FILES_VERSION = new HgVersion(5, 2, 0); private final CommandSettingsFactory myCommandSettingsFactory; private final ServerPluginConfig myConfig; protected final MercurialClasspathTemplate myLogTemplate = new MercurialClasspathTemplate("/buildServerResources/log.template", "hg.log.template"); @@ -99,6 +100,12 @@ return hgVersion.isEqualsOrGreaterThan(REVSET_HG_VERSION); } + // mercurial > 5.1 no longer reports changed files for the merge commits, see https://youtrack.jetbrains.com/issue/TW-79815 + public boolean supportsChangedFilesForMerges() throws VcsException { + HgVersion hgVersion = getHgVersion(); + return hgVersion.isLessThan(MERGE_WITHOUT_CHANGED_FILES_VERSION); + } + private HgVersion getHgVersion() throws VcsException { if (myContext != null) return myContext.getHgVersion(this); diff -r 53998d708051 -r 7f82951e9391 mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerPluginConfig.java --- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerPluginConfig.java Tue Oct 17 12:52:06 2023 +0200 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerPluginConfig.java Wed Oct 18 13:30:24 2023 +0200 @@ -61,4 +61,6 @@ boolean runWithProfile(@NotNull HgVcsRoot root); boolean computeFromRevisions(); + + boolean retryPullForIllegalPathComponent(); } diff -r 53998d708051 -r 7f82951e9391 mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerPluginConfigImpl.java --- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerPluginConfigImpl.java Tue Oct 17 12:52:06 2023 +0200 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerPluginConfigImpl.java Wed Oct 18 13:30:24 2023 +0200 @@ -133,4 +133,8 @@ public boolean computeFromRevisions() { return TeamCityProperties.getBooleanOrTrue("teamcity.hg.computeFromRevisions"); } + + public boolean retryPullForIllegalPathComponent() { + return TeamCityProperties.getBooleanOrTrue("teamcity.hg.retryPullForIllegalPathComponent"); + } } diff -r 53998d708051 -r 7f82951e9391 mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CollectChangesWithRevsets.java --- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CollectChangesWithRevsets.java Tue Oct 17 12:52:06 2023 +0200 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CollectChangesWithRevsets.java Wed Oct 18 13:30:24 2023 +0200 @@ -52,9 +52,22 @@ revsets.append(" + ").append(from); } } - return myRepo.log(myRoot) + List result = myRepo.log(myRoot) .showCommitsFromAllBranches() .withRevsets(revsets.toString()) .call(); + + if (!myRepo.supportsChangedFilesForMerges()) { + for (ChangeSet cs: result) { + if (cs.getParents().size() > 1) { + // new version of Mercurial does not include merge commit changed files into the log + // let's fetch the files with a separate command (https://youtrack.jetbrains.com/issue/TW-79815) + final List files = myRepo.status().fromRevision(cs.getParents().get(0).getId()).toRevision(cs.getId()).call(); + cs.setModifiedFiles(files); + } + } + } + + return result; } } diff -r 53998d708051 -r 7f82951e9391 mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutWithSharedMirrorsTest.java --- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutWithSharedMirrorsTest.java Tue Oct 17 12:52:06 2023 +0200 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutWithSharedMirrorsTest.java Wed Oct 18 13:30:24 2023 +0200 @@ -16,6 +16,7 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; +import com.intellij.openapi.util.SystemInfo; import jetbrains.buildServer.agent.AgentRunningBuild; import jetbrains.buildServer.agent.BuildAgentConfiguration; import jetbrains.buildServer.agent.BuildProgressLogger; @@ -32,6 +33,7 @@ import org.jetbrains.annotations.NotNull; import org.jmock.Expectations; import org.jmock.Mockery; +import org.testng.SkipException; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -114,6 +116,11 @@ public void turn_off_sharing() throws Exception { + // TODO: TW-84326: share extension doesn't work as expected on ARM agents + if (SystemInfo.isARM64) { + throw new SkipException("Ignore test on ARM64 machine"); + } + File myR1Dir = copy(new File("mercurial-tests/testData/subrepos/r1")); copy(new File("mercurial-tests/testData/subrepos/r2")); copy(new File("mercurial-tests/testData/subrepos/r3")); diff -r 53998d708051 -r 7f82951e9391 mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialSupportBuilder.java --- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialSupportBuilder.java Tue Oct 17 12:52:06 2023 +0200 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialSupportBuilder.java Wed Oct 18 13:30:24 2023 +0200 @@ -68,7 +68,6 @@ return vcs; } - public MercurialSupportBuilder withConfig(@NotNull ServerPluginConfig config) { myConfig = config; return this; diff -r 53998d708051 -r 7f82951e9391 mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java --- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java Tue Oct 17 12:52:06 2023 +0200 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java Wed Oct 18 13:30:24 2023 +0200 @@ -17,6 +17,7 @@ import com.intellij.openapi.util.SystemInfo; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.PathIllegalComponentException; import jetbrains.buildServer.util.FileUtil; import jetbrains.buildServer.util.TestFor; import jetbrains.buildServer.vcs.*; @@ -809,6 +810,26 @@ CheckoutRules.DEFAULT); } + @TestFor(issues = "TW-83599") + public void should_retry_pull_on_illegal_path_component() throws Exception { + final VcsRootImpl vcsRoot = createVcsRoot(simpleRepo()); + // we can't realiably force illegal path component errors with real hg repos + final RepoFactory failOnceRepoFactory = failOnceRepoFactory(new PathIllegalComponentException("some-component")); + myVcs = mercurialSupport().withConfig(myPluginConfig).withRepoFactory(failOnceRepoFactory).build(); + + myVcs.syncRepository(vcsRoot); + } + + @TestFor(issues = "TW-83599") + public void get_content_should_retry_pull_on_illegal_path_component() throws IOException, VcsException { + VcsRootImpl vcsRoot = createVcsRoot(simpleRepo()); + // we can't realiably force illegal path component errors with real hg repos + final RepoFactory failOnceRepoFactory = failOnceRepoFactory(new PathIllegalComponentException("some-component")); + myVcs = mercurialSupport().withConfig(myPluginConfig).withRepoFactory(failOnceRepoFactory).build(); + + byte[] content = myVcs.getContent("dir1/subdir/file2.txt", vcsRoot, "4:b06a290a363b"); + assertEquals(new String(content), "bbb"); + } private void assertFiles(final List expectedFiles, final ModificationData modificationData) { Set actualFiles = new HashSet<>(); @@ -838,5 +859,36 @@ public void test_collect_changes_using_checkout_rules() { assertTrue(myVcs.getCollectChangesPolicy() instanceof CollectChangesByCheckoutRules); } + + @NotNull + private RepoFactory failOnceRepoFactory(@NotNull VcsException failure) throws IOException { + final CommandSettingsForRootImpl commandSettingsFactory = new CommandSettingsForRootImpl(new TestCommandSettingsFactory(), new ExtensionsWeaver(), new CommandlineViaFileWrapperWeaver()); + + return new RepoFactory(myPluginConfig, commandSettingsFactory, myHgPathProvider) { + private boolean myDidFail = false; + + @NotNull + @Override + public ServerHgRepo createRepo(@NotNull HgVcsRoot root, @NotNull File workingDir) throws VcsException { + if (myDidFail) { + return super.createRepo(root, workingDir); + } else { + myDidFail = true; + final CommandSettingsFactory rootSettingsFactory = commandSettingsFactory.forRoot(root); + return new ServerHgRepo(rootSettingsFactory, myConfig, workingDir, myHgPathProvider.getHgPath(root), root.getAuthSettings()) { + @Override + public PullCommand pull() { + return new PullCommand(rootSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings) { + @Override + public void call() throws VcsException { + throw failure; + } + }; + } + }; + } + } + }; + } } diff -r 53998d708051 -r 7f82951e9391 mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerPluginConfigBuilder.java --- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerPluginConfigBuilder.java Tue Oct 17 12:52:06 2023 +0200 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerPluginConfigBuilder.java Wed Oct 18 13:30:24 2023 +0200 @@ -115,6 +115,10 @@ public boolean computeFromRevisions() { return true; } + + public boolean retryPullForIllegalPathComponent() { + return true; + } }; } diff -r 53998d708051 -r 7f82951e9391 mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandResultTest.java --- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandResultTest.java Tue Oct 17 12:52:06 2023 +0200 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandResultTest.java Wed Oct 18 13:30:24 2023 +0200 @@ -21,6 +21,7 @@ import jetbrains.buildServer.ExecResult; import jetbrains.buildServer.StreamGobbler; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.AbandonedTransactionFound; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.PathIllegalComponentException; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.UnknownRevisionException; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.UnrelatedRepositoryException; import jetbrains.buildServer.util.TestFor; @@ -136,6 +137,16 @@ } } + public void should_detect_illegal_path_component() throws VcsException { + final CommandResult commandResult = commandResultFor(execResult().withStderr("abort: path contains illegal component: /_mercurial_classpath_template.java.i")); + try { + commandResult.checkCommandFailed(); + fail("expected PathIllegalComponentException to be thrown"); + } catch (PathIllegalComponentException e) { + assertEquals("/_mercurial_classpath_template.java.i", e.getComponent()); + } + } + public void exception_should_not_contain_command_stdout_or_stderr() { final String stdout = "300Mb of output"; final String stderr = "300Mb from stderr";