Replacement for afterEvaluate in Gradle 5.1?

I have a plugin which conditionally adds a dependency on the task once it knows whether it actually depends on it.

I’m now trying to change the declaration to make use of lazy configuration.

I ended up with this:

project.getTasks()
    .register(sourceSet.getTaskName("checkStrings", null), CheckStrings.class, project)
    .configure(task -> {
        task.setDescription("...");

        File outputResourcesDir = sourceSet.getOutput().getResourcesDir();
        if (outputResourcesDir != null)
        {
            task.getResourceDirs().setFrom(outputResourcesDir);

            project.afterEvaluate(projectIgnored -> {
                // Adds dependency on source set output but only if its resources are being checked.
                if (task.getResourceDirs().contains(outputResourcesDir)) {
                    task.dependsOn(sourceSet.getOutput());
                }
            });

            checkStringsTask.dependsOn(task);
        }
    }));

This causes an error at build-time:

Project#afterEvaluate(Action) on root project ‘my-project’ cannot be executed in the current context.

I assume this is because I’m calling afterEvaluate after it was already evaluated. That’s fine - but what’s the alternative? I want to evaluate my block after any other configuration downstream code might have performed on the task.

1 Like

You are adding the project afterEvaluate closure configuration within the context of your task configuration closure. Not sure if that’s maybe the problem? Have you tried adding your afterEvaluate configuration closure at the root level?

So add a line before or after the first line, project.getTasks(), which invokes project.afterEvaluate and adds your configuration closure for your task. You will need to find the task reference again by using it’s name or type.

I am also using afterEvaluate in a custom gradle plugin as a first action before I configure anything else at a lower level and it works the way I need it to meaning any tasks or extensions I am customizing have already been evaluated and initialized for me. Although, I am using Gradle 5.0.

So, I tried that just now.

sourceSets.all(sourceSet -> {

    TaskProvider<CheckStrings> lazyTask = project.getTasks()
        .register(sourceSet.getTaskName("checkStrings", null), CheckStrings.class, project);

    lazyTask.configure(task -> {
        task.setDescription("Runs checks on '${sourceSet.name}' strings.");

        task.setIgnoreFailures(extension.getIgnoreFailures());
        task.setIgnoreMissingTranslations(extension.getIgnoreMissingTranslations());

        File outputResourcesDir = sourceSet.getOutput().getResourcesDir();
        if (outputResourcesDir != null) {
            task.getResourceDirs().setFrom(outputResourcesDir);
        }

        checkStringsTask.dependsOn(task);
    });

    project.afterEvaluate(projectIgnored ->
        lazyTask.configure(task -> {
            File outputResourcesDir = sourceSet.getOutput().getResourcesDir();
            if (outputResourcesDir != null) {
                if (task.getResourceDirs().contains(outputResourcesDir)) {
                    task.dependsOn(sourceSet.getOutput());
                }
            }
        }));
});

Now my test suite fails, because apparently the dependent task to process the source set’s resources is never run, so the task is run against an empty source set and spuriously succeeds. So I’m guessing that configuring a lazy task at afterEvaluate is too late? But I’d still expect lazyTask.configure to configure the task immediately even if it has already been created.