Ignore package-level licenses on config_setting.

config_setting reflects build artifacts which we typically don't consider as part of licensing for third-party packages, and doesn't directly impact the output binary.  As a result, it's more likely that a package-level setting interferes with determining licensing of a binary.

RELNOTES: Ignore package-level licenses on config_setting.
PiperOrigin-RevId: 231298026
diff --git a/src/main/java/com/google/devtools/build/lib/packages/Rule.java b/src/main/java/com/google/devtools/build/lib/packages/Rule.java
index 0c805da..ae01bd2 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/Rule.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/Rule.java
@@ -648,6 +648,8 @@
     if (isAttrDefined("licenses", BuildType.LICENSE)
         && isAttributeValueExplicitlySpecified("licenses")) {
       return NonconfigurableAttributeMapper.of(this).get("licenses", BuildType.LICENSE);
+    } else if (getRuleClassObject().ignorePackageLicenses()) {
+      return License.NO_LICENSE;
     } else {
       return getPackage().getDefaultLicense();
     }
diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
index 1af192c..c5152ed 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
@@ -647,6 +647,7 @@
     private boolean isAnalysisTest = false;
     private boolean isConfigMatcher = false;
     private boolean hasFunctionTransitionWhitelist = false;
+    private boolean ignorePackageLicenses = false;
     private ImplicitOutputsFunction implicitOutputsFunction = ImplicitOutputsFunction.NONE;
     private RuleTransitionFactory transitionFactory;
     private ConfiguredTargetFactory<?, ?, ?> configuredTargetFactory = null;
@@ -808,6 +809,7 @@
           isExecutableSkylark,
           isAnalysisTest,
           hasFunctionTransitionWhitelist,
+          ignorePackageLicenses,
           implicitOutputsFunction,
           isConfigMatcher,
           transitionFactory,
@@ -1201,6 +1203,16 @@
       return this;
     }
 
+    /** This rule class ignores package-level licenses. */
+    public Builder setIgnorePackageLicenses() {
+      this.ignorePackageLicenses = true;
+      return this;
+    }
+
+    public boolean ignorePackageLicenses() {
+      return this.ignorePackageLicenses;
+    }
+
     public RuleClassType getType() {
       return this.type;
     }
@@ -1380,6 +1392,7 @@
   private final boolean isAnalysisTest;
   private final boolean isConfigMatcher;
   private final boolean hasFunctionTransitionWhitelist;
+  private final boolean ignorePackageLicenses;
 
   /**
    * A (unordered) mapping from attribute names to small integers indexing into
@@ -1507,6 +1520,7 @@
       boolean isExecutableSkylark,
       boolean isAnalysisTest,
       boolean hasFunctionTransitionWhitelist,
+      boolean ignorePackageLicenses,
       ImplicitOutputsFunction implicitOutputsFunction,
       boolean isConfigMatcher,
       RuleTransitionFactory transitionFactory,
@@ -1556,6 +1570,7 @@
     this.isExecutableSkylark = isExecutableSkylark;
     this.isAnalysisTest = isAnalysisTest;
     this.hasFunctionTransitionWhitelist = hasFunctionTransitionWhitelist;
+    this.ignorePackageLicenses = ignorePackageLicenses;
     this.configurationFragmentPolicy = configurationFragmentPolicy;
     this.supportsConstraintChecking = supportsConstraintChecking;
     this.requiredToolchains = ImmutableSet.copyOf(requiredToolchains);
@@ -2072,6 +2087,10 @@
    */
   private static void checkThirdPartyRuleHasLicense(Rule rule,
       Package.Builder pkgBuilder, EventHandler eventHandler) {
+    if (rule.getRuleClassObject().ignorePackageLicenses()) {
+      // A package license is sufficient; ignore rules that don't include it.
+      return;
+    }
     if (isThirdPartyPackage(rule.getLabel().getPackageIdentifier())) {
       License license = rule.getLicense();
       if (license == null) {
@@ -2408,6 +2427,11 @@
     return hasFunctionTransitionWhitelist;
   }
 
+  /** Returns true if this rule class should ignore package-level licenses. */
+  public boolean ignorePackageLicenses() {
+    return ignorePackageLicenses;
+  }
+
   public ImmutableSet<Label> getRequiredToolchains() {
     return requiredToolchains;
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/config/ConfigRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/config/ConfigRuleClasses.java
index bf5e9db..fdb00ec 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/config/ConfigRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/config/ConfigRuleClasses.java
@@ -139,6 +139,7 @@
     @Override
     public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) {
       return builder
+          .setIgnorePackageLicenses()
           .requiresConfigurationFragments(PlatformConfiguration.class)
           .add(
               attr(TOOLS_REPOSITORY_ATTRIBUTE, STRING)
diff --git a/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java b/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java
index 85ba7fc..c43ff8a 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java
@@ -888,6 +888,7 @@
         outputsDefaultExecutable,
         isAnalysisTest,
         /* hasFunctionTransitionWhitelist=*/ false,
+        /* ignorePackageLicenses=*/ false,
         implicitOutputsFunction,
         /*isConfigMatcher=*/ false,
         transitionFactory,
diff --git a/src/test/java/com/google/devtools/build/lib/rules/config/ConfigSettingTest.java b/src/test/java/com/google/devtools/build/lib/rules/config/ConfigSettingTest.java
index ffe0bc6..1a11fa0 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/config/ConfigSettingTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/config/ConfigSettingTest.java
@@ -26,6 +26,7 @@
 import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.RepositoryName;
+import com.google.devtools.build.lib.packages.License.LicenseType;
 import com.google.devtools.build.lib.packages.Rule;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
 import com.google.devtools.build.lib.testutil.TestConstants;
@@ -37,6 +38,7 @@
 import com.google.devtools.common.options.OptionMetadataTag;
 import com.google.devtools.common.options.OptionsParser;
 import java.util.Map;
+import java.util.Set;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -1426,5 +1428,70 @@
         "    ],",
         ");");
   }
-}
 
+  private Set<LicenseType> getLicenses(String label) throws Exception {
+    return getTarget(label).getLicense().getLicenseTypes();
+  }
+
+  /** Tests that default license behavior is unaffected. */
+  @Test
+  public void licensesDefault() throws Exception {
+    scratch.file(
+        "test/BUILD",
+        "config_setting(",
+        "    name = 'match',",
+        "    values = {",
+        "        'copt': '-Dfoo',",
+        "    })");
+
+    useConfiguration("--copt", "-Dfoo");
+    assertThat(getLicenses("//test:match")).containsExactly(LicenseType.NONE);
+  }
+
+  /** Tests that third-party doesn't require a license from config_setting. */
+  @Test
+  public void thirdPartyLicenseRequirement() throws Exception {
+    scratch.file(
+        "third_party/test/BUILD",
+        "config_setting(",
+        "    name = 'match',",
+        "    values = {",
+        "        'copt': '-Dfoo',",
+        "    })");
+
+    useConfiguration("--copt", "-Dfoo");
+    assertThat(getLicenses("//third_party/test:match")).containsExactly(LicenseType.NONE);
+  }
+
+  /** Tests that package-wide licenses are ignored by config_setting. */
+  @Test
+  public void packageLicensesIgnored() throws Exception {
+    scratch.file(
+        "test/BUILD",
+        "licenses(['restricted'])",
+        "config_setting(",
+        "    name = 'match',",
+        "    values = {",
+        "        'copt': '-Dfoo',",
+        "    })");
+
+    useConfiguration("--copt", "-Dfoo");
+    assertThat(getLicenses("//test:match")).containsExactly(LicenseType.NONE);
+  }
+
+  /** Tests that rule-specific licenses are still used by config_setting. */
+  @Test
+  public void ruleLicensesUsed() throws Exception {
+    scratch.file(
+        "test/BUILD",
+        "config_setting(",
+        "    name = 'match',",
+        "    licenses = ['restricted'],",
+        "    values = {",
+        "        'copt': '-Dfoo',",
+        "    })");
+
+    useConfiguration("--copt", "-Dfoo");
+    assertThat(getLicenses("//test:match")).containsExactly(LicenseType.RESTRICTED);
+  }
+}