All Downloads are FREE. Search and download functionalities are using the official Maven repository.

foundry.gradle.tasks.CheckDependencyVersionsTask.kt Maven / Gradle / Ivy

/*
 * Copyright (C) 2022 Slack Technologies, LLC
 *
 * 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
 *
 *    https://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 foundry.gradle.tasks

import foundry.gradle.capitalizeUS
import foundry.gradle.getVersionsCatalog
import foundry.gradle.properties.setDisallowChanges
import foundry.gradle.register
import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.MapProperty
import org.gradle.api.tasks.CacheableTask
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskProvider

/**
 * A task that checks expected versions (from [mappedIdentifiersToVersions]) against runtime
 * versions found in [identifiersToVersions].
 *
 * This is important to check for some dependencies pulling newer versions unexpectedly.
 */
@CacheableTask
public abstract class CheckDependencyVersionsTask : BaseDependencyCheckTask() {

  @get:Input public abstract val mappedIdentifiersToVersions: MapProperty

  // Only present for cacheability
  @get:OutputFile public abstract val outputFile: RegularFileProperty

  init {
    group = "verification"
  }

  override fun handleDependencies(identifiersToVersions: Map) {
    val identifierMap =
      mappedIdentifiersToVersions.get().filterValues {
        // Blank versions mean it's managed by a BOM and we don't need to check it here
        it.isNotBlank()
      }

    val actualVersions = identifiersToVersions.filterKeys { it in identifierMap }

    val issues =
      mutableListOf().apply {
        mappedIdentifiersToVersions.get().forEach { (identifier, declared) ->
          val actual = actualVersions[identifier] ?: return@forEach
          if (actual != declared) {
            this += "$identifier - declared $declared - actual $actual"
          }
        }
      }

    val issuesString = issues.joinToString("\n")
    if (issues.isNotEmpty()) {
      throw GradleException(
        "Mismatched dependency versions! Please update their versions in" +
          " libs.versions.toml to match their resolved versions.\n\n" +
          "${issuesString}\n\nIf you just updated a library, it may pull " +
          "in a newer version of a dependency that we separately specify in libs.versions.toml. " +
          "Keeping the versions in libs.versions.toml in sync with the final resolved versions " +
          "makes it easier to see what version of a library we depend on at a glance."
      )
    }

    outputFile.asFile.get().writeText("Issues:\n$issuesString")
  }

  public companion object {
    public fun register(
      project: Project,
      name: String,
      configuration: Configuration,
    ): TaskProvider {
      return project.tasks.register(
        "check${name.capitalizeUS()}Versions"
      ) {
        configureIdentifiersToVersions(configuration)
        outputFile.setDisallowChanges(
          project.layout.buildDirectory.file(
            "reports/foundry/dependencyVersionsIssues/$name/issues.txt"
          )
        )
        val catalog = project.getVersionsCatalog()
        this.mappedIdentifiersToVersions.putAll(
          project.provider {
            catalog.libraryAliases.associate {
              val dep = catalog.findLibrary(it).get().get()
              dep.module.toString() to dep.versionConstraint.toString()
            }
          }
        )
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy