You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@maven.apache.org by GitBox <gi...@apache.org> on 2020/05/25 11:48:08 UTC

[GitHub] [maven-enforcer] elharo commented on a change in pull request #49: MENFORCER-245 Improve documentation about writing own Enforcer Rule

elharo commented on a change in pull request #49:
URL: https://github.com/apache/maven-enforcer/pull/49#discussion_r429891969



##########
File path: enforcer-api/src/site/apt/writing-a-custom-rule.apt.vm
##########
@@ -33,71 +33,50 @@ Writing a custom rule
   [[1]] First make a new jar project starting with the sample pom below:
   
 +---+
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-
-  <groupId>custom-rule</groupId>
-  <artifactId>custom-rule-sample</artifactId>
-  <packaging>jar</packaging>
-  <version>1.0</version>
-
-  <name>My Custom Rule</name>
-  <description>This is my custom rule.</description>
-
-  <properties>
-    <api.version>${project.version}</api.version>
-    <maven.version>2.0.9</maven.version>
-  </properties>
-
-  <dependencies>
-    <dependency>
-      <groupId>org.apache.maven.enforcer</groupId>
-      <artifactId>enforcer-api</artifactId>
-      <version>${api.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.maven</groupId>
-      <artifactId>maven-project</artifactId>
-      <version>${maven.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.maven</groupId>
-      <artifactId>maven-core</artifactId>
-      <version>${maven.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.maven</groupId>
-      <artifactId>maven-artifact</artifactId>
-      <version>${maven.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.maven</groupId>
-      <artifactId>maven-plugin-api</artifactId>
-      <version>${maven.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.codehaus.plexus</groupId>
-      <artifactId>plexus-container-default</artifactId>
-      <version>1.0-alpha-9</version>
-    </dependency>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <version>3.8.2</version>
-      <scope>test</scope>
-    </dependency>
-  </dependencies>
-
-  <build>
-  </build>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>custom-rule</groupId>
+    <artifactId>custom-rule-sample</artifactId>
+    <packaging>jar</packaging>
+    <version>1.0</version>
+    <name>My Custom Rule</name>
+    <description>This is my custom rule.</description>
+    <properties>
+        <api.version>${project.version}</api.version>
+        <maven.version>3.0</maven.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.maven.enforcer</groupId>
+            <artifactId>enforcer-api</artifactId>
+            <version>${api.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-core</artifactId>
+            <version>${maven.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-plugin-api</artifactId>
+            <version>${maven.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>3.8.1</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+    <build>
+    </build>
 </project>
 +---+
 
   [[2]] Create your rule class. The rule must implement the {{{./apidocs/index.html}EnforcerRule}} interface.
    The rule can get access to components and the log via the {{{./apidocs/index.html}EnforcerRuleHelper}} interface.
+   In addition, the rule must provide a setter method for each parameter allowed to be configured in the pom.xml file (like the shown in point 5).

Review comment:
       the shown?

##########
File path: enforcer-api/src/custom-rule-sample/pom.xml
##########
@@ -1,73 +1,58 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  * Licensed to the Apache Software Foundation (ASF) under one
-  * or more contributor license agreements.  See the NOTICE file
-  * distributed with this work for additional information
-  * regarding copyright ownership.  The ASF licenses this file
-  * to you 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. 
-  *
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-	<modelVersion>4.0.0</modelVersion>
-	<groupId>custom-rule</groupId>
-	<artifactId>custom-rule-sample</artifactId>
-	<packaging>jar</packaging>
-	<version>1.0</version>
-	<name>My Custom Rule</name>
-	<description>This is my custom rule.</description>
-	<properties>
-	  <api.version>1.0-beta-1</api.version>
-	  <maven.version>2.0.9</maven.version>
-	</properties>
-	<build>	
-	</build>
-	<dependencies>
-		<dependency>
-			<groupId>org.apache.maven.enforcer</groupId>
-			<artifactId>enforcer-api</artifactId>
-			<version>${api.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.maven</groupId>
-			<artifactId>maven-project</artifactId>
-			<version>${maven.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.maven</groupId>
-			<artifactId>maven-core</artifactId>
-			<version>${maven.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.maven</groupId>
-			<artifactId>maven-artifact</artifactId>
-			<version>${maven.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.maven</groupId>
-			<artifactId>maven-plugin-api</artifactId>
-			<version>${maven.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>org.codehaus.plexus</groupId>
-			<artifactId>plexus-container-default</artifactId>
-			<version>1.0-alpha-9</version>
-		</dependency>
-		<dependency>
-			<groupId>junit</groupId>
-			<artifactId>junit</artifactId>
-			<version>3.8.1</version>
-			<scope>test</scope>
-		</dependency>	
-	</dependencies>
-</project>
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  * Licensed to the Apache Software Foundation (ASF) under one
+  * or more contributor license agreements.  See the NOTICE file
+  * distributed with this work for additional information
+  * regarding copyright ownership.  The ASF licenses this file
+  * to you 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. 
+  *
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>

Review comment:
       convention for XML files in Maven is two space indents

##########
File path: enforcer-api/src/custom-rule-sample/src/main/java/org/apache/maven/enforcer/rule/MyCustomRule.java
##########
@@ -1,120 +1,131 @@
-package org.apache.maven.enforcer.rule;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
- */
-
-import org.apache.maven.artifact.resolver.ArtifactResolver;
-import org.apache.maven.enforcer.rule.api.EnforcerRule;
-import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
-import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
-import org.apache.maven.execution.MavenSession;
-import org.apache.maven.execution.RuntimeInformation;
-import org.apache.maven.plugin.logging.Log;
-import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
-import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
-
-/**
- * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
- */
-public class MyCustomRule
-    implements EnforcerRule
-{
-    /**
-     * Simple param. This rule will fail if the value is true.
-     */
-    private boolean shouldIfail = false;
-
-    public void execute( EnforcerRuleHelper helper )
-        throws EnforcerRuleException
-    {
-        Log log = helper.getLog();
-
-        try
-        {
-            // get the various expressions out of the helper.
-            MavenProject project = (MavenProject) helper.evaluate( "${project}" );
-            MavenSession session = (MavenSession) helper.evaluate( "${session}" );
-            String target = (String) helper.evaluate( "${project.build.directory}" );
-            String artifactId = (String) helper.evaluate( "${project.artifactId}" );
-
-            // retreive any component out of the session directly
-            ArtifactResolver resolver = (ArtifactResolver) helper.getComponent( ArtifactResolver.class );
-            RuntimeInformation rti = (RuntimeInformation) helper.getComponent( RuntimeInformation.class );
-
-            log.info( "Retrieved Target Folder: " + target );
-            log.info( "Retrieved ArtifactId: " +artifactId );
-            log.info( "Retrieved Project: " + project );
-            log.info( "Retrieved RuntimeInfo: " + rti );
-            log.info( "Retrieved Session: " + session );
-            log.info( "Retrieved Resolver: " + resolver );
-
-            if ( this.shouldIfail )
-            {
-                throw new EnforcerRuleException( "Failing because my param said so." );
-            }
-        }
-        catch ( ComponentLookupException e )
-        {
-            throw new EnforcerRuleException( "Unable to lookup a component " + e.getLocalizedMessage(), e );
-        }
-        catch ( ExpressionEvaluationException e )
-        {
-            throw new EnforcerRuleException( "Unable to lookup an expression " + e.getLocalizedMessage(), e );
-        }
-    }
-
-    /**
-     * If your rule is cacheable, you must return a unique id when parameters or conditions
-     * change that would cause the result to be different. Multiple cached results are stored
-     * based on their id.
-     * 
-     * The easiest way to do this is to return a hash computed from the values of your parameters.
-     * 
-     * If your rule is not cacheable, then the result here is not important, you may return anything.
-     */
-    public String getCacheId()
-    {
-        //no hash on boolean...only parameter so no hash is needed.
-        return ""+this.shouldIfail;
-    }
-
-    /**
-     * This tells the system if the results are cacheable at all. Keep in mind that during
-     * forked builds and other things, a given rule may be executed more than once for the same
-     * project. This means that even things that change from project to project may still 
-     * be cacheable in certain instances.
-     */
-    public boolean isCacheable()
-    {
-        return false;
-    }
-
-    /**
-     * If the rule is cacheable and the same id is found in the cache, the stored results
-     * are passed to this method to allow double checking of the results. Most of the time 
-     * this can be done by generating unique ids, but sometimes the results of objects returned
-     * by the helper need to be queried. You may for example, store certain objects in your rule
-     * and then query them later.
-     */
-    public boolean isResultValid( EnforcerRule arg0 )
-    {
-        return false;
-    }
-}
+package org.apache.maven.enforcer.rule;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import org.apache.maven.ProjectDependenciesResolver;
+import org.apache.maven.enforcer.rule.api.EnforcerRule;
+import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
+import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+
+/**
+ * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
+ * @author <a href="mailto:belingueres@gmail.com">Gabriel Belingueres</a>
+ */
+public class MyCustomRule
+    implements EnforcerRule
+{
+    /**
+     * Simple param. This rule will fail if the value is true.

Review comment:
       will fail --> fails (tech writing lives in the eternal present)

##########
File path: enforcer-api/src/custom-rule-sample/src/main/java/org/apache/maven/enforcer/rule/MyCustomRule.java
##########
@@ -1,120 +1,131 @@
-package org.apache.maven.enforcer.rule;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
- */
-
-import org.apache.maven.artifact.resolver.ArtifactResolver;
-import org.apache.maven.enforcer.rule.api.EnforcerRule;
-import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
-import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
-import org.apache.maven.execution.MavenSession;
-import org.apache.maven.execution.RuntimeInformation;
-import org.apache.maven.plugin.logging.Log;
-import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
-import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
-
-/**
- * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
- */
-public class MyCustomRule
-    implements EnforcerRule
-{
-    /**
-     * Simple param. This rule will fail if the value is true.
-     */
-    private boolean shouldIfail = false;
-
-    public void execute( EnforcerRuleHelper helper )
-        throws EnforcerRuleException
-    {
-        Log log = helper.getLog();
-
-        try
-        {
-            // get the various expressions out of the helper.
-            MavenProject project = (MavenProject) helper.evaluate( "${project}" );
-            MavenSession session = (MavenSession) helper.evaluate( "${session}" );
-            String target = (String) helper.evaluate( "${project.build.directory}" );
-            String artifactId = (String) helper.evaluate( "${project.artifactId}" );
-
-            // retreive any component out of the session directly
-            ArtifactResolver resolver = (ArtifactResolver) helper.getComponent( ArtifactResolver.class );
-            RuntimeInformation rti = (RuntimeInformation) helper.getComponent( RuntimeInformation.class );
-
-            log.info( "Retrieved Target Folder: " + target );
-            log.info( "Retrieved ArtifactId: " +artifactId );
-            log.info( "Retrieved Project: " + project );
-            log.info( "Retrieved RuntimeInfo: " + rti );
-            log.info( "Retrieved Session: " + session );
-            log.info( "Retrieved Resolver: " + resolver );
-
-            if ( this.shouldIfail )
-            {
-                throw new EnforcerRuleException( "Failing because my param said so." );
-            }
-        }
-        catch ( ComponentLookupException e )
-        {
-            throw new EnforcerRuleException( "Unable to lookup a component " + e.getLocalizedMessage(), e );
-        }
-        catch ( ExpressionEvaluationException e )
-        {
-            throw new EnforcerRuleException( "Unable to lookup an expression " + e.getLocalizedMessage(), e );
-        }
-    }
-
-    /**
-     * If your rule is cacheable, you must return a unique id when parameters or conditions
-     * change that would cause the result to be different. Multiple cached results are stored
-     * based on their id.
-     * 
-     * The easiest way to do this is to return a hash computed from the values of your parameters.
-     * 
-     * If your rule is not cacheable, then the result here is not important, you may return anything.
-     */
-    public String getCacheId()
-    {
-        //no hash on boolean...only parameter so no hash is needed.
-        return ""+this.shouldIfail;
-    }
-
-    /**
-     * This tells the system if the results are cacheable at all. Keep in mind that during
-     * forked builds and other things, a given rule may be executed more than once for the same
-     * project. This means that even things that change from project to project may still 
-     * be cacheable in certain instances.
-     */
-    public boolean isCacheable()
-    {
-        return false;
-    }
-
-    /**
-     * If the rule is cacheable and the same id is found in the cache, the stored results
-     * are passed to this method to allow double checking of the results. Most of the time 
-     * this can be done by generating unique ids, but sometimes the results of objects returned
-     * by the helper need to be queried. You may for example, store certain objects in your rule
-     * and then query them later.
-     */
-    public boolean isResultValid( EnforcerRule arg0 )
-    {
-        return false;
-    }
-}
+package org.apache.maven.enforcer.rule;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import org.apache.maven.ProjectDependenciesResolver;
+import org.apache.maven.enforcer.rule.api.EnforcerRule;
+import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
+import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+
+/**
+ * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
+ * @author <a href="mailto:belingueres@gmail.com">Gabriel Belingueres</a>
+ */
+public class MyCustomRule
+    implements EnforcerRule
+{
+    /**
+     * Simple param. This rule will fail if the value is true.
+     */
+    private boolean shouldIfail = false;
+
+    public void execute( EnforcerRuleHelper helper )
+        throws EnforcerRuleException
+    {
+        Log log = helper.getLog();
+
+        try
+        {
+            // get the various expressions out of the helper.
+            MavenProject project = (MavenProject) helper.evaluate( "${project}" );
+            MavenSession session = (MavenSession) helper.evaluate( "${session}" );
+            String target = (String) helper.evaluate( "${project.build.directory}" );
+            String artifactId = (String) helper.evaluate( "${project.artifactId}" );
+            String mavenVersion = (String) helper.evaluate( "${maven.version}" );
+
+            // retrieve any component out of the session directly
+            ProjectDependenciesResolver resolver = helper.getComponent( ProjectDependenciesResolver.class );
+
+            log.info( "Retrieved Target Folder: " + target );
+            log.info( "Retrieved ArtifactId: " +artifactId );
+            log.info( "Retrieved Project: " + project );
+            log.info( "Retrieved Maven version: " + mavenVersion );
+            log.info( "Retrieved Session: " + session );
+            log.info( "Retrieved Resolver: " + resolver );
+
+            if ( this.shouldIfail )
+            {
+                throw new EnforcerRuleException( "Failing because my param said so." );
+            }
+        }
+        catch ( ComponentLookupException e )
+        {
+            throw new EnforcerRuleException( "Unable to lookup a component " + e.getLocalizedMessage(), e );
+        }
+        catch ( ExpressionEvaluationException e )
+        {
+            throw new EnforcerRuleException( "Unable to lookup an expression " + e.getLocalizedMessage(), e );
+        }
+    }
+
+    /**
+     * If your rule is cacheable, you must return a unique id when parameters or conditions
+     * change that would cause the result to be different. Multiple cached results are stored
+     * based on their id.
+     * 
+     * The easiest way to do this is to return a hash computed from the values of your parameters.
+     * 
+     * If your rule is not cacheable, then the result here is not important, you may return anything.
+     */
+    public String getCacheId()
+    {
+        //no hash on boolean...only parameter so no hash is needed.
+        return Boolean.toString( this.shouldIfail );
+    }
+
+    /**
+     * This tells the system if the results are cacheable at all. Keep in mind that during
+     * forked builds and other things, a given rule may be executed more than once for the same
+     * project. This means that even things that change from project to project may still 
+     * be cacheable in certain instances.
+     */
+    public boolean isCacheable()
+    {
+        return false;
+    }
+
+    /**
+     * If the rule is cacheable and the same id is found in the cache, the stored results
+     * are passed to this method to allow double checking of the results. Most of the time 
+     * this can be done by generating unique ids, but sometimes the results of objects returned
+     * by the helper need to be queried. You may for example, store certain objects in your rule
+     * and then query them later.
+     */
+    public boolean isResultValid( EnforcerRule arg0 )

Review comment:
       arg0 --> rule




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org