Browse Source

Added migration/index.asciidoc generation support (#87318)

Including extracting static content from migration/index, so the template would be as light as possible.

The reason for this work is because the gradle task `generateReleaseNotes` was not correctly adding new links and imports to the migrations/index and that caused documentation to fail building for 8.3.0.
Craig Taverner 3 years ago
parent
commit
a4e0d9b9dd

+ 37 - 0
build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/release/GenerateReleaseNotesTask.java

@@ -56,11 +56,13 @@ public class GenerateReleaseNotesTask extends DefaultTask {
     private final RegularFileProperty releaseNotesTemplate;
     private final RegularFileProperty releaseHighlightsTemplate;
     private final RegularFileProperty breakingChangesTemplate;
+    private final RegularFileProperty migrationIndexTemplate;
 
     private final RegularFileProperty releaseNotesIndexFile;
     private final RegularFileProperty releaseNotesFile;
     private final RegularFileProperty releaseHighlightsFile;
     private final RegularFileProperty breakingChangesMigrationFile;
+    private final RegularFileProperty migrationIndexFile;
 
     private final GitWrapper gitWrapper;
 
@@ -72,11 +74,13 @@ public class GenerateReleaseNotesTask extends DefaultTask {
         releaseNotesTemplate = objectFactory.fileProperty();
         releaseHighlightsTemplate = objectFactory.fileProperty();
         breakingChangesTemplate = objectFactory.fileProperty();
+        migrationIndexTemplate = objectFactory.fileProperty();
 
         releaseNotesIndexFile = objectFactory.fileProperty();
         releaseNotesFile = objectFactory.fileProperty();
         releaseHighlightsFile = objectFactory.fileProperty();
         breakingChangesMigrationFile = objectFactory.fileProperty();
+        migrationIndexFile = objectFactory.fileProperty();
 
         gitWrapper = new GitWrapper(execOperations);
     }
@@ -137,6 +141,13 @@ public class GenerateReleaseNotesTask extends DefaultTask {
             this.breakingChangesMigrationFile.get().getAsFile(),
             entries
         );
+
+        LOGGER.info("Updating migration/index...");
+        MigrationIndexGenerator.update(
+            getMinorVersions(versions),
+            this.migrationIndexTemplate.get().getAsFile(),
+            this.migrationIndexFile.get().getAsFile()
+        );
     }
 
     /**
@@ -154,6 +165,14 @@ public class GenerateReleaseNotesTask extends DefaultTask {
             .collect(toSet());
     }
 
+    /**
+     * Convert set of QualifiedVersion to MinorVersion by deleting all but the major and minor components.
+     */
+    @VisibleForTesting
+    static Set<MinorVersion> getMinorVersions(Set<QualifiedVersion> versions) {
+        return versions.stream().map(MinorVersion::of).collect(toSet());
+    }
+
     /**
      * Group a set of files by the version in which they first appeared, up until the supplied version. Any files not
      * present in an earlier version are assumed to have been introduced in the specified version.
@@ -320,6 +339,15 @@ public class GenerateReleaseNotesTask extends DefaultTask {
         this.breakingChangesTemplate.set(file);
     }
 
+    @InputFile
+    public RegularFileProperty getMigrationIndexTemplate() {
+        return migrationIndexTemplate;
+    }
+
+    public void setMigrationIndexTemplate(RegularFile file) {
+        this.migrationIndexTemplate.set(file);
+    }
+
     @OutputFile
     public RegularFileProperty getReleaseNotesIndexFile() {
         return releaseNotesIndexFile;
@@ -355,4 +383,13 @@ public class GenerateReleaseNotesTask extends DefaultTask {
     public void setBreakingChangesMigrationFile(RegularFile file) {
         this.breakingChangesMigrationFile.set(file);
     }
+
+    @OutputFile
+    public RegularFileProperty getMigrationIndexFile() {
+        return migrationIndexFile;
+    }
+
+    public void setMigrationIndexFile(RegularFile file) {
+        this.migrationIndexFile.set(file);
+    }
 }

+ 50 - 0
build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/release/MigrationIndexGenerator.java

@@ -0,0 +1,50 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+package org.elasticsearch.gradle.internal.release;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+
+import static java.util.Comparator.reverseOrder;
+
+/**
+ * This class ensures that the migrate/index page has the appropriate anchors and include directives
+ * for the current repository version.
+ */
+public class MigrationIndexGenerator {
+
+    static void update(Set<MinorVersion> versions, File indexTemplate, File indexFile) throws IOException {
+        try (FileWriter indexFileWriter = new FileWriter(indexFile)) {
+            indexFileWriter.write(generateFile(versions, Files.readString(indexTemplate.toPath())));
+        }
+    }
+
+    @VisibleForTesting
+    static String generateFile(Set<MinorVersion> versionsSet, String template) throws IOException {
+        final Set<MinorVersion> versions = new TreeSet<>(reverseOrder());
+        versions.addAll(versionsSet);
+        final List<String> includeVersions = versions.stream().map(MinorVersion::underscore).collect(Collectors.toList());
+
+        final Map<String, Object> bindings = new HashMap<>();
+        bindings.put("versions", versions);
+        bindings.put("includeVersions", includeVersions);
+
+        return TemplateUtils.render(template, bindings);
+    }
+}

+ 47 - 0
build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/release/MinorVersion.java

@@ -0,0 +1,47 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+package org.elasticsearch.gradle.internal.release;
+
+import java.util.Comparator;
+import java.util.Objects;
+
+/**
+ * Encapsulates comparison and printing logic for an x.y.
+ */
+public record MinorVersion(int major, int minor) implements Comparable<MinorVersion> {
+    /**
+     * Converts a QualifiedVersion into a MinorVersion by deleting all but the major and minor components.
+     */
+    public static MinorVersion of(final QualifiedVersion v) {
+        Objects.requireNonNull(v);
+        return new MinorVersion(v.major(), v.minor());
+    }
+
+    @Override
+    public String toString() {
+        return major + "." + minor;
+    }
+
+    /** Generate version string with underscore instead of dot */
+    public String underscore() {
+        return major + "_" + minor;
+    }
+
+    private static final Comparator<MinorVersion> COMPARATOR = Comparator.comparing((MinorVersion v) -> v.major)
+        .thenComparing(v -> v.minor);
+
+    @Override
+    public int compareTo(MinorVersion other) {
+        return COMPARATOR.compare(this, other);
+    }
+
+    public boolean isBefore(MinorVersion other) {
+        return this.compareTo(other) < 0;
+    }
+}

+ 2 - 0
build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/release/ReleaseToolsPlugin.java

@@ -96,6 +96,8 @@ public class ReleaseToolsPlugin implements Plugin<Project> {
                     String.format("docs/reference/migration/migrate_%d_%d.asciidoc", version.getMajor(), version.getMinor())
                 )
             );
+            task.setMigrationIndexTemplate(projectDirectory.file(RESOURCES + "templates/migration-index.asciidoc"));
+            task.setMigrationIndexFile(projectDirectory.file("docs/reference/migration/index.asciidoc"));
 
             task.dependsOn(validateChangelogsTask);
         });

+ 4 - 0
build-tools-internal/src/main/resources/templates/migration-index.asciidoc

@@ -0,0 +1,4 @@
+include::migration_intro.asciidoc[]
+
+<% versions.each { print "* <<migrating-${ it },Migrating to ${ it }>>\n" } %>
+<% includeVersions.each { print "include::migrate_${ it }.asciidoc[]\n" } %>

+ 23 - 0
build-tools-internal/src/test/java/org/elasticsearch/gradle/internal/release/GenerateReleaseNotesTaskTest.java

@@ -180,6 +180,29 @@ public class GenerateReleaseNotesTaskTest extends GradleUnitTestCase {
         );
     }
 
+    /**
+     * Check that when deriving a list of major.minor versions from git tags, the current unreleased version is included,
+     * but any higher version numbers are not.
+     */
+    @Test
+    public void getMinorVersions_includesCurrentButNotFutureVersions() {
+        // given:
+        when(gitWrapper.listVersions(anyString())).thenReturn(
+            Stream.of("8.0.0-alpha1", "8.0.0-alpha2", "8.0.0", "8.0.1", "8.1.0", "8.2.0", "8.2.1", "8.3.0", "8.3.1", "8.4.0")
+                .map(QualifiedVersion::of)
+        );
+
+        // when:
+        Set<QualifiedVersion> versions = GenerateReleaseNotesTask.getVersions(gitWrapper, "8.3.0-SNAPSHOT");
+        Set<MinorVersion> minorVersions = GenerateReleaseNotesTask.getMinorVersions(versions);
+
+        // then:
+        assertThat(
+            minorVersions,
+            containsInAnyOrder(new MinorVersion(8, 0), new MinorVersion(8, 1), new MinorVersion(8, 2), new MinorVersion(8, 3))
+        );
+    }
+
     /**
      * Check that the task partitions the list of files correctly by version for a prerelease.
      */

+ 2 - 31
docs/reference/migration/index.asciidoc

@@ -1,34 +1,4 @@
-[[breaking-changes]]
-= Migration guide
-
-This section discusses the changes that you need to be aware of to migrate
-your application to {version}. For more information about what's new in this
-release, see the <<release-highlights>> and <<es-release-notes>>.
-
-As {es} introduces new features and improves existing ones, the changes
-sometimes make older settings, APIs, and parameters obsolete. We typically
-deprecate obsolete functionality as part of a release. If possible, we support
-the deprecated functionality for several subsequent releases before removing it.
-This enables applications to continue working unchanged while you prepare to
-migrate away from the deprecated functionality.
-
-To get the most out of {es} and facilitate future upgrades, we strongly
-encourage migrating away from using deprecated functionality as soon as
-possible.
-
-To give you insight into what deprecated features you're using, {es}:
-
-- Returns a `Warn` HTTP header whenever you
-submit a request that uses deprecated functionality.
-- <<deprecation-logging, Logs deprecation warnings>> when
-deprecated functionality is used.
-- <<migration-api-deprecation, Provides a deprecation info API>>
-that scans a cluster's configuration
-and mappings for deprecated functionality.
-
-For more information about {minor-version},
-see the <<release-highlights>> and <<es-release-notes>>.
-For information about how to upgrade your cluster, see <<setup-upgrade>>.
+include::migration_intro.asciidoc[]
 
 * <<migrating-8.1,Migrating to 8.2>>
 * <<migrating-8.1,Migrating to 8.1>>
@@ -37,3 +7,4 @@ For information about how to upgrade your cluster, see <<setup-upgrade>>.
 include::migrate_8_2.asciidoc[]
 include::migrate_8_1.asciidoc[]
 include::migrate_8_0.asciidoc[]
+

+ 31 - 0
docs/reference/migration/migration_intro.asciidoc

@@ -0,0 +1,31 @@
+[[breaking-changes]]
+= Migration guide
+
+This section discusses the changes that you need to be aware of to migrate
+your application to {version}. For more information about what's new in this
+release, see the <<release-highlights>> and <<es-release-notes>>.
+
+As {es} introduces new features and improves existing ones, the changes
+sometimes make older settings, APIs, and parameters obsolete. We typically
+deprecate obsolete functionality as part of a release. If possible, we support
+the deprecated functionality for several subsequent releases before removing it.
+This enables applications to continue working unchanged while you prepare to
+migrate away from the deprecated functionality.
+
+To get the most out of {es} and facilitate future upgrades, we strongly
+encourage migrating away from using deprecated functionality as soon as
+possible.
+
+To give you insight into what deprecated features you're using, {es}:
+
+- Returns a `Warn` HTTP header whenever you
+submit a request that uses deprecated functionality.
+- <<deprecation-logging, Logs deprecation warnings>> when
+deprecated functionality is used.
+- <<migration-api-deprecation, Provides a deprecation info API>>
+that scans a cluster's configuration
+and mappings for deprecated functionality.
+
+For more information about {minor-version},
+see the <<release-highlights>> and <<es-release-notes>>.
+For information about how to upgrade your cluster, see <<setup-upgrade>>.