This is an automated email from the ASF dual-hosted git repository.

ppkarwasz pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/logging-flume.git


The following commit(s) were added to refs/heads/trunk by this push:
     new c0d73dca Make the build reproducible by deriving version metadata from 
the manifest (#489)
c0d73dca is described below

commit c0d73dcae30ecf10c343c83ac988d5c8d3ffb824
Author: Piotr P. Karwasz <[email protected]>
AuthorDate: Tue Aug 25 13:48:30 2026 +0200

    Make the build reproducible by deriving version metadata from the manifest 
(#489)
    
    * Apply the `revision` convention to `flume-parent`
    
    Every published module inherits from `flume-parent`, not from the
    aggregator, so the CI-friendly properties have to be declared there as
    well. Without them the release automation bumps only the aggregator and
    the artifacts ship a stale version and build timestamp.
    
    Assisted-By: Claude Opus 5 (1M context) <[email protected]>
    Claude-Session: https://claude.ai/code/session_011QwMh1JvFaPBgWEGrMgMj7
    
    * Derive the version metadata from the JAR manifest
    
    `saveVersion.sh` recorded the builder's user name, host, clock and a
    checksum of the working copy, so no two builds agreed and the source
    distribution, which carries no repository metadata, agreed with none.
    The same facts now come from POM-derived manifest headers, which a Git
    checkout and the source archive produce identically.
    
    `getUser()` and `getSrcChecksum()` are deprecated for removal, and
    `getRevision()` reports nothing until the build records a commit id
    again.
    
    Assisted-By: Claude Opus 5 (1M context) <[email protected]>
    Claude-Session: https://claude.ai/code/session_011QwMh1JvFaPBgWEGrMgMj7
    
    * Fall back to the Maven descriptor on blank manifest headers
    
    A present but empty header would have suppressed the fallback.
    
    Assisted-By: Claude Fable 5 <[email protected]>
    Claude-Session: https://claude.ai/code/session_016zsFn1f2B32vcNoCeZSfn7
    
    * Mention the "Unknown" sentinel in the `getDate` contract
    
    The `@return` clause promised ISO-8601 unconditionally.
    
    Assisted-By: Claude Fable 5 <[email protected]>
    Claude-Session: https://claude.ai/code/session_016zsFn1f2B32vcNoCeZSfn7
    
    * Keep repository specifics out of the metadata test
    
    Downstream builds override `<scm>`; assert only invariants, while
    still rejecting tags that betray an unset `<scm><tag>`.
    
    * Apply Spotless formatting
    
    Assisted-By: Claude Fable 5 <[email protected]>
---
 flume-ng-auth/pom.xml                              |   2 +-
 flume-ng-channels/flume-file-channel/pom.xml       |   2 +-
 .../flume-spillable-memory-channel/pom.xml         |   2 +-
 flume-ng-channels/pom.xml                          |   2 +-
 .../flume-ng-config-filter-api/pom.xml             |   2 +-
 .../pom.xml                                        |   2 +-
 .../pom.xml                                        |   2 +-
 flume-ng-configfilters/pom.xml                     |   2 +-
 flume-ng-configuration/pom.xml                     |   2 +-
 flume-ng-core/pom.xml                              | 113 +----------
 flume-ng-core/scripts/saveVersion.ps1              |  61 ------
 flume-ng-core/scripts/saveVersion.sh               |  69 -------
 .../java/org/apache/flume/VersionAnnotation.java   |  72 -------
 .../java/org/apache/flume/tools/VersionInfo.java   | 224 ++++++++++++++++-----
 .../org/apache/flume/tools/TestVersionInfo.java    | 158 ++++++++++++---
 flume-ng-dist/pom.xml                              |   2 +-
 .../flume-ganglia-monitor/pom.xml                  |   2 +-
 .../flume-http-monitor/pom.xml                     |   2 +-
 .../flume-prometheus-monitor/pom.xml               |   2 +-
 flume-ng-instrumentation/pom.xml                   |   2 +-
 flume-ng-node/pom.xml                              |   2 +-
 flume-ng-sdk/pom.xml                               |  16 +-
 flume-ng-sources/flume-http-source/pom.xml         |   2 +-
 flume-ng-sources/flume-netcat-source/pom.xml       |   2 +-
 flume-ng-sources/flume-syslog-source/pom.xml       |   2 +-
 flume-ng-sources/flume-taildir-source/pom.xml      |   2 +-
 flume-ng-sources/pom.xml                           |   2 +-
 flume-parent/pom.xml                               |  23 ++-
 flume-tools/pom.xml                                |   2 +-
 29 files changed, 364 insertions(+), 414 deletions(-)

diff --git a/flume-ng-auth/pom.xml b/flume-ng-auth/pom.xml
index e288313d..b13267f3 100644
--- a/flume-ng-auth/pom.xml
+++ b/flume-ng-auth/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-parent</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
     <relativePath>../flume-parent/pom.xml</relativePath>
   </parent>
 
diff --git a/flume-ng-channels/flume-file-channel/pom.xml 
b/flume-ng-channels/flume-file-channel/pom.xml
index 245e4d56..6183926c 100644
--- a/flume-ng-channels/flume-file-channel/pom.xml
+++ b/flume-ng-channels/flume-file-channel/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-ng-channels</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
   </parent>
 
   <groupId>org.apache.flume.flume-ng-channels</groupId>
diff --git a/flume-ng-channels/flume-spillable-memory-channel/pom.xml 
b/flume-ng-channels/flume-spillable-memory-channel/pom.xml
index b891a42a..2fc1378d 100644
--- a/flume-ng-channels/flume-spillable-memory-channel/pom.xml
+++ b/flume-ng-channels/flume-spillable-memory-channel/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-ng-channels</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
   </parent>
 
   <groupId>org.apache.flume.flume-ng-channels</groupId>
diff --git a/flume-ng-channels/pom.xml b/flume-ng-channels/pom.xml
index a8aeef90..42343fad 100644
--- a/flume-ng-channels/pom.xml
+++ b/flume-ng-channels/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-parent</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
     <relativePath>../flume-parent/pom.xml</relativePath>
   </parent>
 
diff --git a/flume-ng-configfilters/flume-ng-config-filter-api/pom.xml 
b/flume-ng-configfilters/flume-ng-config-filter-api/pom.xml
index 5f4b9cd6..0fa090bd 100644
--- a/flume-ng-configfilters/flume-ng-config-filter-api/pom.xml
+++ b/flume-ng-configfilters/flume-ng-config-filter-api/pom.xml
@@ -20,7 +20,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-ng-configfilters</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
   </parent>
 
   <artifactId>flume-ng-config-filter-api</artifactId>
diff --git 
a/flume-ng-configfilters/flume-ng-environment-variable-config-filter/pom.xml 
b/flume-ng-configfilters/flume-ng-environment-variable-config-filter/pom.xml
index 78c30b0c..f0d39f5d 100644
--- a/flume-ng-configfilters/flume-ng-environment-variable-config-filter/pom.xml
+++ b/flume-ng-configfilters/flume-ng-environment-variable-config-filter/pom.xml
@@ -20,7 +20,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-ng-configfilters</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
   </parent>
 
   <artifactId>flume-ng-environment-variable-config-filter</artifactId>
diff --git 
a/flume-ng-configfilters/flume-ng-external-process-config-filter/pom.xml 
b/flume-ng-configfilters/flume-ng-external-process-config-filter/pom.xml
index 339fdfdb..1ae97a67 100644
--- a/flume-ng-configfilters/flume-ng-external-process-config-filter/pom.xml
+++ b/flume-ng-configfilters/flume-ng-external-process-config-filter/pom.xml
@@ -20,7 +20,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-ng-configfilters</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
   </parent>
 
   <artifactId>flume-ng-external-process-config-filter</artifactId>
diff --git a/flume-ng-configfilters/pom.xml b/flume-ng-configfilters/pom.xml
index 3a219835..7c6a1c74 100644
--- a/flume-ng-configfilters/pom.xml
+++ b/flume-ng-configfilters/pom.xml
@@ -20,7 +20,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-parent</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
     <relativePath>../flume-parent/pom.xml</relativePath>
   </parent>
 
diff --git a/flume-ng-configuration/pom.xml b/flume-ng-configuration/pom.xml
index 8ab25fd6..0ae2b9d2 100644
--- a/flume-ng-configuration/pom.xml
+++ b/flume-ng-configuration/pom.xml
@@ -20,7 +20,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-parent</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
     <relativePath>../flume-parent/pom.xml</relativePath>
   </parent>
   <artifactId>flume-ng-configuration</artifactId>
diff --git a/flume-ng-core/pom.xml b/flume-ng-core/pom.xml
index fa9857c8..2f8044fe 100644
--- a/flume-ng-core/pom.xml
+++ b/flume-ng-core/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-parent</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
     <relativePath>../flume-parent/pom.xml</relativePath>
   </parent>
 
@@ -183,115 +183,4 @@
       </plugin>
     </plugins>
   </build>
-  <profiles>
-    <profile>
-      <id>not-windows</id>
-      <activation>
-        <os>
-          <family>!Windows</family>
-        </os>
-      </activation>
-      <build>
-        <plugins>
-          <plugin>
-            <groupId>org.apache.maven.plugins</groupId>
-            <artifactId>maven-antrun-plugin</artifactId>
-            <executions>
-              <execution>
-                <id>generate-version</id>
-                <goals>
-                  <goal>run</goal>
-                </goals>
-                <phase>generate-sources</phase>
-                <configuration>
-                  <target>
-                    <mkdir 
dir="${project.build.directory}/generated-sources/java" />
-                    <exec executable="sh">
-                      <arg line="${basedir}/scripts/saveVersion.sh 
${project.version} ${project.build.directory}" />
-                    </exec>
-                  </target>
-                </configuration>
-              </execution>
-            </executions>
-          </plugin>
-
-          <plugin>
-            <groupId>org.codehaus.mojo</groupId>
-            <artifactId>build-helper-maven-plugin</artifactId>
-            <executions>
-              <execution>
-                <id>add-source</id>
-                <goals>
-                  <goal>add-source</goal>
-                </goals>
-                <phase>generate-sources</phase>
-                <configuration>
-                  <sources>
-                    <source>target/generated-sources/java</source>
-                  </sources>
-                </configuration>
-              </execution>
-            </executions>
-          </plugin>
-
-        </plugins>
-      </build>
-    </profile>
-
-    <profile>
-      <id>windows</id>
-      <activation>
-        <os>
-          <family>Windows</family>
-        </os>
-      </activation>
-      <build>
-        <plugins>
-          <plugin>
-            <groupId>org.apache.maven.plugins</groupId>
-            <artifactId>maven-antrun-plugin</artifactId>
-            <executions>
-              <execution>
-                <id>generate-version</id>
-                <goals>
-                  <goal>run</goal>
-                </goals>
-                <phase>generate-sources</phase>
-                <configuration>
-                  <target>
-                    <mkdir 
dir="${project.build.directory}/generated-sources/java/org/apache/flume" />
-                    <exec executable="powershell">
-                      <arg line="-executionpolicy unrestricted -file 
${basedir}\scripts\saveVersion.ps1  ${project.version} 
${project.build.directory}" />
-                    </exec>
-                  </target>
-                </configuration>
-              </execution>
-            </executions>
-          </plugin>
-
-          <plugin>
-            <groupId>org.codehaus.mojo</groupId>
-            <artifactId>build-helper-maven-plugin</artifactId>
-            <executions>
-              <execution>
-                <id>add-source</id>
-                <goals>
-                  <goal>add-source</goal>
-                </goals>
-                <phase>generate-sources</phase>
-                <configuration>
-                  <sources>
-                    <source>target/generated-sources/java</source>
-                  </sources>
-                </configuration>
-              </execution>
-            </executions>
-          </plugin>
-
-        </plugins>
-      </build>
-    </profile>
-
-  </profiles>
-
 </project>
diff --git a/flume-ng-core/scripts/saveVersion.ps1 
b/flume-ng-core/scripts/saveVersion.ps1
deleted file mode 100644
index dff88134..00000000
--- a/flume-ng-core/scripts/saveVersion.ps1
+++ /dev/null
@@ -1,61 +0,0 @@
-# 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.
-
-# This script is used to generate the annotation of package info that
-# records the version, revision, branch, url, user and timestamp.
-
-$version=$args[0]
-$buildDirectory=$args[1]
-$outputFile= 
"$buildDirectory\generated-sources\java\org\apache\flume\package-info.java"
-$user = $Env:username
-$date = Get-Date
-
-cmd /c svn info 2>&1 | Out-Null
-if ( $LastExitCode -eq 0 ) {
-  $revision=svn info  | % { if( $_ -match "Last Changed Rev: (?<rev>.*)" ) { 
$matches['rev'];} }
-  $url=svn info  | % { if( $_ -match "URL: (?<url>.*)" ) { $matches['url'];} }
-  $branch=  if( $url -match ".*(?<branch>(branches.*)|(tags.*)|(trunk.*))" ) { 
$matches['branch']; } else { "Unknown"; }
-}
-else {
-    cmd /c git rev-parse HEAD  2>&1 | Out-Null
-    if ( $LastExitCode -eq 0 ) {
-      $revision=$(git log -1 --pretty=format:"%H")
-      $branch=$(git name-rev --name-only HEAD)
-      $remote=$(git config branch.$branch.remote)
-      $url=$(git config remote.$remote.url)
-    }
-    else {
-      revision="Unknown"
-      branch="Unknown"
-      url="file://$cwd"
-    }
-}
-
-$srcChecksum="N/A"
-
-
-$fileContent = @"
-/*
- * Generated by scripts/saveVersion.ps1
- */
-@VersionAnnotation(version="$version", revision="$revision", branch="$branch",
-                         user="$user", date="$date", url="$url",
-                         srcChecksum="$srcChecksum")
-package org.apache.flume;
-"@
-
-New-Item $outputFile -value $fileContent -force -type file
-
diff --git a/flume-ng-core/scripts/saveVersion.sh 
b/flume-ng-core/scripts/saveVersion.sh
deleted file mode 100755
index ad3f8b19..00000000
--- a/flume-ng-core/scripts/saveVersion.sh
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/bin/sh
-
-# 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.
-
-# This script is used to generate the annotation of package info that
-# records the version, revision, branch, url, user and timestamp.
-
-unset LANG
-unset LC_CTYPE
-unset LC_TIME
-version=$1
-buildDirectory=$2
-user=`whoami`
-date=`date`
-dir=`pwd`
-cwd=`dirname $dir`
-if [ -d ../.svn ]; then
-  revision=`svn info ../ | sed -n -e 's/Last Changed Rev: \(.*\)/\1/p'`
-  url=`svn info  ../ | sed -n -e 's/URL: \(.*\)/\1/p'`
-  branch=`echo $url | sed -n -e 's,.*\(branches/.*\)$,\1,p' \
-                             -e 's,.*\(tags/.*\)$,\1,p' \
-                             -e 's,.*trunk$,trunk,p'`
-elif git rev-parse HEAD 2>/dev/null > /dev/null ; then
-  revision=`git log -1 --pretty=format:"%H"`
-  hostname=`hostname`
-  branch=`git branch | sed -n -e 's/^* //p'`
-  url="git://${hostname}${cwd}"
-else
-  revision="Unknown"
-  branch="Unknown"
-  url="file://$cwd"
-fi
-
-if [ -n "$(which md5sum)" ]; then
-  srcChecksum=`find ../ -name '*.java' | grep -v generated-sources | LC_ALL=C 
sort | \
-      xargs md5sum | md5sum | cut -d ' ' -f 1`
-else
-  srcChecksum=`find ../ -name '*.java' | grep -v generated-sources | LC_ALL=C 
sort | \
-      xargs md5 | md5 | cut -d ' ' -f 1`
-fi
-
-mkdir -p $buildDirectory/generated-sources/java/org/apache/flume/
-cat << EOF | \
-  sed -e "s/VERSION/$version/" -e "s/USER/$user/" -e "s/DATE/$date/" \
-      -e "s|URL|$url|" -e "s/REV/$revision/" \
-      -e "s|BRANCH|$branch|" -e "s/SRCCHECKSUM/$srcChecksum/" \
-      > 
$buildDirectory/generated-sources/java/org/apache/flume/package-info.java
-/*
- * Generated by scripts/saveVersion.sh
- */
-@VersionAnnotation(version="VERSION", revision="REV", branch="BRANCH",
-                         user="USER", date="DATE", url="URL",
-                         srcChecksum="SRCCHECKSUM")
-package org.apache.flume;
-EOF
\ No newline at end of file
diff --git 
a/flume-ng-core/src/main/java/org/apache/flume/VersionAnnotation.java 
b/flume-ng-core/src/main/java/org/apache/flume/VersionAnnotation.java
deleted file mode 100644
index 06269ac3..00000000
--- a/flume-ng-core/src/main/java/org/apache/flume/VersionAnnotation.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.
- */
-package org.apache.flume;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * This class is about package attribute that captures
- * version info of Flume that was compiled.
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.PACKAGE)
-public @interface VersionAnnotation {
-
-    /**
-     * Get the Flume version
-     * @return the version string "1.1"
-     */
-    String version();
-
-    /**
-     * Get the subversion revision.
-     * @return the revision number as a string (eg. "100755")
-     */
-    String revision();
-
-    /**
-     * Get the branch from which this was compiled.
-     * @return The branch name, e.g. "trunk"
-     */
-    String branch();
-
-    /**
-     * Get the username that compiled Flume.
-     */
-    String user();
-
-    /**
-     * Get the date when Flume was compiled.
-     * @return the date in unix 'date' format
-     */
-    String date();
-
-    /**
-     * Get the url for the subversion repository.
-     */
-    String url();
-
-    /**
-     * Get a checksum of the source files from which
-     * Flume was compiled.
-     * @return a string that uniquely identifies the source
-     **/
-    String srcChecksum();
-}
diff --git 
a/flume-ng-core/src/main/java/org/apache/flume/tools/VersionInfo.java 
b/flume-ng-core/src/main/java/org/apache/flume/tools/VersionInfo.java
index f5220e4d..0f646930 100644
--- a/flume-ng-core/src/main/java/org/apache/flume/tools/VersionInfo.java
+++ b/flume-ng-core/src/main/java/org/apache/flume/tools/VersionInfo.java
@@ -16,105 +16,229 @@
  */
 package org.apache.flume.tools;
 
-import org.apache.flume.VersionAnnotation;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URL;
+import java.util.Properties;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.apache.commons.lang3.StringUtils;
 
-/*
- * This class provides version info of Flume NG
+/**
+ * Provides the build metadata of the Flume artifact this class was loaded 
from.
+ *
+ * <p>The values come from the manifest of that artifact, falling back to its 
Maven descriptor when
+ * Flume has been shaded into another artifact and the manifest is no longer 
its own. Every accessor
+ * returns {@value #UNKNOWN} rather than {@code null} when the information is 
unavailable.
  */
-
 public class VersionInfo {
 
-    private static Package myPackage;
-    private static VersionAnnotation version;
+    private static final String UNKNOWN = "Unknown";
+
+    private static final String GROUP_ID = "org.apache.flume";
+    private static final String ARTIFACT_ID = "flume-ng-core";
+
+    private static final String IMPLEMENTATION_TIMESTAMP = 
"Implementation-Timestamp";
+    private static final String PURL = "Purl";
+    private static final String BUNDLE_SCM = "Bundle-SCM";
+
+    private static final String PURL_PREFIX = "pkg:maven/" + GROUP_ID + "/" + 
ARTIFACT_ID + "@";
+    private static final String CLASS_PATH = 
"org/apache/flume/tools/VersionInfo.class";
+    private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
+    private static final String POM_PROPERTIES_PATH =
+            "/META-INF/maven/" + GROUP_ID + "/" + ARTIFACT_ID + 
"/pom.properties";
+
+    /** Matches one {@code name=value} pair of an OSGi header, with an 
optionally quoted value. */
+    private static final Pattern SCM_ATTRIBUTE =
+            
Pattern.compile("(?:^|,)\\s*([A-Za-z0-9_-]+)\\s*=\\s*(?:\"([^\"]*)\"|([^,]*))");
+
+    private static final Attributes MANIFEST = ownManifest();
+    private static final Properties POM_PROPERTIES = pomProperties();
+
+    private static final String VERSION = version(MANIFEST, POM_PROPERTIES);
+    private static final String PURL_VALUE = purl(MANIFEST, POM_PROPERTIES);
+    private static final String URL_VALUE = 
orUnknown(scmAttribute(MANIFEST.getValue(BUNDLE_SCM), "url"));
+    private static final String TAG = 
orUnknown(scmAttribute(MANIFEST.getValue(BUNDLE_SCM), "tag"));
+    private static final String DATE = 
orUnknown(MANIFEST.getValue(IMPLEMENTATION_TIMESTAMP));
+
+    /**
+     * Reads the manifest of the artifact this class was loaded from.
+     *
+     * <p>Resolving it against the location of this class, instead of looking 
up
+     * {@code META-INF/MANIFEST.MF} on the class path, keeps another artifact 
from answering. Returns
+     * empty attributes when the manifest is missing or belongs to an artifact 
Flume was shaded into.
+     */
+    private static Attributes ownManifest() {
+        URL self = VersionInfo.class.getResource("VersionInfo.class");
+        if (self == null) {
+            return new Attributes();
+        }
+        String location = self.toString();
+        if (!location.endsWith(CLASS_PATH)) {
+            return new Attributes();
+        }
+        String root = location.substring(0, location.length() - 
CLASS_PATH.length());
+        try (InputStream stream = URI.create(root + 
MANIFEST_PATH).toURL().openStream()) {
+            Attributes attributes = new Manifest(stream).getMainAttributes();
+            return isOwn(attributes) ? attributes : new Attributes();
+        } catch (IOException | RuntimeException ignored) {
+            return new Attributes();
+        }
+    }
+
+    private static Properties pomProperties() {
+        Properties properties = new Properties();
+        try (InputStream stream = 
VersionInfo.class.getResourceAsStream(POM_PROPERTIES_PATH)) {
+            if (stream != null) {
+                properties.load(stream);
+            }
+        } catch (IOException | RuntimeException ignored) {
+            // Falls through to the empty properties.
+        }
+        return properties;
+    }
+
+    /** Tells whether the manifest describes this artifact rather than one 
Flume was shaded into. */
+    static boolean isOwn(Attributes manifest) {
+        String purl = manifest.getValue(PURL);
+        return purl != null && purl.startsWith(PURL_PREFIX);
+    }
 
-    static {
-        myPackage = VersionAnnotation.class.getPackage();
-        version = myPackage.getAnnotation(VersionAnnotation.class);
+    static String version(Attributes manifest, Properties pomProperties) {
+        String version = 
manifest.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
+        return orUnknown(StringUtils.isNotBlank(version) ? version : 
pomProperties.getProperty("version"));
+    }
+
+    static String purl(Attributes manifest, Properties pomProperties) {
+        String purl = manifest.getValue(PURL);
+        if (StringUtils.isBlank(purl)) {
+            String groupId = pomProperties.getProperty("groupId");
+            String artifactId = pomProperties.getProperty("artifactId");
+            String version = pomProperties.getProperty("version");
+            if (groupId != null && artifactId != null && version != null) {
+                purl = "pkg:maven/" + groupId + "/" + artifactId + "@" + 
version;
+            }
+        }
+        return orUnknown(purl);
     }
 
     /**
-     * Get the meta-data for the Flume package.
-     * @return
+     * Returns one attribute of an OSGi {@code Bundle-SCM} header, or {@code 
null} if absent.
+     *
+     * <p>The header is specified by OSGi Core R8, section 3.2.1, as a comma 
separated list of
+     * {@code url}, {@code connection}, {@code developer-connection} and 
{@code tag} attributes.
      */
-    static Package getPackage() {
-        return myPackage;
+    static String scmAttribute(String header, String attribute) {
+        if (header == null) {
+            return null;
+        }
+        Matcher matcher = SCM_ATTRIBUTE.matcher(header);
+        while (matcher.find()) {
+            if (attribute.equals(matcher.group(1))) {
+                String quoted = matcher.group(2);
+                return quoted != null ? quoted : matcher.group(3).trim();
+            }
+        }
+        return null;
+    }
+
+    private static String orUnknown(String value) {
+        return StringUtils.defaultIfBlank(value, UNKNOWN);
     }
 
     /**
-     * Get the Flume version.
-     * @return the Flume version string, eg. "1.1"
+     * Gets the Flume version.
+     *
+     * @return the Flume version string, eg. "2.0.0"
      */
     public static String getVersion() {
-        return version != null ? version.version() : "Unknown";
+        return VERSION;
+    }
+
+    /**
+     * Gets the Package URL of the Flume artifact this class was loaded from.
+     *
+     * @return the Package URL, eg. 
"pkg:maven/org.apache.flume/[email protected]"
+     */
+    public static String getPurl() {
+        return PURL_VALUE;
     }
 
     /**
-     * Get the subversion revision number for the root directory
-     * @return the revision number, eg. "100755"
+     * Gets the source control revision this was built from.
+     *
+     * <p>The build no longer records a commit id, since it has to produce the 
same artifact from a
+     * Git checkout and from the source distribution, which carries no 
repository metadata.
+     *
+     * @return always "Unknown"
      */
     public static String getRevision() {
-        if (version != null && version.revision() != null && 
!version.revision().isEmpty()) {
-            return version.revision();
-        }
-        return "Unknown";
+        return UNKNOWN;
     }
 
     /**
-     * Get the branch on which this originated.
-     * @return The branch name, e.g. "trunk" or "branches/branch-1.1"
+     * Gets the source control tag or branch this was built from.
+     *
+     * @return the tag, eg. "rel/2.0.0"
      */
     public static String getBranch() {
-        return version != null ? version.branch() : "Unknown";
+        return TAG;
     }
 
     /**
-     * The date that Flume was compiled.
-     * @return the compilation date in unix date format
+     * Gets the date Flume was built.
+     *
+     * @return the build date in ISO-8601 format, or "Unknown" if unavailable
      */
     public static String getDate() {
-        return version != null ? version.date() : "Unknown";
+        return DATE;
     }
 
     /**
-     * The user that compiled Flume.
-     * @return the username of the user
+     * Gets the user that compiled Flume.
+     *
+     * @return always "Unknown"
+     * @deprecated Recording the user would make the build unreproducible.
      */
+    @Deprecated(since = "2.0.0", forRemoval = true)
     public static String getUser() {
-        return version != null ? version.user() : "Unknown";
+        return UNKNOWN;
     }
 
     /**
-     * Get the subversion URL for the root Flume directory.
+     * Gets the source control URL of the Flume repository.
+     *
+     * @return the repository URL
      */
     public static String getUrl() {
-        return version != null ? version.url() : "Unknown";
+        return URL_VALUE;
     }
 
     /**
-     * Get the checksum of the source files from which Flume was
-     * built.
-     **/
+     * Gets the checksum of the source files Flume was built from.
+     *
+     * @return always "Unknown"
+     * @deprecated Use {@link #getPurl()} to identify the artifact, and verify 
it against the
+     *     checksums published with the release.
+     */
+    @Deprecated(since = "2.0.0", forRemoval = true)
     public static String getSrcChecksum() {
-        return version != null ? version.srcChecksum() : "Unknown";
+        return UNKNOWN;
     }
 
-    /**
-     * Returns the build version info which includes version,
-     * revision, user, date and source checksum
-     */
+    /** Returns the build version info, which includes the version, the tag 
and the build date. */
     public static String getBuildVersion() {
-        return VersionInfo.getVersion() + " from "
-                + VersionInfo.getRevision() + " by "
-                + VersionInfo.getUser() + " on "
-                + VersionInfo.getDate() + " source checksum "
-                + VersionInfo.getSrcChecksum();
+        return getVersion() + " from " + getBranch() + " built on " + 
getDate();
     }
 
     public static void main(String[] args) {
         System.out.println("Flume " + getVersion());
-        System.out.println("Source code repository: " + 
"https://git.apache.org/repos/asf/flume.git";);
-        System.out.println("Revision: " + getRevision());
-        System.out.println("Compiled by " + getUser() + " on " + getDate());
-        System.out.println("From source with checksum " + getSrcChecksum());
+        System.out.println("Package URL: " + getPurl());
+        System.out.println("Source code repository: " + getUrl());
+        System.out.println("Tag: " + getBranch());
+        System.out.println("Compiled on " + getDate());
     }
 }
diff --git 
a/flume-ng-core/src/test/java/org/apache/flume/tools/TestVersionInfo.java 
b/flume-ng-core/src/test/java/org/apache/flume/tools/TestVersionInfo.java
index 59457f96..b9276110 100644
--- a/flume-ng-core/src/test/java/org/apache/flume/tools/TestVersionInfo.java
+++ b/flume-ng-core/src/test/java/org/apache/flume/tools/TestVersionInfo.java
@@ -16,42 +16,154 @@
  */
 package org.apache.flume.tools;
 
-import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
+import java.net.URI;
+import java.time.Instant;
+import java.util.List;
+import java.util.Properties;
+import java.util.jar.Attributes;
 import org.junit.Test;
 
 public class TestVersionInfo {
 
-    private static final Logger logger = LogManager.getLogger();
+    private static final String PURL = 
"pkg:maven/org.apache.flume/[email protected]";
+
+    private static final String BUNDLE_SCM = 
"url=\"https://gitbox.apache.org/repos/asf/logging-flume.git\",";
+            + 
"connection=\"scm:git:https://gitbox.apache.org/repos/asf/logging-flume.git\",";
+            + 
"developer-connection=\"scm:git:https://gitbox.apache.org/repos/asf/logging-flume.git\",";
+            + "tag=\"rel/2.0.0\"";
 
     /**
-     *  Make sure that Unknown is expected when no version info
+     * Checks the metadata of the artifact the test runs against.
+     *
+     * <p>BND writes the manifest to the output directory before the tests 
run, so the values are
+     * available whether Flume is loaded from a JAR or from the compiled 
classes.
      */
     @Test
-    public void testVersionInfoUnknown() {
+    public void testMetadataOfOwnArtifact() {
+        assertTrue(
+                "getVersion returned " + VersionInfo.getVersion(),
+                VersionInfo.getVersion().matches("\\d+\\.\\d+.*"));
+        assertTrue(
+                "getPurl returned " + VersionInfo.getPurl(),
+                
VersionInfo.getPurl().startsWith("pkg:maven/org.apache.flume/flume-ng-core@"));
+        // Downstream builds override `<scm>`, so only check invariants:
+        // a valid URL, and a tag that does not betray an unset `<scm><tag>`.
+        assertTrue(
+                "getUrl returned " + VersionInfo.getUrl(),
+                
URI.create(VersionInfo.getUrl()).toString().startsWith("https://";));
+        assertFalse(
+                "getBranch returned " + VersionInfo.getBranch(),
+                List.of("", "Unknown", "HEAD", "master", "main", 
"trunk").contains(VersionInfo.getBranch()));
+        // Throws if the timestamp is not ISO-8601.
+        Instant.parse(VersionInfo.getDate());
+        assertTrue(
+                "getBuildVersion returned " + VersionInfo.getBuildVersion(),
+                VersionInfo.getBuildVersion().matches(".+ from .+ built on 
.+"));
+    }
 
-        logger.debug("Flume " + VersionInfo.getVersion());
-        logger.debug("Subversion " + VersionInfo.getUrl() + " -r " + 
VersionInfo.getRevision());
-        logger.debug("Compiled by " + VersionInfo.getUser() + " on " + 
VersionInfo.getDate());
-        logger.debug("From source with checksum " + 
VersionInfo.getSrcChecksum());
-        logger.debug("Flume " + VersionInfo.getBuildVersion());
+    @Test
+    @SuppressWarnings({"deprecation", "removal"})
+    public void testUnrecordedMetadata() {
+        assertEquals("Unknown", VersionInfo.getRevision());
+        assertEquals("Unknown", VersionInfo.getUser());
+        assertEquals("Unknown", VersionInfo.getSrcChecksum());
+    }
 
-        assertTrue("getVersion returned Unknown", 
!VersionInfo.getVersion().equals("Unknown"));
-        assertTrue("getUser returned Unknown", 
!VersionInfo.getUser().equals("Unknown"));
-        assertTrue("getUrl returned Unknown", 
!VersionInfo.getUrl().equals("Unknown"));
-        assertTrue(
-                "getSrcChecksum returned Unknown", 
!VersionInfo.getSrcChecksum().equals("Unknown"));
+    @Test
+    public void testVersionPrefersTheManifest() {
+        Attributes manifest = new Attributes();
+        manifest.putValue("Implementation-Version", "2.0.0");
+        assertEquals("2.0.0", VersionInfo.version(manifest, 
pomProperties("1.11.0")));
+    }
 
-        // check getBuildVersion() return format
-        assertTrue(
-                "getBuildVersion returned unexpected format",
-                VersionInfo.getBuildVersion().matches(".+from.+by.+on.+source 
checksum.+"));
+    @Test
+    public void testVersionFallsBackToPomProperties() {
+        assertEquals("1.11.0", VersionInfo.version(new Attributes(), 
pomProperties("1.11.0")));
+    }
+
+    @Test
+    public void testVersionWithoutAnySource() {
+        assertEquals("Unknown", VersionInfo.version(new Attributes(), new 
Properties()));
+    }
+
+    /** A present but blank header must not shadow the Maven descriptor. */
+    @Test
+    public void testVersionIgnoresBlankHeader() {
+        Attributes manifest = new Attributes();
+        manifest.putValue("Implementation-Version", " ");
+        assertEquals("1.11.0", VersionInfo.version(manifest, 
pomProperties("1.11.0")));
+    }
+
+    @Test
+    public void testPurlPrefersTheManifest() {
+        Attributes manifest = new Attributes();
+        manifest.putValue("Purl", PURL);
+        assertEquals(PURL, VersionInfo.purl(manifest, 
pomProperties("1.11.0")));
+    }
+
+    @Test
+    public void testPurlIsBuiltFromPomProperties() {
+        assertEquals(
+                "pkg:maven/org.apache.flume/[email protected]",
+                VersionInfo.purl(new Attributes(), pomProperties("1.11.0")));
+    }
+
+    @Test
+    public void testPurlWithoutAnySource() {
+        assertEquals("Unknown", VersionInfo.purl(new Attributes(), new 
Properties()));
+    }
+
+    /** A present but blank header must not shadow the Maven descriptor. */
+    @Test
+    public void testPurlIgnoresBlankHeader() {
+        Attributes manifest = new Attributes();
+        manifest.putValue("Purl", " ");
+        assertEquals(
+                "pkg:maven/org.apache.flume/[email protected]", 
VersionInfo.purl(manifest, pomProperties("1.11.0")));
+    }
+
+    /** A manifest of an artifact Flume was shaded into must not be mistaken 
for our own. */
+    @Test
+    public void testForeignManifestIsRejected() {
+        Attributes foreign = new Attributes();
+        foreign.putValue("Purl", "pkg:maven/com.example/[email protected]");
+        foreign.putValue("Implementation-Version", "1.0.0");
+        assertFalse(VersionInfo.isOwn(foreign));
+        assertFalse(VersionInfo.isOwn(new Attributes()));
+
+        Attributes own = new Attributes();
+        own.putValue("Purl", PURL);
+        assertTrue(VersionInfo.isOwn(own));
+    }
+
+    @Test
+    public void testScmAttributes() {
+        assertEquals("rel/2.0.0", VersionInfo.scmAttribute(BUNDLE_SCM, "tag"));
+        assertEquals(
+                "https://gitbox.apache.org/repos/asf/logging-flume.git";, 
VersionInfo.scmAttribute(BUNDLE_SCM, "url"));
+        assertEquals(
+                
"scm:git:https://gitbox.apache.org/repos/asf/logging-flume.git";,
+                VersionInfo.scmAttribute(BUNDLE_SCM, "developer-connection"));
+        assertNull(VersionInfo.scmAttribute(BUNDLE_SCM, "revision"));
+        assertNull(VersionInfo.scmAttribute(null, "tag"));
+    }
+
+    /** OSGi only requires quoting for values with special characters. */
+    @Test
+    public void testScmAttributeWithoutQuotes() {
+        assertEquals("rel/2.0.0", 
VersionInfo.scmAttribute("url=https://example.org,tag=rel/2.0.0";, "tag"));
+    }
 
-        // "Unknown" when build without svn or git
-        assertNotNull("getRevision returned null", VersionInfo.getRevision());
-        assertNotNull("getBranch returned null", VersionInfo.getBranch());
+    private static Properties pomProperties(String version) {
+        Properties properties = new Properties();
+        properties.setProperty("groupId", "org.apache.flume");
+        properties.setProperty("artifactId", "flume-ng-core");
+        properties.setProperty("version", version);
+        return properties;
     }
 }
diff --git a/flume-ng-dist/pom.xml b/flume-ng-dist/pom.xml
index 6e92bc1d..2faad49d 100644
--- a/flume-ng-dist/pom.xml
+++ b/flume-ng-dist/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-parent</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
     <relativePath>../flume-parent/pom.xml</relativePath>
   </parent>
 
diff --git a/flume-ng-instrumentation/flume-ganglia-monitor/pom.xml 
b/flume-ng-instrumentation/flume-ganglia-monitor/pom.xml
index 1911b120..cb357256 100644
--- a/flume-ng-instrumentation/flume-ganglia-monitor/pom.xml
+++ b/flume-ng-instrumentation/flume-ganglia-monitor/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-ng-instrumentation</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
   </parent>
 
   <groupId>org.apache.flume.flume-ng-instrumentation</groupId>
diff --git a/flume-ng-instrumentation/flume-http-monitor/pom.xml 
b/flume-ng-instrumentation/flume-http-monitor/pom.xml
index 6c266c68..e1e33e69 100644
--- a/flume-ng-instrumentation/flume-http-monitor/pom.xml
+++ b/flume-ng-instrumentation/flume-http-monitor/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-ng-instrumentation</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
   </parent>
 
   <groupId>org.apache.flume.flume-ng-instrumentation</groupId>
diff --git a/flume-ng-instrumentation/flume-prometheus-monitor/pom.xml 
b/flume-ng-instrumentation/flume-prometheus-monitor/pom.xml
index 27b90fda..6d66a863 100644
--- a/flume-ng-instrumentation/flume-prometheus-monitor/pom.xml
+++ b/flume-ng-instrumentation/flume-prometheus-monitor/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-ng-instrumentation</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
   </parent>
 
   <groupId>org.apache.flume.flume-ng-instrumentation</groupId>
diff --git a/flume-ng-instrumentation/pom.xml b/flume-ng-instrumentation/pom.xml
index e664afbb..1a049f90 100644
--- a/flume-ng-instrumentation/pom.xml
+++ b/flume-ng-instrumentation/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-parent</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
     <relativePath>../flume-parent/pom.xml</relativePath>
   </parent>
 
diff --git a/flume-ng-node/pom.xml b/flume-ng-node/pom.xml
index 40f6a4d0..5878f0f5 100644
--- a/flume-ng-node/pom.xml
+++ b/flume-ng-node/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-parent</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
     <relativePath>../flume-parent/pom.xml</relativePath>
   </parent>
 
diff --git a/flume-ng-sdk/pom.xml b/flume-ng-sdk/pom.xml
index bbe85ee1..c5b1d20d 100644
--- a/flume-ng-sdk/pom.xml
+++ b/flume-ng-sdk/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-parent</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
     <relativePath>../flume-parent/pom.xml</relativePath>
   </parent>
 
@@ -90,6 +90,20 @@
             <goals>
               <goal>test-jar</goal>
             </goals>
+            <configuration>
+              <!-- BND describes the main classes in a single manifest per 
module, which `logging-parent`
+                   feeds to every execution. Drop it here: the test JAR is not 
that bundle, and its
+                   Package URL needs the qualifiers of a classified artifact. 
-->
+              <archive combine.self="override">
+                <manifest>
+                  
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
+                  
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
+                </manifest>
+                <manifestEntries>
+                  
<Purl>pkg:maven/${project.groupId}/${project.artifactId}@${project.version}?classifier=tests&amp;type=test-jar</Purl>
+                </manifestEntries>
+              </archive>
+            </configuration>
           </execution>
         </executions>
       </plugin>
diff --git a/flume-ng-sources/flume-http-source/pom.xml 
b/flume-ng-sources/flume-http-source/pom.xml
index 43770d96..d7f2b585 100644
--- a/flume-ng-sources/flume-http-source/pom.xml
+++ b/flume-ng-sources/flume-http-source/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-ng-sources</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
   </parent>
 
   <groupId>org.apache.flume.flume-ng-sources</groupId>
diff --git a/flume-ng-sources/flume-netcat-source/pom.xml 
b/flume-ng-sources/flume-netcat-source/pom.xml
index d3292661..5c8becc1 100644
--- a/flume-ng-sources/flume-netcat-source/pom.xml
+++ b/flume-ng-sources/flume-netcat-source/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-ng-sources</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
   </parent>
 
   <groupId>org.apache.flume.flume-ng-sources</groupId>
diff --git a/flume-ng-sources/flume-syslog-source/pom.xml 
b/flume-ng-sources/flume-syslog-source/pom.xml
index e45b597f..1f0beb2f 100644
--- a/flume-ng-sources/flume-syslog-source/pom.xml
+++ b/flume-ng-sources/flume-syslog-source/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-ng-sources</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
   </parent>
 
   <groupId>org.apache.flume.flume-ng-sources</groupId>
diff --git a/flume-ng-sources/flume-taildir-source/pom.xml 
b/flume-ng-sources/flume-taildir-source/pom.xml
index 89edc395..d371c0f3 100644
--- a/flume-ng-sources/flume-taildir-source/pom.xml
+++ b/flume-ng-sources/flume-taildir-source/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-ng-sources</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
   </parent>
 
   <groupId>org.apache.flume.flume-ng-sources</groupId>
diff --git a/flume-ng-sources/pom.xml b/flume-ng-sources/pom.xml
index 3318e3fd..5e12ea54 100644
--- a/flume-ng-sources/pom.xml
+++ b/flume-ng-sources/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-parent</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
     <relativePath>../flume-parent/pom.xml</relativePath>
   </parent>
 
diff --git a/flume-parent/pom.xml b/flume-parent/pom.xml
index f02aa175..8036ba0a 100644
--- a/flume-parent/pom.xml
+++ b/flume-parent/pom.xml
@@ -28,7 +28,7 @@
 
   <groupId>org.apache.flume</groupId>
   <artifactId>flume-parent</artifactId>
-  <version>2.0.0-SNAPSHOT</version>
+  <version>${revision}</version>
   <packaging>pom</packaging>
 
   <name>Apache Flume Parent</name>
@@ -59,7 +59,7 @@
   <scm child.scm.connection.inherit.append.path="false" 
child.scm.developerConnection.inherit.append.path="false" 
child.scm.url.inherit.append.path="false">
     
<connection>scm:git:https://gitbox.apache.org/repos/asf/logging-flume.git</connection>
     
<developerConnection>scm:git:https://gitbox.apache.org/repos/asf/logging-flume.git</developerConnection>
-    <tag>rel/${project.version}</tag>
+    <tag>rel/${revision}</tag>
     <url>https://gitbox.apache.org/repos/asf/logging-flume.git</url>
   </scm>
 
@@ -75,12 +75,25 @@
 
   <properties>
 
+    <revision>2.0.0-SNAPSHOT</revision>
+
     <!-- Version of the artifacts released from the main `logging-flume` 
repository -->
-    <flume-project.version>2.0.0-SNAPSHOT</flume-project.version>
+    <flume-project.version>${revision}</flume-project.version>
     <!-- The website is generated by Antora from `flume-project`: skip the 
per-module `maven-site-plugin` sites. -->
     <maven.site.skip>true</maven.site.skip>
-    <!-- Update for year of distribution. Should be set by the 
maven-release-plugin at release time. -->
-    
<project.build.outputTimestamp>2022-01-02T00:00:00Z</project.build.outputTimestamp>
+    <!-- Dummy value; overwritten by CI at release time. Do not edit manually. 
-->
+    
<project.build.outputTimestamp>2026-01-01T00:00:00Z</project.build.outputTimestamp>
+
+    <!-- Append build metadata to the manifest generated by BND in 
`logging-parent`.
+         `Bundle-SCM` is specified by OSGi Core R8, section 3.2.1; 
`logging-parent` strips the header
+         because inheritance assembly corrupts `project.scm.url`. Flume sets
+         `child.scm.*.inherit.append.path="false"`, so its value is correct: 
keep the header.
+         Neither the JAR File Specification nor OSGi define a header for the 
build timestamp or the
+         Package URL, so `Implementation-Timestamp` and `Purl` are 
Flume-specific. -->
+    <bnd-extra-config>-removeheaders: Bundle-DocURL,Bundle-Developers
+
+      Implementation-Timestamp: ${project.build.outputTimestamp}
+      Purl: 
pkg:maven/${project.groupId}/${project.artifactId}@${project.version}</bnd-extra-config>
     <!-- Set default encoding to UTF-8 to remove maven complaints -->
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 
diff --git a/flume-tools/pom.xml b/flume-tools/pom.xml
index 7d58b3fb..9d3d65fb 100644
--- a/flume-tools/pom.xml
+++ b/flume-tools/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>org.apache.flume</groupId>
     <artifactId>flume-parent</artifactId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>${revision}</version>
     <relativePath>../flume-parent/pom.xml</relativePath>
   </parent>
 

Reply via email to