Search in sources :

Example 6 with EmptyChangeException

use of com.google.copybara.exception.EmptyChangeException in project copybara by google.

the class GitHubPrOrigin method newReader.

@Override
public Reader<GitRevision> newReader(Glob originFiles, Authoring authoring) throws ValidationException {
    return new ReaderImpl(url, originFiles, authoring, gitOptions, gitOriginOptions, generalOptions, /*includeBranchCommitLogs=*/
    false, submoduleStrategy, firstParent, partialFetch, patchTransformation, describeVersion, /*configPath=*/
    null, /*workflowName=*/
    null) {

        /**
         * Disable rebase since this is controlled by useMerge field.
         */
        @Override
        protected void maybeRebase(GitRepository repo, GitRevision ref, Path workdir) throws RepoException, CannotResolveRevisionException {
        }

        @Override
        public Optional<Baseline<GitRevision>> findBaseline(GitRevision startRevision, String label) throws RepoException, ValidationException {
            if (!baselineFromBranch) {
                return super.findBaseline(startRevision, label);
            }
            return findBaselinesWithoutLabel(startRevision, /*limit=*/
            1).stream().map(e -> new Baseline<>(e.getSha1(), e)).findFirst();
        }

        @Override
        public ImmutableList<GitRevision> findBaselinesWithoutLabel(GitRevision startRevision, int limit) throws RepoException, ValidationException {
            String baseline = Iterables.getLast(startRevision.associatedLabels().get(GITHUB_BASE_BRANCH_SHA1), null);
            checkNotNull(baseline, "%s label should be present in %s", GITHUB_BASE_BRANCH_SHA1, startRevision);
            GitRevision baselineRev = getRepository().resolveReference(baseline);
            // Don't skip the first change as it is already the baseline
            BaselinesWithoutLabelVisitor<GitRevision> visitor = new BaselinesWithoutLabelVisitor<>(originFiles, limit, /*skipFirst=*/
            false);
            visitChanges(baselineRev, visitor);
            return visitor.getResult();
        }

        @Override
        public Endpoint getFeedbackEndPoint(Console console) throws ValidationException {
            gitHubOptions.validateEndpointChecker(endpointChecker);
            return new GitHubEndPoint(gitHubOptions.newGitHubApiSupplier(url, endpointChecker, ghHost), url, console, ghHost);
        }

        /**
         * Deal with the case of useMerge. We have a new commit (the merge) and first-parent from that
         * commit doesn't work for this case.
         */
        @Override
        public ChangesResponse<GitRevision> changes(@Nullable GitRevision fromRef, GitRevision toRef) throws RepoException, ValidationException {
            checkCondition(toRef.associatedLabels().containsKey(GITHUB_PR_USE_MERGE), "Cannot determine whether 'use_merge' was set.");
            if (toRef.associatedLabel(GITHUB_PR_USE_MERGE).contains("false")) {
                return super.changes(fromRef, toRef);
            }
            GitLogEntry merge = Iterables.getOnlyElement(getRepository().log(toRef.getSha1()).withLimit(1).run());
            // Fast-forward merge
            if (merge.getParents().size() == 1) {
                return super.changes(fromRef, toRef);
            }
            // HEAD of the Pull Request
            GitRevision gitRevision = merge.getParents().get(1);
            ChangesResponse<GitRevision> prChanges = super.changes(fromRef, gitRevision);
            // origin_files
            if (prChanges.isEmpty()) {
                return prChanges;
            }
            try {
                return ChangesResponse.forChanges(ImmutableList.<Change<GitRevision>>builder().addAll(prChanges.getChanges()).add(change(merge.getCommit())).build());
            } catch (EmptyChangeException e) {
                throw new RepoException("Error getting the merge commit information: " + merge, e);
            }
        }
    };
}
Also used : Path(java.nio.file.Path) GitHubUtil.asHeadRef(com.google.copybara.git.github.util.GitHubUtil.asHeadRef) Origin(com.google.copybara.Origin) CombinedStatus(com.google.copybara.git.github.api.CombinedStatus) Collections2(com.google.common.collect.Collections2) Review(com.google.copybara.git.github.api.Review) ImmutableListMultimap.toImmutableListMultimap(com.google.common.collect.ImmutableListMultimap.toImmutableListMultimap) Matcher(java.util.regex.Matcher) Change(com.google.copybara.Change) BaselinesWithoutLabelVisitor(com.google.copybara.BaselinesWithoutLabelVisitor) CannotResolveRevisionException(com.google.copybara.exception.CannotResolveRevisionException) Endpoint(com.google.copybara.Endpoint) Splitter(com.google.common.base.Splitter) GeneralOptions(com.google.copybara.GeneralOptions) Path(java.nio.file.Path) ImmutableSetMultimap(com.google.common.collect.ImmutableSetMultimap) User(com.google.copybara.git.github.api.User) ProfilerTask(com.google.copybara.profiler.Profiler.ProfilerTask) ImmutableSet(com.google.common.collect.ImmutableSet) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) Set(java.util.Set) Collectors(java.util.stream.Collectors) Collectors.joining(java.util.stream.Collectors.joining) Sets(com.google.common.collect.Sets) Objects(java.util.Objects) List(java.util.List) GitHubApi(com.google.copybara.git.github.api.GitHubApi) PullRequest(com.google.copybara.git.github.api.PullRequest) GitHubUtil.asMergeRef(com.google.copybara.git.github.util.GitHubUtil.asMergeRef) ImmutableListMultimap(com.google.common.collect.ImmutableListMultimap) AutoValue(com.google.auto.value.AutoValue) Optional(java.util.Optional) Joiner(com.google.common.base.Joiner) AuthorAssociation(com.google.copybara.git.github.api.AuthorAssociation) Iterables(com.google.common.collect.Iterables) CheckRuns(com.google.copybara.git.github.api.CheckRuns) ValidationException.checkCondition(com.google.copybara.exception.ValidationException.checkCondition) RepoException(com.google.copybara.exception.RepoException) SubmoduleStrategy(com.google.copybara.git.GitOrigin.SubmoduleStrategy) HashSet(java.util.HashSet) GitHubUtil(com.google.copybara.git.github.util.GitHubUtil) Label(com.google.copybara.git.github.api.Label) State(com.google.copybara.git.github.api.Status.State) ImmutableList(com.google.common.collect.ImmutableList) Issue(com.google.copybara.git.github.api.Issue) Nullable(javax.annotation.Nullable) GitLogEntry(com.google.copybara.git.GitRepository.GitLogEntry) Uninterruptibles(com.google.common.util.concurrent.Uninterruptibles) EmptyChangeException(com.google.copybara.exception.EmptyChangeException) Preconditions.checkNotNull(com.google.common.base.Preconditions.checkNotNull) CharMatcher(com.google.common.base.CharMatcher) ValidationException(com.google.copybara.exception.ValidationException) ReaderImpl(com.google.copybara.git.GitOrigin.ReaderImpl) PatchTransformation(com.google.copybara.transform.patch.PatchTransformation) Console(com.google.copybara.util.console.Console) TimeUnit(java.util.concurrent.TimeUnit) Authoring(com.google.copybara.authoring.Authoring) Checker(com.google.copybara.checks.Checker) Glob(com.google.copybara.util.Glob) CheckRun(com.google.copybara.git.github.api.CheckRun) Preconditions(com.google.common.base.Preconditions) Status(com.google.copybara.git.github.api.Status) GitHubHost(com.google.copybara.git.github.util.GitHubHost) GitHubPrUrl(com.google.copybara.git.github.util.GitHubHost.GitHubPrUrl) VisibleForTesting(com.google.common.annotations.VisibleForTesting) Collections(java.util.Collections) ReaderImpl(com.google.copybara.git.GitOrigin.ReaderImpl) Change(com.google.copybara.Change) RepoException(com.google.copybara.exception.RepoException) Console(com.google.copybara.util.console.Console) BaselinesWithoutLabelVisitor(com.google.copybara.BaselinesWithoutLabelVisitor) EmptyChangeException(com.google.copybara.exception.EmptyChangeException) Nullable(javax.annotation.Nullable) GitLogEntry(com.google.copybara.git.GitRepository.GitLogEntry)

Example 7 with EmptyChangeException

use of com.google.copybara.exception.EmptyChangeException in project copybara by google.

the class GitRepository method commit.

// TODO(malcon): Create a CommitCmd object builder
public void commit(@Nullable String author, boolean amend, @Nullable ZonedDateTime timestamp, String message) throws RepoException, ValidationException {
    if (isEmptyStaging() && !amend) {
        String baseline = "unknown";
        try {
            baseline = parseRef("HEAD");
        } catch (CannotResolveRevisionException | RepoException e) {
            logger.atWarning().withCause(e).log("Cannot find baseline.");
        }
        throw new EmptyChangeException(String.format("Migration of the revision resulted in an empty change from baseline '%s'.\n" + "Is the change already migrated?", baseline));
    }
    ImmutableList.Builder<String> params = ImmutableList.<String>builder().add("commit");
    if (author != null) {
        params.add("--author", author);
    }
    if (timestamp != null) {
        params.add("--date", timestamp.format(ISO_OFFSET_DATE_TIME_NO_SUBSECONDS));
    }
    if (amend) {
        params.add("--amend");
    }
    if (noVerify) {
        params.add("--no-verify");
    }
    Path descriptionFile = null;
    try {
        if (message.getBytes(StandardCharsets.UTF_8).length > ARBITRARY_MAX_ARG_SIZE) {
            descriptionFile = getCwd().resolve(UUID.randomUUID().toString() + ".desc");
            Files.write(descriptionFile, message.getBytes(StandardCharsets.UTF_8));
            params.add("-F", descriptionFile.toAbsolutePath().toString());
        } else {
            params.add("-m", message);
        }
        git(getCwd(), addGitDirAndWorkTreeParams(params.build()));
    } catch (IOException e) {
        throw new RepoException("Could not commit change: Failed to write file " + descriptionFile, e);
    } finally {
        try {
            if (descriptionFile != null) {
                Files.deleteIfExists(descriptionFile);
            }
        } catch (IOException e) {
            logger.atWarning().log("Could not delete description file: %s", descriptionFile);
        }
    }
}
Also used : Path(java.nio.file.Path) ImmutableList(com.google.common.collect.ImmutableList) CannotResolveRevisionException(com.google.copybara.exception.CannotResolveRevisionException) EmptyChangeException(com.google.copybara.exception.EmptyChangeException) RepoException(com.google.copybara.exception.RepoException) IOException(java.io.IOException)

Example 8 with EmptyChangeException

use of com.google.copybara.exception.EmptyChangeException in project copybara by google.

the class Mirror method run.

@Override
public void run(Path workdir, ImmutableList<String> sourceRefs) throws RepoException, IOException, ValidationException {
    try (ProfilerTask ignore = generalOptions.profiler().start("run/" + name)) {
        GitRepository repo = gitOptions.cachedBareRepoForUrl(origin);
        if (Iterables.isEmpty(actions)) {
            defaultMirror(repo);
        } else {
            ImmutableList.Builder<ActionResult> allResultsBuilder = ImmutableList.builder();
            for (Action action : actions) {
                GitMirrorContext context = new GitMirrorContext(action, new SkylarkConsole(generalOptions.console()), sourceRefs, refspec, origin, destination, generalOptions.isForced(), repo, generalOptions.getDirFactory(), Dict.empty());
                try {
                    action.run(context);
                    ActionResult actionResult = context.getActionResult();
                    allResultsBuilder.add(actionResult);
                    // First error aborts the execution of the other actions unless --force is used
                    ValidationException.checkCondition(generalOptions.isForced() || actionResult.getResult() != Result.ERROR, "Feedback migration '%s' action '%s' returned error: %s. Aborting execution.", name, action.getName(), actionResult.getMsg());
                } catch (NonFastForwardRepositoryException e) {
                    allResultsBuilder.add(ActionResult.error(action.getName() + ": " + e.getMessage()));
                    if (!generalOptions.isForced()) {
                        throw e;
                    }
                    logger.atWarning().withCause(e).log();
                } finally {
                    generalOptions.eventMonitors().dispatchEvent(m -> m.onChangeMigrationFinished(new ChangeMigrationFinishedEvent(ImmutableList.copyOf(context.getNewDestinationEffects()), getOriginDescription(), getDestinationDescription())));
                }
            }
            ImmutableList<ActionResult> allResults = allResultsBuilder.build();
            if (allResults.stream().anyMatch(a -> a.getResult() == Result.ERROR)) {
                String errors = allResults.stream().filter(a -> a.getResult() == Result.ERROR).map(ActionResult::getMsg).collect(Collectors.joining("\n - "));
                throw new ValidationException("One or more errors happened during the migration:\n" + " - " + errors);
            }
            // This check also returns true if there are no actions
            if (allResults.stream().allMatch(a -> a.getResult() == Result.NO_OP)) {
                String detailedMessage = allResults.isEmpty() ? "actions field is empty" : allResults.stream().map(ActionResult::getMsg).collect(ImmutableList.toImmutableList()).toString();
                throw new EmptyChangeException(String.format("git.mirror migration '%s' was noop. Detailed messages: %s", name, detailedMessage));
            }
        }
    }
    // More fine grain events based on the references created/updated/deleted:
    ChangeMigrationFinishedEvent event = new ChangeMigrationFinishedEvent(ImmutableList.of(new DestinationEffect(generalOptions.dryRunMode ? DestinationEffect.Type.NOOP : DestinationEffect.Type.UPDATED, generalOptions.dryRunMode ? "Refspecs " + refspec + " can be mirrored" : "Refspecs " + refspec + " mirrored successfully", // TODO(danielromero): Populate OriginRef here
    ImmutableList.of(), new DestinationRef(getOriginDestinationRef(destination), "mirror", /*url=*/
    null))), getOriginDescription(), getDestinationDescription());
    generalOptions.eventMonitors().dispatchEvent(m -> m.onChangeMigrationFinished(event));
}
Also used : Action(com.google.copybara.action.Action) ValidationException(com.google.copybara.exception.ValidationException) ChangeMigrationFinishedEvent(com.google.copybara.monitor.EventMonitor.ChangeMigrationFinishedEvent) ImmutableList(com.google.common.collect.ImmutableList) SkylarkConsole(com.google.copybara.transform.SkylarkConsole) ActionResult(com.google.copybara.action.ActionResult) DestinationRef(com.google.copybara.DestinationEffect.DestinationRef) ProfilerTask(com.google.copybara.profiler.Profiler.ProfilerTask) DestinationEffect(com.google.copybara.DestinationEffect) EmptyChangeException(com.google.copybara.exception.EmptyChangeException)

Example 9 with EmptyChangeException

use of com.google.copybara.exception.EmptyChangeException in project copybara by google.

the class SkylarkTransformation method transform.

@Override
public TransformationStatus transform(TransformWork work) throws IOException, ValidationException, RepoException {
    SkylarkConsole skylarkConsole = new SkylarkConsole(work.getConsole());
    TransformWork skylarkWork = work.withConsole(skylarkConsole).withParams(params);
    TransformationStatus status = TransformationStatus.success();
    try (Mutability mu = Mutability.create("dynamic_transform")) {
        StarlarkThread thread = new StarlarkThread(mu, StarlarkSemantics.DEFAULT);
        thread.setPrintHandler(printHandler);
        Object result = Starlark.call(thread, function, ImmutableList.of(skylarkWork), /*kwargs=*/
        ImmutableMap.of());
        result = result == Starlark.NONE ? TransformationStatus.success() : result;
        checkCondition(result instanceof TransformationStatus, "Dynamic transforms functions should return nothing or objects of type %s, but '%s'" + " returned: %s", TransformationStatus.STARLARK_TYPE_NAME, describe(), result);
        status = (TransformationStatus) result;
    } catch (EvalException e) {
        if (e.getCause() instanceof EmptyChangeException) {
            throw ((EmptyChangeException) e.getCause());
        }
        if (e.getCause() instanceof RepoException) {
            throw new RepoException(String.format("Error while executing the skylark transformation %s: %s", describe(), e.getMessageWithStack()), e);
        }
        throw new ValidationException(String.format("Error while executing the skylark transformation %s: %s", describe(), e.getMessageWithStack()), e);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        throw new RuntimeException("This should not happen.", e);
    } finally {
        work.updateFrom(skylarkWork);
    }
    checkCondition(skylarkConsole.getErrorCount() == 0, "%d error(s) while executing %s", skylarkConsole.getErrorCount(), describe());
    return status;
}
Also used : TransformationStatus(com.google.copybara.TransformationStatus) ValidationException(com.google.copybara.exception.ValidationException) NonReversibleValidationException(com.google.copybara.exception.NonReversibleValidationException) StarlarkThread(net.starlark.java.eval.StarlarkThread) TransformWork(com.google.copybara.TransformWork) Mutability(net.starlark.java.eval.Mutability) EmptyChangeException(com.google.copybara.exception.EmptyChangeException) EvalException(net.starlark.java.eval.EvalException) RepoException(com.google.copybara.exception.RepoException)

Example 10 with EmptyChangeException

use of com.google.copybara.exception.EmptyChangeException in project copybara by google.

the class WorkflowTest method testDryRunWithLocalGitPath.

/**
 * Regression test that checks that we reuse the same writer in dry-run mode for multiple
 * invocations inside the same migration so that state is kept.
 */
@Test
public void testDryRunWithLocalGitPath() throws Exception {
    Path originPath = Files.createTempDirectory("origin");
    Path destinationPath = Files.createTempDirectory("destination");
    GitRepository origin = GitRepository.newRepo(/*verbose*/
    true, originPath, getGitEnv()).init();
    GitRepository destination = GitRepository.newBareRepo(destinationPath, getGitEnv(), /*verbose=*/
    true, DEFAULT_TIMEOUT, /*noVerify=*/
    false).init();
    String primaryBranch = origin.getPrimaryBranch();
    String config = "core.workflow(" + "    name = 'default',\n" + "    origin = git.origin(\n" + "        url = 'file://" + origin.getWorkTree() + "',\n" + "        ref = '" + primaryBranch + "'\n" + "    ),\n" + "    destination = git.destination(" + "        url = 'file://" + destination.getGitDir() + "',\n" + "        push = '" + primaryBranch + "',\n" + "        fetch = '" + primaryBranch + "'\n" + "    ),\n" + "    authoring = " + authoring + ",\n" + "    mode = 'SQUASH',\n" + ")\n";
    addGitFile(originPath, origin, "foo.txt", "not important");
    commit(origin, "baseline\n\nOrigin-Label: 1234567");
    options.setWorkdirToRealTempDir();
    // Pass custom HOME directory so that we run an hermetic test and we
    // can add custom configuration to $HOME/.gitconfig.
    options.setEnvironment(GitTestUtil.getGitEnv().getEnvironment());
    options.setHomeDir(Files.createTempDirectory("home").toString());
    options.gitDestination.committerName = "Foo";
    options.gitDestination.committerEmail = "foo@foo.com";
    options.workflowOptions.initHistory = true;
    loadConfig(config).getMigration("default").run(Files.createTempDirectory("workdir"), ImmutableList.of());
    // Now run again with force and no changes so that it uses the default migrator (The affected
    // path
    options.gitDestination.localRepoPath = Files.createTempDirectory("temp").toString();
    options.workflowOptions.initHistory = false;
    options.general.dryRunMode = true;
    options.setForce(true);
    EmptyChangeException e = assertThrows(EmptyChangeException.class, () -> loadConfig(config).getMigration("default").run(Files.createTempDirectory("workdir"), ImmutableList.of()));
    assertThat(e).hasMessageThat().contains("Migration of the revision resulted in an empty change");
    assertThat(e).hasMessageThat().contains(destination.parseRef("HEAD"));
}
Also used : Path(java.nio.file.Path) FileSubjects.assertThatPath(com.google.copybara.testing.FileSubjects.assertThatPath) GitRepository(com.google.copybara.git.GitRepository) EmptyChangeException(com.google.copybara.exception.EmptyChangeException) Test(org.junit.Test)

Aggregations

EmptyChangeException (com.google.copybara.exception.EmptyChangeException)42 Test (org.junit.Test)27 ImmutableList (com.google.common.collect.ImmutableList)10 RepoException (com.google.copybara.exception.RepoException)10 ValidationException (com.google.copybara.exception.ValidationException)10 ProfilerTask (com.google.copybara.profiler.Profiler.ProfilerTask)10 Path (java.nio.file.Path)10 CannotResolveRevisionException (com.google.copybara.exception.CannotResolveRevisionException)8 Endpoint (com.google.copybara.Endpoint)7 VisibleForTesting (com.google.common.annotations.VisibleForTesting)5 CharMatcher (com.google.common.base.CharMatcher)5 Preconditions (com.google.common.base.Preconditions)5 Splitter (com.google.common.base.Splitter)5 Collections2 (com.google.common.collect.Collections2)5 ImmutableSetMultimap (com.google.common.collect.ImmutableSetMultimap)5 Iterables (com.google.common.collect.Iterables)5 Sets (com.google.common.collect.Sets)5 Uninterruptibles (com.google.common.util.concurrent.Uninterruptibles)5 BaselinesWithoutLabelVisitor (com.google.copybara.BaselinesWithoutLabelVisitor)5 Change (com.google.copybara.Change)5