Maven CodeSnippet Plugin (#544)
* adding a plugin that can replace embedme and codesnippet usage in the azure-sdk CI builds
This commit is contained in:
Родитель
8e64eb7f0a
Коммит
6417a861e5
|
@ -290,6 +290,7 @@ PublishScripts/
|
|||
#*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
!packages/java-packages/
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
|
|
|
@ -7,9 +7,10 @@ This repository contains useful tools that the Azure SDK team utilizes across th
|
|||
| Package or Intent | Path | Description | Status |
|
||||
| ------------------------------ | ------------------------------------------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| doc-warden | [Readme](packages/python-packages/doc-warden/README.md) | A tool used to enforce readme standards across Azure SDK Repos. | [![Build Status](https://dev.azure.com/azure-sdk/public/_apis/build/status/108?branchName=master)](https://dev.azure.com/azure-sdk/public/_build/latest?definitionId=108&branchName=master) |
|
||||
| pixel-server | [Readme](/web/pixel-server/README.md) | A tiny ASP.NET Core site used to serve a pixel and record impressions. | Not Yet Enabled |
|
||||
| pixel-server | [Readme](web/pixel-server/README.md) | A tiny ASP.NET Core site used to serve a pixel and record impressions. | Not Yet Enabled |
|
||||
| pixel insertion tool | [Readme](scripts/python/readme_tracking/readme.md) | A tool used to insert the requests for images served by `pixel server`. | Not Yet Enabled |
|
||||
| Check Enforcer | [Readme](/tools/check-enforcer/README.md) | Manage GitHub check-runs in a mono-repo. | Not Yet Enabled |
|
||||
| Check Enforcer | [Readme](tools/check-enforcer/README.md) | Manage GitHub check-runs in a mono-repo. | Not Yet Enabled |
|
||||
| Maven Plugin for Snippets | [Readme](packages/java-packages/snippet-replacer-maven-plugin/README.md) | A Maven plugin that that updates code snippets referenced from javadoc comments. | Not Yet Enabled |
|
||||
|
||||
## Contributing
|
||||
|
||||
|
@ -26,3 +27,5 @@ For more information see the [Code of Conduct FAQ](https://opensource.microsoft.
|
|||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
[![Azure DevOps builds](https://img.shields.io/azure-devops/build/azure-sdk/internal/1372?label=eng%2Fcommon%20sync)](https://dev.azure.com/azure-sdk/internal/_build/latest?definitionId=1372&branchName=master)
|
||||
|
||||
C:/repo/sdk-tools/packages/java-packages/snippet-replacer-maven-plugin
|
|
@ -0,0 +1,133 @@
|
|||
# Snippet Replacer
|
||||
|
||||
`snippet-replacer-maven-plugin` allows java devs to reference actual java code in their javadoc comments. Developers running code written by the Azure team want their documentation to be useful. This plugin helps the Azure SDK team deliver on that promise by ensuring that code samples presented in doc-comments is always _actual running code_.
|
||||
|
||||
### How does it work?
|
||||
|
||||
First, reference the plugin in your maven project's `pom.xml` file.
|
||||
|
||||
```xml
|
||||
<plugin>
|
||||
<groupId>com.azure.tools</groupId>
|
||||
<artifactId>snippet-replacer-maven-plugin</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<configuration>
|
||||
<mode>update</mode>
|
||||
<targetDir>${project.basedir}</targetDir>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>process-sources</phase>
|
||||
<goals>
|
||||
<goal>snippet-engine</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
```
|
||||
|
||||
The plugin is intended to be run in the `process-sources` phase.
|
||||
|
||||
### The modes of operation
|
||||
|
||||
`snippet-replacer` has two modes, `update` and `verify`.
|
||||
|
||||
`update` mode runs during your build and _actually updates_ your Javadoc comments with referenced source code.
|
||||
`verify` mode is intended to be run during CI/PR builds. It will error a javadoc comment that is not updated.
|
||||
|
||||
## How to define a referencable snippet
|
||||
|
||||
Embed a beginning and end html comment wherever you want the source code inserted.
|
||||
|
||||
Within working java code, we have a snippet definition. The string after the `BEGIN:` or `END:` comments is an identifer that can be referenced from javadoc or readmes.
|
||||
|
||||
```
|
||||
public ConfigurationClient createSyncConfigurationClient() {
|
||||
String connectionString = getConnectionString();
|
||||
// BEGIN: com.azure.data.applicationconfig.configurationclient.instantiation
|
||||
ConfigurationClient configurationClient = new ConfigurationClientBuilder()
|
||||
.connectionString(connectionString)
|
||||
.buildClient();
|
||||
// END: com.azure.data.applicationconfig.configurationclient.instantiation
|
||||
return configurationClient;
|
||||
}
|
||||
```
|
||||
The above example defines a code snippet of identifier `com.azure.data.applicationconfig.configurationclient.instantiation`.
|
||||
|
||||
### Example of `update`
|
||||
|
||||
Within a javadoc comment, a snippet is referenced by a matching pair html comments.
|
||||
|
||||
```
|
||||
...
|
||||
* <p><strong>Instantiating a synchronous Configuration Client</strong></p>
|
||||
*
|
||||
* <!-- src_embed com.azure.core.http.rest.pagedflux.instantiation -->
|
||||
* <!-- end com.azure.core.http.rest.pagedflux.instantiation -->
|
||||
*
|
||||
* <p>View {@link ConfigurationClientBuilder this} for additional ways to construct the client.</p>
|
||||
*
|
||||
* @see ConfigurationClientBuilder
|
||||
*/
|
||||
@ServiceClient(builder = ConfigurationClientBuilder.class, serviceInterfaces = ConfigurationService.class)
|
||||
public final class ConfigurationClient {
|
||||
...
|
||||
```
|
||||
After update runs:
|
||||
```
|
||||
...
|
||||
* <p><strong>Instantiating a synchronous Configuration Client</strong></p>
|
||||
*
|
||||
* <!-- src_embed com.azure.core.http.rest.pagedflux.instantiation -->
|
||||
* <pre>
|
||||
* ConfigurationClient configurationClient = new ConfigurationClientBuilder()
|
||||
* .connectionString(connectionString)
|
||||
* .buildClient();
|
||||
* </pre>
|
||||
* <!-- end com.azure.core.http.rest.pagedflux.instantiation -->
|
||||
*
|
||||
* <p>View {@link ConfigurationClientBuilder this} for additional ways to construct the client.</p>
|
||||
*
|
||||
* @see ConfigurationClientBuilder
|
||||
*/
|
||||
@ServiceClient(builder = ConfigurationClientBuilder.class, serviceInterfaces = ConfigurationService.class)
|
||||
public final class ConfigurationClient {
|
||||
...
|
||||
```
|
||||
|
||||
The referenced code snippet will be embedded (with javadoc appropriate encoding) with the properly spaced code snippet.
|
||||
|
||||
### Example of `verify`
|
||||
|
||||
This mode is intended for use within CI systems. It will throw an error detailing where snippets are in need of updating. Any dev can rebuild your project with `update` mode and commit the result.
|
||||
|
||||
### Functionality against root README.md
|
||||
|
||||
While the plugin is mostly intended for use in Javadoc comments, it also will run update and verify operations against the file ${project.basedir}/README.md.
|
||||
|
||||
Example reference before update:
|
||||
|
||||
````
|
||||
```Java com.azure.data.applicationconfig.configurationclient.instantiation
|
||||
```
|
||||
````
|
||||
|
||||
Example of README.md after update:
|
||||
|
||||
````
|
||||
```Java com.azure.data.applicationconfig.configurationclient.instantiation
|
||||
ConfigurationClient configurationClient = new ConfigurationClientBuilder()
|
||||
.connectionString(connectionString)
|
||||
.buildClient();
|
||||
```
|
||||
````
|
||||
|
||||
Which Renders:
|
||||
|
||||
```Java com.azure.data.applicationconfig.configurationclient.instantiation
|
||||
ConfigurationClient configurationClient = new ConfigurationClientBuilder()
|
||||
.connectionString(connectionString)
|
||||
.buildClient();
|
||||
```
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
<?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>com.azure.tools</groupId>
|
||||
<artifactId>snippet-replacer-maven-plugin</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<packaging>maven-plugin</packaging>
|
||||
<name>snippet-replacer-maven-plugin Maven Plugin</name>
|
||||
|
||||
<url>https://github.com/azure/azure-sdk-tools</url>
|
||||
|
||||
<prerequisites>
|
||||
<maven>${maven.version}</maven>
|
||||
</prerequisites>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<maven.version>3.3.9</maven.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-plugin-api</artifactId>
|
||||
<version>${maven.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-core</artifactId>
|
||||
<version>${maven.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-artifact</artifactId>
|
||||
<version>${maven.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-compat</artifactId>
|
||||
<version>${maven.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.plugin-tools</groupId>
|
||||
<artifactId>maven-plugin-annotations</artifactId>
|
||||
<version>3.6.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.plugin-testing</groupId>
|
||||
<artifactId>maven-plugin-testing-harness</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<testResources>
|
||||
<testResource>
|
||||
<directory>${basedir}/src/test/resources</directory>
|
||||
</testResource>
|
||||
</testResources>
|
||||
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_maven-plugin_packaging -->
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-plugin-plugin</artifactId>
|
||||
<version>3.6.0</version>
|
||||
<configuration>
|
||||
<skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-install-plugin</artifactId>
|
||||
<version>2.5.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.8.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-invoker-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-plugin-plugin</artifactId>
|
||||
<version>3.6.0</version>
|
||||
<configuration>
|
||||
<!-- <goalPrefix>maven-archetype-plugin</goalPrefix> -->
|
||||
<skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>mojo-descriptor</id>
|
||||
<goals>
|
||||
<goal>descriptor</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>help-goal</id>
|
||||
<goals>
|
||||
<goal>helpmojo</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,33 @@
|
|||
package azuresdk.plugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SnippetDictionary {
|
||||
private HashMap<String, List<String>> _snippetDictionary = new HashMap<>();
|
||||
|
||||
public boolean isActive() {
|
||||
return !_snippetDictionary.isEmpty();
|
||||
}
|
||||
|
||||
public void beginSnippet(String key) {
|
||||
if (!this._snippetDictionary.containsKey((key))) {
|
||||
this._snippetDictionary.put(key, new ArrayList<>());
|
||||
}
|
||||
}
|
||||
|
||||
public void processLine(String line) {
|
||||
for (Map.Entry<String, List<String>> entry : this._snippetDictionary.entrySet()) {
|
||||
entry.getValue().add(line);
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> finalizeSnippet(String key) {
|
||||
List<String> value = this._snippetDictionary.get(key);
|
||||
this._snippetDictionary.remove(key);
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package azuresdk.plugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SnippetOperationResult<T> {
|
||||
public T result;
|
||||
List<VerifyResult> errorList;
|
||||
|
||||
public SnippetOperationResult(T resultObject, List<VerifyResult> errors){
|
||||
super();
|
||||
this.result = resultObject;
|
||||
this.errorList = errors;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package azuresdk.plugin;
|
||||
|
||||
|
||||
import org.apache.maven.plugin.AbstractMojo;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
|
||||
import org.apache.maven.plugins.annotations.LifecyclePhase;
|
||||
import org.apache.maven.plugins.annotations.Mojo;
|
||||
import org.apache.maven.plugins.annotations.Parameter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
@Mojo( name = "snippet-engine", defaultPhase = LifecyclePhase.PROCESS_SOURCES )
|
||||
public class SnippetPluginEntry
|
||||
extends AbstractMojo
|
||||
{
|
||||
@Parameter( property = "report.mode", required = true )
|
||||
private String mode;
|
||||
|
||||
@Parameter( defaultValue = "${project.basedir}", property = "report.targetDir", required = true )
|
||||
private File targetDir;
|
||||
|
||||
public void execute()
|
||||
{
|
||||
try {
|
||||
SnippetReplacer replacer = new SnippetReplacer(mode, targetDir, getLog());
|
||||
getLog().info("Completed Execution for Snippet Replacer");
|
||||
} catch (Exception e) {
|
||||
getLog().error(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,520 @@
|
|||
package azuresdk.plugin;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.*;
|
||||
import java.util.regex.*;
|
||||
|
||||
import com.google.common.base.Verify;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.logging.Log;
|
||||
|
||||
public class SnippetReplacer {
|
||||
public final static Pattern SNIPPET_DEF_BEGIN = Pattern.compile("\\s*\\/\\/\\s*BEGIN\\:\\s+([a-zA-Z0-9\\.\\#\\-\\_]*)\\s*");
|
||||
public final static Pattern SNIPPET_DEF_END = Pattern.compile("\\s*\\/\\/\\s*END\\:\\s+([a-zA-Z0-9\\.\\#\\-\\_]*)\\s*");
|
||||
public final static Pattern SNIPPET_SRC_CALL_BEGIN = Pattern.compile("(\\s*)\\*?\\s*<!--\\s+src_embed\\s+([a-zA-Z0-9\\.\\#\\-\\_]*)\\s*-->");
|
||||
public final static Pattern SNIPPET_SRC_CALL_END = Pattern.compile("(\\s*)\\*?\\s*<!--\\s+end\\s+([a-zA-Z0-9\\.\\#\\-\\_]*)\\s*-->");
|
||||
public final static Pattern SNIPPET_README_CALL_BEGIN = Pattern.compile("```(\\s*)?Java\\s+([a-zA-Z0-9\\.\\#\\-\\_]*)\\s*");
|
||||
public final static Pattern SNIPPET_README_CALL_END = Pattern.compile("```");
|
||||
public final static Pattern WHITESPACE_EXTRACTION = Pattern.compile("(\\s*)(.*)");
|
||||
|
||||
private static PathMatcher SAMPLE_PATH_GLOB = FileSystems.getDefault().getPathMatcher("glob:**/src/samples/java/**/*.java");
|
||||
private static PathMatcher JAVA_GLOB = FileSystems.getDefault().getPathMatcher("glob:**/*.java");
|
||||
|
||||
private static HashMap<String, String> REPLACEMENT_SET = new HashMap<String, String>(){{
|
||||
put("\"", """);
|
||||
put(">", ">");
|
||||
put("<", "<");
|
||||
put("@", "{@literal @}");
|
||||
put("{", "{");
|
||||
put("}", "}");
|
||||
put("(", "(");
|
||||
put(")", ")");
|
||||
put("/", "/");
|
||||
put("\\", "\");
|
||||
}};
|
||||
|
||||
public SnippetReplacer(){}
|
||||
|
||||
public SnippetReplacer(String mode, File folderToVerify, Log logger) throws MojoExecutionException, IOException {
|
||||
switch (mode) {
|
||||
case "update":
|
||||
this.runUpdate(folderToVerify, logger);
|
||||
break;
|
||||
case "verify":
|
||||
this.runVerification(folderToVerify, logger);
|
||||
break;
|
||||
default:
|
||||
throw new MojoExecutionException(String.format("Unrecognized snippet-replacer mode: %s.", mode));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The "verification" operation encapsulated by this function is as follows.
|
||||
*
|
||||
* 1. Scan under the target direction for all discovered code snippet DEFINITIONS
|
||||
* 2. Examine all snippet CALLS, finding where updates are needed.
|
||||
* 3. Report all discovered snippets in need of update as well as all bad snippet calls
|
||||
*
|
||||
* A "bad snippet call" is simply calling for a snippet whose Id has no definition.
|
||||
*
|
||||
* See {@link #runUpdate(File, Log)} for details on actually defining and calling snippets.
|
||||
*/
|
||||
public void runVerification(File folderToVerify, Log logger) throws IOException, MojoExecutionException {
|
||||
List<Path> allLocatedJavaFiles = glob(folderToVerify.toPath(), JAVA_GLOB);
|
||||
List<Path> snippetSources = globFiles(allLocatedJavaFiles, SAMPLE_PATH_GLOB);
|
||||
List<VerifyResult> snippetsNeedingUpdate = new ArrayList<>();
|
||||
HashMap<String, List<String>> foundSnippets = new HashMap<>();
|
||||
List<VerifyResult> badSnippetCalls = new ArrayList<>();
|
||||
|
||||
// scan the sample files for all the snippet files
|
||||
foundSnippets = this.getAllSnippets(snippetSources);
|
||||
|
||||
// walk across all the java files, run UpdateSrcSnippets
|
||||
for (Path sourcePath : allLocatedJavaFiles) {
|
||||
SnippetOperationResult<List<VerifyResult>> verifyResult = this.verifySrcSnippets(sourcePath, foundSnippets);
|
||||
snippetsNeedingUpdate.addAll(verifyResult.result);
|
||||
badSnippetCalls.addAll(verifyResult.errorList);
|
||||
}
|
||||
|
||||
// now find folderToVerify/README.md
|
||||
// run Update ReadmeSnippets on that
|
||||
File readmeInBaseDir = new File(folderToVerify, "README.md");
|
||||
SnippetOperationResult<List<VerifyResult>> rdmeResult = this.verifyReadmeSnippets(readmeInBaseDir.toPath(), foundSnippets);
|
||||
snippetsNeedingUpdate.addAll(rdmeResult.result);
|
||||
badSnippetCalls.addAll(rdmeResult.errorList);
|
||||
|
||||
if (snippetsNeedingUpdate.size() > 0 || badSnippetCalls.size() > 0) {
|
||||
for (VerifyResult result : snippetsNeedingUpdate) {
|
||||
logger.error(String.format("SnippetId %s needs update in file %s.", result.SnippetWithIssues, result.ReadmeLocation.toString()));
|
||||
}
|
||||
|
||||
for (VerifyResult result : badSnippetCalls) {
|
||||
logger.error(String.format("Unable to locate snippet with Id of %s. Reference in %s", result.SnippetWithIssues, result.ReadmeLocation.toString()));
|
||||
}
|
||||
|
||||
throw new MojoExecutionException("Snippet-Replacer has encountered errors, check above output for details.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method encapsulates the "update" lifecycle of the snippet-replacer plugin.
|
||||
*
|
||||
* Given a root folder, the plugin will scan for snippet DEFINITIONS or snippet CALLS. Once a snippet definition
|
||||
* index has been formulated, all java files located under the target directory will have snippet CALLS updated with
|
||||
* the source from the DEFINITIONS.
|
||||
*
|
||||
* <p><strong>Snippet Definition</strong></p>
|
||||
*
|
||||
* A snippet definition is delineated by BEGIN and END comments directly in your java source.
|
||||
* Example:
|
||||
* <pre>
|
||||
* // BEGIN: com.azure.data.applicationconfig.configurationclient.instantiation
|
||||
* ConfigurationClient configurationClient = new ConfigurationClientBuilder()
|
||||
* .connectionString(connectionString)
|
||||
* .buildClient();
|
||||
* // END: com.azure.data.applicationconfig.configurationclient.instantiation
|
||||
* </pre>
|
||||
*
|
||||
* <p><strong>Calling a Snippet</strong></p>
|
||||
*
|
||||
* From within a javadoc comment, embed an html comment
|
||||
* /*
|
||||
* <!-- src_embed com.azure.data.applicationconfig.configurationclient.instantiation -->
|
||||
* ConfigurationClient configurationClient = new ConfigurationClientBuilder()
|
||||
* .connectionString(connectionString)
|
||||
* .buildClient();
|
||||
* <!-- end com.azure.data.applicationconfig.configurationclient.instantiation -->
|
||||
* Other javadoc details perhaps.
|
||||
* */
|
||||
* public void myfunction()
|
||||
* </pre>
|
||||
*
|
||||
* After finishing update operations, this function will throw a MojoExecutionException after reporting all snippet
|
||||
* CALLS that have no DEFINITION.
|
||||
*/
|
||||
public void runUpdate(File folderToVerify, Log logger) throws IOException, MojoExecutionException {
|
||||
List<Path> allLocatedJavaFiles = glob(folderToVerify.toPath(), JAVA_GLOB);
|
||||
List<Path> snippetSources = globFiles(allLocatedJavaFiles, SAMPLE_PATH_GLOB);
|
||||
HashMap<String, List<String>> foundSnippets = new HashMap<String, List<String>>();
|
||||
List<VerifyResult> badSnippetCalls = new ArrayList<>();
|
||||
|
||||
// scan the sample files for all the snippet files
|
||||
foundSnippets = this.getAllSnippets(snippetSources);
|
||||
|
||||
// walk across all the java files, run UpdateSrcSnippets
|
||||
for (Path sourcePath : allLocatedJavaFiles) {
|
||||
badSnippetCalls.addAll(this.updateSrcSnippets(sourcePath, foundSnippets));
|
||||
}
|
||||
|
||||
// now find folderToVerify/README.md
|
||||
// run Update ReadmeSnippets on that
|
||||
File readmeInBaseDir = new File(folderToVerify, "README.md");
|
||||
badSnippetCalls.addAll(this.updateReadmeSnippets(readmeInBaseDir.toPath(), foundSnippets));
|
||||
|
||||
if (badSnippetCalls.size() > 0) {
|
||||
for (VerifyResult result : badSnippetCalls) {
|
||||
logger.error(String.format("Unable to locate snippet with Id of %s. Reference in %s", result.SnippetWithIssues, result.ReadmeLocation.toString()));
|
||||
}
|
||||
throw new MojoExecutionException("Discovered snippets in need of updating. Please run this plugin in update mode and commit the changes.");
|
||||
}
|
||||
}
|
||||
|
||||
public List<VerifyResult> updateReadmeSnippets(Path file, HashMap<String, List<String>> snippetMap) throws IOException, MojoExecutionException {
|
||||
List<String> lines = Files.readAllLines(file, StandardCharsets.UTF_8);
|
||||
SnippetOperationResult<StringBuilder> opResult = this.updateSnippets(file,
|
||||
lines,
|
||||
SNIPPET_README_CALL_BEGIN,
|
||||
SNIPPET_README_CALL_END,
|
||||
snippetMap,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
"",
|
||||
true);
|
||||
|
||||
if (opResult.result != null) {
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(file, StandardCharsets.UTF_8)) {
|
||||
writer.write(opResult.result.toString());
|
||||
}
|
||||
}
|
||||
|
||||
return opResult.errorList;
|
||||
}
|
||||
|
||||
public List<VerifyResult> updateSrcSnippets(Path file, HashMap<String, List<String>> snippetMap) throws IOException, MojoExecutionException {
|
||||
List<String> lines = Files.readAllLines(file, StandardCharsets.UTF_8);
|
||||
SnippetOperationResult<StringBuilder> opResult = this.updateSnippets(file,
|
||||
lines,
|
||||
SNIPPET_SRC_CALL_BEGIN,
|
||||
SNIPPET_SRC_CALL_END,
|
||||
snippetMap,
|
||||
"<pre>",
|
||||
"</pre>",
|
||||
1,
|
||||
"* ",
|
||||
false);
|
||||
|
||||
if (opResult.result != null) {
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(file, StandardCharsets.UTF_8)) {
|
||||
writer.write(opResult.result.toString());
|
||||
}
|
||||
}
|
||||
|
||||
return opResult.errorList;
|
||||
}
|
||||
|
||||
public SnippetOperationResult<StringBuilder> updateSnippets(Path file, List<String> lines, Pattern beginRegex, Pattern endRegex, HashMap<String, List<String>> snippetMap,
|
||||
String preFence, String postFence, int prefixGroupNum, String additionalLinePrefix, boolean disableEscape) {
|
||||
|
||||
List<VerifyResult> badSnippetCalls = new ArrayList<>();
|
||||
StringBuilder modifiedLines = new StringBuilder();
|
||||
boolean inSnippet = false;
|
||||
boolean needsAmend = false;
|
||||
String lineSep = System.lineSeparator();
|
||||
String currentSnippetId = "";
|
||||
|
||||
for (String line : lines) {
|
||||
Matcher begin = beginRegex.matcher(line);
|
||||
Matcher end = endRegex.matcher(line);
|
||||
|
||||
if (begin.matches()) {
|
||||
modifiedLines.append(line + lineSep);
|
||||
currentSnippetId = begin.group(2);
|
||||
inSnippet = true;
|
||||
}
|
||||
else if (end.matches()) {
|
||||
if (inSnippet) {
|
||||
List<String> newSnippets = null;
|
||||
if (snippetMap.containsKey(currentSnippetId)) {
|
||||
newSnippets = snippetMap.get(currentSnippetId);
|
||||
} else {
|
||||
badSnippetCalls.add(new VerifyResult(file, currentSnippetId));
|
||||
needsAmend = true;
|
||||
inSnippet = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
List<String> modifiedSnippets = new ArrayList<>();
|
||||
|
||||
// We use this additional prefix because in src snippet cases we need to prespace
|
||||
// for readme snippet cases we DONT need the prespace at all.
|
||||
String linePrefix = this.prefixFunction(end, prefixGroupNum, additionalLinePrefix);
|
||||
|
||||
for (String snippet : this.respaceLines(newSnippets)) {
|
||||
String moddedSnippet = disableEscape ? snippet : this.escapeString(snippet);
|
||||
modifiedSnippets.add(moddedSnippet.length() == 0
|
||||
? linePrefix.replaceAll("[\\s]+$", "") + lineSep
|
||||
: linePrefix + moddedSnippet + lineSep);
|
||||
}
|
||||
|
||||
if (preFence != null && preFence.length() > 0) {
|
||||
modifiedLines.append(linePrefix + preFence + lineSep);
|
||||
}
|
||||
|
||||
modifiedLines.append(String.join("", modifiedSnippets));
|
||||
|
||||
if (postFence != null && postFence.length() > 0) {
|
||||
modifiedLines.append(linePrefix + postFence + lineSep);
|
||||
}
|
||||
|
||||
modifiedLines.append(line + lineSep);
|
||||
needsAmend = true;
|
||||
inSnippet = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (inSnippet) {
|
||||
// do nothing. we'll write everything at the end,
|
||||
// we'd do a comparison here if we were verifying
|
||||
}
|
||||
else {
|
||||
modifiedLines.append(line + lineSep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needsAmend) {
|
||||
return new SnippetOperationResult<StringBuilder>(modifiedLines, badSnippetCalls);
|
||||
}
|
||||
else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public SnippetOperationResult<List<VerifyResult>> verifyReadmeSnippets(Path file, HashMap<String, List<String>> snippetMap) throws IOException, MojoExecutionException {
|
||||
List<String> lines = Files.readAllLines(file, StandardCharsets.UTF_8);
|
||||
return this.verifySnippets(file, lines, SNIPPET_README_CALL_BEGIN, SNIPPET_README_CALL_END, snippetMap, "", "", 0, "", true);
|
||||
}
|
||||
|
||||
public SnippetOperationResult<List<VerifyResult>> verifySrcSnippets(Path file, HashMap<String, List<String>> snippetMap) throws IOException, MojoExecutionException {
|
||||
List<String> lines = Files.readAllLines(file, StandardCharsets.UTF_8);
|
||||
return this.verifySnippets(file, lines, SNIPPET_SRC_CALL_BEGIN, SNIPPET_SRC_CALL_END, snippetMap, "<pre>", "</pre>", 1, "* ", false);
|
||||
}
|
||||
|
||||
public SnippetOperationResult<List<VerifyResult>> verifySnippets(Path file, List<String> lines, Pattern beginRegex, Pattern endRegex,
|
||||
HashMap<String, List<String>> snippetMap, String preFence, String postFence, int prefixGroupNum,
|
||||
String additionalLinePrefix, boolean disableEscape) {
|
||||
|
||||
boolean inSnippet = false;
|
||||
String lineSep = System.lineSeparator();
|
||||
List<String> currentSnippetSet = null;
|
||||
List<VerifyResult> foundIssues = new ArrayList<>();
|
||||
List<VerifyResult> badSnippetCalls = new ArrayList<>();
|
||||
String currentSnippetId = "";
|
||||
|
||||
for (String line : lines) {
|
||||
Matcher begin = beginRegex.matcher(line);
|
||||
Matcher end = endRegex.matcher(line);
|
||||
|
||||
if (begin.matches()) {
|
||||
currentSnippetId = begin.group(2);
|
||||
inSnippet = true;
|
||||
currentSnippetSet = new ArrayList<>();
|
||||
}
|
||||
else if (end.matches()) {
|
||||
if (inSnippet) {
|
||||
List<String> newSnippets;
|
||||
if (snippetMap.containsKey(currentSnippetId)) {
|
||||
newSnippets = snippetMap.get(currentSnippetId);
|
||||
} else {
|
||||
badSnippetCalls.add(new VerifyResult(file, currentSnippetId));
|
||||
inSnippet = false;
|
||||
currentSnippetSet = null;
|
||||
continue;
|
||||
}
|
||||
List<String> modifiedSnippets = new ArrayList<>();
|
||||
|
||||
// We use this additional prefix because in src snippet cases we need to prespace
|
||||
// for readme snippet cases we DONT need the prespace at all.
|
||||
String linePrefix = this.prefixFunction(end, prefixGroupNum, additionalLinePrefix);
|
||||
|
||||
for (String snippet : this.respaceLines(newSnippets)) {
|
||||
String moddedSnippet = disableEscape ? snippet : this.escapeString(snippet);
|
||||
modifiedSnippets.add(moddedSnippet.length() == 0
|
||||
? linePrefix.replaceAll("[\\s]+$", "") + lineSep
|
||||
: linePrefix + moddedSnippet + lineSep);
|
||||
}
|
||||
|
||||
Collections.sort(modifiedSnippets);
|
||||
Collections.sort(currentSnippetSet);
|
||||
|
||||
if (!modifiedSnippets.equals(currentSnippetSet)) {
|
||||
foundIssues.add(new VerifyResult(file, currentSnippetId));
|
||||
}
|
||||
|
||||
inSnippet = false;
|
||||
currentSnippetSet = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (inSnippet) {
|
||||
if (preFence.length() > 0 && postFence.length() > 0) {
|
||||
if (!line.contains(preFence) && !line.contains(postFence)) {
|
||||
currentSnippetSet.add(line + lineSep);
|
||||
}
|
||||
}
|
||||
else {
|
||||
currentSnippetSet.add(line + lineSep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new SnippetOperationResult<List<VerifyResult>>(foundIssues, badSnippetCalls);
|
||||
}
|
||||
|
||||
public HashMap<String, List<String>> getAllSnippets(List<Path> snippetSources) throws IOException, MojoExecutionException {
|
||||
HashMap<String, List<String>> locatedSnippets = new HashMap<>();
|
||||
List<VerifyResult> detectedIssues = new ArrayList<>();
|
||||
|
||||
for(Path samplePath: snippetSources){
|
||||
List<String> fileContent = Files.readAllLines(samplePath, StandardCharsets.UTF_8);
|
||||
HashMap<String, List<String>> tempSnippetMap = new HashMap<>();
|
||||
SnippetDictionary snippetReader = new SnippetDictionary();
|
||||
int counter = 0;
|
||||
|
||||
for (String line : fileContent) {
|
||||
Matcher begin = SNIPPET_DEF_BEGIN.matcher(line);
|
||||
Matcher end = SNIPPET_DEF_END.matcher(line);
|
||||
|
||||
if (begin.matches() ){
|
||||
String id_beginning = begin.group(1);
|
||||
snippetReader.beginSnippet((id_beginning));
|
||||
}
|
||||
else if (end.matches()) {
|
||||
String id_ending = end.group(1);
|
||||
List<String> snippetContent = snippetReader.finalizeSnippet((id_ending));
|
||||
if (!tempSnippetMap.containsKey((id_ending))) {
|
||||
tempSnippetMap.put(id_ending, snippetContent);
|
||||
}
|
||||
else {
|
||||
// detect duplicate in file
|
||||
detectedIssues.add(new VerifyResult(samplePath, id_ending));
|
||||
}
|
||||
}
|
||||
else if (snippetReader.isActive()) {
|
||||
snippetReader.processLine(line);
|
||||
}
|
||||
|
||||
counter++;
|
||||
}
|
||||
|
||||
// we need to examine them individually, as we want to get a complete list of all the duplicates in a run
|
||||
for (String snippetId : tempSnippetMap.keySet()) {
|
||||
if (!locatedSnippets.containsKey(snippetId)) {
|
||||
locatedSnippets.put(snippetId, tempSnippetMap.get(snippetId));
|
||||
}
|
||||
else {
|
||||
// detect duplicate across multiple files
|
||||
detectedIssues.add(new VerifyResult(samplePath, snippetId));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (detectedIssues.size() > 0) {
|
||||
throw new MojoExecutionException("Duplicate Snippet Definitions Detected. " + System.lineSeparator() + this.getErrorString(detectedIssues));
|
||||
}
|
||||
|
||||
return locatedSnippets;
|
||||
}
|
||||
|
||||
private String getErrorString(List<VerifyResult> errors) {
|
||||
StringBuilder results = new StringBuilder();
|
||||
|
||||
for (VerifyResult result : errors) {
|
||||
results.append(String.format("Duplicate snippetId %s detected in %s.", result.SnippetWithIssues, result.ReadmeLocation.toString()) + System.lineSeparator());
|
||||
}
|
||||
|
||||
return results.toString();
|
||||
}
|
||||
|
||||
private List<String> respaceLines(List<String> snippetText) {
|
||||
// get List of all the the leading whitespace in the sample
|
||||
// toss out lines that are empty (as they shouldn't mess with the minimum)
|
||||
String minWhitespace = null;
|
||||
List<String> modifiedStrings = new ArrayList<>();
|
||||
|
||||
for (String snippetLine : snippetText) {
|
||||
// only look at non-whitespace only strings for the min indent
|
||||
if(snippetLine.trim().length() != 0) {
|
||||
Matcher leadSpaceMatch = WHITESPACE_EXTRACTION.matcher(snippetLine);
|
||||
|
||||
if (leadSpaceMatch.matches()) {
|
||||
String leadSpace = leadSpaceMatch.group(1);
|
||||
|
||||
if (minWhitespace == null || leadSpace.length() < minWhitespace.length())
|
||||
minWhitespace = leadSpace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (String snippetLine : snippetText) {
|
||||
modifiedStrings.add(snippetLine.replaceFirst(minWhitespace, ""));
|
||||
}
|
||||
|
||||
return modifiedStrings;
|
||||
}
|
||||
|
||||
private int getEndIndex(List<String> lines, int startIndex) {
|
||||
for (int i = startIndex; i < lines.size(); i++) {
|
||||
Matcher end = SNIPPET_SRC_CALL_END.matcher(lines.get(i));
|
||||
if (end.matches())
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private String prefixFunction(Matcher match, int groupNum, String additionalPrefix) {
|
||||
// if we pass -1 as the matcher groupNum, we don't want any prefix at all
|
||||
if (match == null || groupNum < 1) {
|
||||
return "";
|
||||
} else {
|
||||
return match.group(groupNum) + additionalPrefix;
|
||||
}
|
||||
}
|
||||
|
||||
private String escapeString(String target) {
|
||||
if (target != null && target.trim().length() > 0) {
|
||||
for (String key : this.REPLACEMENT_SET.keySet()) {
|
||||
target = target.replace(key, REPLACEMENT_SET.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
private List<Path> glob(Path rootFolder, PathMatcher pathMatcher) throws IOException {
|
||||
List<Path> locatedPaths = new ArrayList<>();
|
||||
|
||||
Files.walkFileTree(rootFolder, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
if (pathMatcher.matches(file)) {
|
||||
locatedPaths.add(file);
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
@Override
|
||||
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
|
||||
return locatedPaths;
|
||||
}
|
||||
|
||||
private List<Path> globFiles(List<Path> paths, PathMatcher pathMatcher) throws IOException {
|
||||
List<Path> locatedPaths = new ArrayList<>();
|
||||
|
||||
for (Path path : paths) {
|
||||
if (pathMatcher.matches(path)) {
|
||||
locatedPaths.add(path);
|
||||
}
|
||||
};
|
||||
|
||||
return locatedPaths;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package azuresdk.plugin;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class VerifyResult {
|
||||
public String SnippetWithIssues;
|
||||
public Path ReadmeLocation;
|
||||
|
||||
public VerifyResult(Path readmeLocation, String snippetIdWithIssues) {
|
||||
this.ReadmeLocation = readmeLocation;
|
||||
this.SnippetWithIssues = snippetIdWithIssues;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
package azuresdk.plugin;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class SnippetReplacerTests {
|
||||
|
||||
private Path _getPathToResource(String relativeLocation){
|
||||
String pathToTestFile = SnippetReplacerTests.class.getResource(relativeLocation).getPath();
|
||||
|
||||
if(pathToTestFile.startsWith("/")){
|
||||
pathToTestFile = pathToTestFile.substring(1);
|
||||
}
|
||||
|
||||
return Paths.get(pathToTestFile);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSrcParse()
|
||||
throws Exception
|
||||
{
|
||||
Path testFile = _getPathToResource("../../project-to-test/basic_src_snippet_parse.txt");
|
||||
HashMap<String, List<String>> foundSnippets = new SnippetReplacer().getAllSnippets(
|
||||
new ArrayList<Path>(Arrays.asList(testFile.toAbsolutePath())));
|
||||
|
||||
assertTrue(foundSnippets.size() == 3);
|
||||
assertTrue(
|
||||
foundSnippets.get("com.azure.data.applicationconfig.configurationclient.instantiation").size() == 3);
|
||||
assertTrue(
|
||||
foundSnippets.get("com.azure.data.appconfiguration.ConfigurationClient.addConfigurationSetting#String-String-String").size() == 3);
|
||||
assertTrue(foundSnippets.get("com.azure.core.http.rest.pagedflux.instantiation").size() == 9);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSrcInsertion()
|
||||
throws Exception
|
||||
{
|
||||
/*
|
||||
Ensures html encoding, empty and populated snippets replacement
|
||||
*/
|
||||
Path snippetSourceFile = _getPathToResource("../../project-to-test/basic_src_snippet_parse.txt");
|
||||
Path codeForReplacement = _getPathToResource("../../project-to-test/basic_src_snippet_insertion_before.txt");
|
||||
Path expectedOutCome = _getPathToResource("../../project-to-test/basic_src_snippet_insertion_after.txt");
|
||||
SnippetReplacer testReplacer = new SnippetReplacer();
|
||||
List<String> testLines = Files.readAllLines(codeForReplacement, StandardCharsets.UTF_8);
|
||||
byte[] rawBytes = Files.readAllBytes(expectedOutCome);
|
||||
String expectedString = new String(rawBytes, StandardCharsets.UTF_8);
|
||||
|
||||
HashMap<String, List<String>> foundSnippets = testReplacer.getAllSnippets(
|
||||
new ArrayList<Path>(Arrays.asList(snippetSourceFile.toAbsolutePath())));
|
||||
SnippetOperationResult<StringBuilder> opResult = testReplacer.updateSnippets(codeForReplacement, testLines,
|
||||
testReplacer.SNIPPET_SRC_CALL_BEGIN, testReplacer.SNIPPET_SRC_CALL_END, foundSnippets,
|
||||
"<pre>", "</pre>", 1, "* ", false);
|
||||
|
||||
assertTrue(opResult.result != null);
|
||||
assertEquals(opResult.result.toString(),expectedString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadmeInsertion()
|
||||
throws Exception {
|
||||
/*
|
||||
Ensures html encoding, empty and populated snippets replacement
|
||||
*/
|
||||
Path snippetSourceFile = _getPathToResource("../../project-to-test/basic_src_snippet_parse.txt");
|
||||
Path codeForReplacement = _getPathToResource("../../project-to-test/basic_readme_insertion_before.txt");
|
||||
Path expectedOutCome = _getPathToResource("../../project-to-test/basic_readme_insertion_after.txt");
|
||||
SnippetReplacer testReplacer = new SnippetReplacer();
|
||||
List<String> testLines = Files.readAllLines(codeForReplacement, StandardCharsets.UTF_8);
|
||||
byte[] rawBytes = Files.readAllBytes(expectedOutCome);
|
||||
String expectedString = new String(rawBytes, StandardCharsets.UTF_8);
|
||||
|
||||
HashMap<String, List<String>> foundSnippets = testReplacer.getAllSnippets(
|
||||
new ArrayList<Path>(Arrays.asList(snippetSourceFile.toAbsolutePath())));
|
||||
SnippetOperationResult<StringBuilder> opResult = testReplacer.updateSnippets(codeForReplacement, testLines,
|
||||
testReplacer.SNIPPET_README_CALL_BEGIN, testReplacer.SNIPPET_README_CALL_END, foundSnippets,
|
||||
"", "", 0, "", true);
|
||||
|
||||
assertTrue(opResult.result != null);
|
||||
assertTrue(opResult.result.toString().equals(expectedString));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadmeVerification() throws Exception {
|
||||
Path snippetSourceFile = _getPathToResource("../../project-to-test/basic_src_snippet_parse.txt");
|
||||
Path verification = _getPathToResource("../../project-to-test/readme_insertion_verification_failure.txt");
|
||||
SnippetReplacer testReplacer = new SnippetReplacer();
|
||||
List<String> testLines = Files.readAllLines(verification, StandardCharsets.UTF_8);
|
||||
|
||||
HashMap<String, List<String>> foundSnippets = testReplacer.getAllSnippets(
|
||||
new ArrayList<Path>(Arrays.asList(snippetSourceFile.toAbsolutePath())));
|
||||
SnippetOperationResult<List<VerifyResult>> opResult = testReplacer.verifySnippets(verification, testLines,
|
||||
testReplacer.SNIPPET_README_CALL_BEGIN, testReplacer.SNIPPET_README_CALL_END, foundSnippets,
|
||||
"", "", 0, "", true);
|
||||
|
||||
assertTrue(opResult.result != null);
|
||||
assertTrue(opResult.result.size() == 1);
|
||||
assertTrue(opResult.result.get(0).SnippetWithIssues.equals("com.azure.core.http.rest.pagedflux.instantiation"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSrcVerification() throws Exception {
|
||||
Path snippetSourceFile = _getPathToResource("../../project-to-test/basic_src_snippet_parse.txt");
|
||||
Path verification = _getPathToResource("../../project-to-test/src_insertion_verification_failure.txt");
|
||||
SnippetReplacer testReplacer = new SnippetReplacer();
|
||||
List<String> testLines = Files.readAllLines(verification, StandardCharsets.UTF_8);
|
||||
|
||||
HashMap<String, List<String>> foundSnippets = testReplacer.getAllSnippets(
|
||||
new ArrayList<Path>(Arrays.asList(snippetSourceFile.toAbsolutePath())));
|
||||
SnippetOperationResult<List<VerifyResult>> opResult = testReplacer.verifySnippets(verification, testLines,
|
||||
testReplacer.SNIPPET_SRC_CALL_BEGIN, testReplacer.SNIPPET_SRC_CALL_END, foundSnippets,
|
||||
"<pre>", "</pre>", 1, "* ", false);
|
||||
|
||||
assertTrue(opResult.result != null);
|
||||
assertTrue(opResult.result.size() == 2);
|
||||
assertTrue(opResult.result.get(0).SnippetWithIssues.equals("com.azure.data.applicationconfig.configurationclient.instantiation"));
|
||||
assertTrue(opResult.result.get(1).SnippetWithIssues.equals("com.azure.core.http.rest.pagedflux.instantiation"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptySnippetWorks() throws Exception {
|
||||
Path single = _getPathToResource("../../project-to-test/empty_snippet_def.txt");
|
||||
|
||||
List<Path> srcs = new ArrayList<Path>(Arrays.asList(single.toAbsolutePath()));
|
||||
HashMap<String, List<String>> foundSnippets = new SnippetReplacer().getAllSnippets(srcs);
|
||||
|
||||
assertTrue(foundSnippets.keySet().size() == 1);
|
||||
assertTrue(foundSnippets.containsKey("com.azure.data.applicationconfig.configurationclient.testEmpty"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void duplicateSnippetsCrashWithSingleFile() {
|
||||
try {
|
||||
Path single = _getPathToResource("../../project-to-test/duplicate_snippet_src.txt");
|
||||
|
||||
List<Path> srcs = new ArrayList<Path>(Arrays.asList(single.toAbsolutePath()));
|
||||
HashMap<String, List<String>> foundSnippets = new SnippetReplacer().getAllSnippets(srcs);
|
||||
} catch (Exception e){
|
||||
// check for snippet id in string
|
||||
assertTrue(e.toString().contains("com.azure.data.applicationconfig.configurationclient.instantiation"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void duplicateSnippetsCrashWithMultipleFiles() {
|
||||
try {
|
||||
Path single = _getPathToResource("../../project-to-test/duplicate_snippet_src.txt");
|
||||
Path multiple = _getPathToResource("../../project-to-test/duplicate_snippet_src_multiple.txt");
|
||||
|
||||
List<Path> srcs = new ArrayList<Path>(Arrays.asList(single.toAbsolutePath(), multiple.toAbsolutePath()));
|
||||
HashMap<String, List<String>> foundSnippets = new SnippetReplacer().getAllSnippets(srcs);
|
||||
} catch (Exception e){
|
||||
// check for snippet id in string
|
||||
assertTrue(e.toString().contains("com.azure.data.applicationconfig.configurationclient.instantiation"));
|
||||
// should be one duplicate message from each file
|
||||
assertTrue((e.toString().split("Duplicate snippetId", -1).length - 1) == 2);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notFoundSnippetCrashes() throws IOException{
|
||||
HashMap<String, List<String>> emptyMap = new HashMap<String, List<String>>();
|
||||
|
||||
Path codeForReplacement = _getPathToResource("../../project-to-test/basic_src_snippet_insertion_before.txt");
|
||||
List<String> testLines = Files.readAllLines(codeForReplacement, StandardCharsets.UTF_8);
|
||||
SnippetReplacer testReplacer = new SnippetReplacer();
|
||||
|
||||
SnippetOperationResult<StringBuilder> opResult = testReplacer.updateSnippets(codeForReplacement, testLines,
|
||||
testReplacer.SNIPPET_SRC_CALL_BEGIN, testReplacer.SNIPPET_SRC_CALL_END, emptyMap, "<pre>",
|
||||
"</pre>", 1, "* ", false);
|
||||
|
||||
assertTrue(opResult.errorList.size() == 3);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
##### Create a Configuration Client
|
||||
|
||||
Once you have the value of the connection string you can create the configuration client:
|
||||
|
||||
```Java com.azure.data.applicationconfig.configurationclient.instantiation
|
||||
ConfigurationClient configurationClient = new ConfigurationClientBuilder()
|
||||
.connectionString(connectionString)
|
||||
.buildClient();
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
``` Java com.azure.core.http.rest.pagedflux.instantiation
|
||||
// A supplier that fetches the first page of data from source/service
|
||||
Supplier<Mono<PagedResponse<Integer>>> firstPageRetriever = () -> getFirstPage();
|
||||
|
||||
// A function that fetches subsequent pages of data from source/service given a continuation token
|
||||
Function<String, Mono<PagedResponse<Integer>>> nextPageRetriever =
|
||||
continuationToken -> getNextPage(continuationToken);
|
||||
|
||||
PagedFlux<Integer> pagedFlux = new PagedFlux<>(firstPageRetriever,
|
||||
nextPageRetriever);
|
||||
```
|
|
@ -0,0 +1,15 @@
|
|||
##### Create a Configuration Client
|
||||
|
||||
Once you have the value of the connection string you can create the configuration client:
|
||||
|
||||
```Java com.azure.data.applicationconfig.configurationclient.instantiation
|
||||
ConfigurationClient configurationClient = new ConfigurationClientBuilder()
|
||||
.connectionString(connectionString)
|
||||
.buildClient();
|
||||
Some other crap
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
``` Java com.azure.core.http.rest.pagedflux.instantiation
|
||||
```
|
|
@ -0,0 +1,86 @@
|
|||
import java.time.OffsetDateTime;
|
||||
|
||||
/**
|
||||
* This class provides a client that contains all the operations for {@link ConfigurationSetting ConfigurationSettings}
|
||||
* in Azure App Configuration Store. Operations allowed by the client are adding, retrieving, deleting, set read-only
|
||||
* status ConfigurationSettings, and listing settings or revision of a setting based on a
|
||||
* {@link SettingSelector filter}.
|
||||
*
|
||||
* <p><strong>Instantiating a synchronous Configuration Client</strong></p>
|
||||
*
|
||||
* <!-- src_embed com.azure.data.applicationconfig.configurationclient.instantiation -->
|
||||
* <pre>
|
||||
* ConfigurationClient configurationClient = new ConfigurationClientBuilder()
|
||||
* .connectionString(connectionString)
|
||||
* .buildClient();
|
||||
* </pre>
|
||||
* <!-- end com.azure.data.applicationconfig.configurationclient.instantiation -->
|
||||
*
|
||||
* <p>View {@link ConfigurationClientBuilder this} for additional ways to construct the client.</p>
|
||||
*
|
||||
* @see ConfigurationClientBuilder
|
||||
*/
|
||||
@ServiceClient(builder = ConfigurationClientBuilder.class, serviceInterfaces = ConfigurationService.class)
|
||||
public final class ConfigurationClient {
|
||||
private final ConfigurationAsyncClient client;
|
||||
|
||||
/**
|
||||
* Creates a ConfigurationClient that sends requests to the configuration service at {@code serviceEndpoint}. Each
|
||||
* service call goes through the {@code pipeline}.
|
||||
*
|
||||
* @param client The {@link ConfigurationAsyncClient} that the client routes its request through.
|
||||
*/
|
||||
ConfigurationClient(ConfigurationAsyncClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a configuration value in the service if that key does not exist. The {@code label} is optional.
|
||||
*
|
||||
* <p><strong>Code Samples</strong></p>
|
||||
*
|
||||
* <p>Add a setting with the key "prodDBConnection", label "westUS" and value "db_connection".</p>
|
||||
*
|
||||
* <!-- src_embed com.azure.data.appconfiguration.ConfigurationClient.addConfigurationSetting#String-String-String -->
|
||||
* <pre>
|
||||
* ConfigurationSetting result = configurationClient
|
||||
* .addConfigurationSetting("prodDBConnection", "westUS", "db_connection");
|
||||
* System.out.printf("Key: %s, Label: %s, Value: %s", result.getKey(), result.getLabel(), result.getValue());
|
||||
* </pre>
|
||||
* <!-- end com.azure.data.appconfiguration.ConfigurationClient.addConfigurationSetting#String-String-String -->
|
||||
*
|
||||
* @param key The key of the configuration setting to add.
|
||||
* @param label The label of the configuration setting to create. If {@code null} no label will be used.
|
||||
* @param value The value associated with this configuration setting key.
|
||||
* @return The {@link ConfigurationSetting} that was created, or {@code null} if a key collision occurs or the key
|
||||
* is an invalid value (which will also throw ServiceRequestException described below).
|
||||
* @throws IllegalArgumentException If {@code key} is {@code null}.
|
||||
* @throws ResourceModifiedException If a ConfigurationSetting with the same key exists.
|
||||
* @throws HttpResponseException If {@code key} is an empty string.
|
||||
*/
|
||||
@ServiceMethod(returns = ReturnType.SINGLE)
|
||||
public ConfigurationSetting addConfigurationSetting(String key, String label, String value) {
|
||||
return addConfigurationSettingWithResponse(
|
||||
new ConfigurationSetting().setKey(key).setLabel(label).setValue(value), Context.NONE).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* <!-- src_embed com.azure.core.http.rest.pagedflux.instantiation -->
|
||||
* <pre>
|
||||
* // A supplier that fetches the first page of data from source/service
|
||||
* Supplier<Mono<PagedResponse<Integer>>> firstPageRetriever = () -> getFirstPage();
|
||||
*
|
||||
* // A function that fetches subsequent pages of data from source/service given a continuation token
|
||||
* Function<String, Mono<PagedResponse<Integer>>> nextPageRetriever =
|
||||
* continuationToken -> getNextPage(continuationToken);
|
||||
*
|
||||
* PagedFlux<Integer> pagedFlux = new PagedFlux<>(firstPageRetriever,
|
||||
* nextPageRetriever);
|
||||
* </pre>
|
||||
* <!-- end com.azure.core.http.rest.pagedflux.instantiation -->
|
||||
*/
|
||||
public ConfigurationSetting addConfigurationSetting(String key, String label, String value) {
|
||||
return addConfigurationSettingWithResponse(
|
||||
new ConfigurationSetting().setKey(key).setLabel(label).setValue(value), Context.NONE).getValue();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
import java.time.OffsetDateTime;
|
||||
|
||||
/**
|
||||
* This class provides a client that contains all the operations for {@link ConfigurationSetting ConfigurationSettings}
|
||||
* in Azure App Configuration Store. Operations allowed by the client are adding, retrieving, deleting, set read-only
|
||||
* status ConfigurationSettings, and listing settings or revision of a setting based on a
|
||||
* {@link SettingSelector filter}.
|
||||
*
|
||||
* <p><strong>Instantiating a synchronous Configuration Client</strong></p>
|
||||
*
|
||||
* <!-- src_embed com.azure.data.applicationconfig.configurationclient.instantiation -->
|
||||
* Existing content waiting for cleanup.
|
||||
* <!-- end com.azure.data.applicationconfig.configurationclient.instantiation -->
|
||||
*
|
||||
* <p>View {@link ConfigurationClientBuilder this} for additional ways to construct the client.</p>
|
||||
*
|
||||
* @see ConfigurationClientBuilder
|
||||
*/
|
||||
@ServiceClient(builder = ConfigurationClientBuilder.class, serviceInterfaces = ConfigurationService.class)
|
||||
public final class ConfigurationClient {
|
||||
private final ConfigurationAsyncClient client;
|
||||
|
||||
/**
|
||||
* Creates a ConfigurationClient that sends requests to the configuration service at {@code serviceEndpoint}. Each
|
||||
* service call goes through the {@code pipeline}.
|
||||
*
|
||||
* @param client The {@link ConfigurationAsyncClient} that the client routes its request through.
|
||||
*/
|
||||
ConfigurationClient(ConfigurationAsyncClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a configuration value in the service if that key does not exist. The {@code label} is optional.
|
||||
*
|
||||
* <p><strong>Code Samples</strong></p>
|
||||
*
|
||||
* <p>Add a setting with the key "prodDBConnection", label "westUS" and value "db_connection".</p>
|
||||
*
|
||||
* <!-- src_embed com.azure.data.appconfiguration.ConfigurationClient.addConfigurationSetting#String-String-String -->
|
||||
* <!-- end com.azure.data.appconfiguration.ConfigurationClient.addConfigurationSetting#String-String-String -->
|
||||
*
|
||||
* @param key The key of the configuration setting to add.
|
||||
* @param label The label of the configuration setting to create. If {@code null} no label will be used.
|
||||
* @param value The value associated with this configuration setting key.
|
||||
* @return The {@link ConfigurationSetting} that was created, or {@code null} if a key collision occurs or the key
|
||||
* is an invalid value (which will also throw ServiceRequestException described below).
|
||||
* @throws IllegalArgumentException If {@code key} is {@code null}.
|
||||
* @throws ResourceModifiedException If a ConfigurationSetting with the same key exists.
|
||||
* @throws HttpResponseException If {@code key} is an empty string.
|
||||
*/
|
||||
@ServiceMethod(returns = ReturnType.SINGLE)
|
||||
public ConfigurationSetting addConfigurationSetting(String key, String label, String value) {
|
||||
return addConfigurationSettingWithResponse(
|
||||
new ConfigurationSetting().setKey(key).setLabel(label).setValue(value), Context.NONE).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* <!-- src_embed com.azure.core.http.rest.pagedflux.instantiation -->
|
||||
* <!-- end com.azure.core.http.rest.pagedflux.instantiation -->
|
||||
*/
|
||||
public ConfigurationSetting addConfigurationSetting(String key, String label, String value) {
|
||||
return addConfigurationSettingWithResponse(
|
||||
new ConfigurationSetting().setKey(key).setLabel(label).setValue(value), Context.NONE).getValue();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
|
||||
/**
|
||||
* This class contains code samples for generating javadocs through doclets for {@link ConfigurationClient}
|
||||
*/
|
||||
public final class ConfigurationClientJavaDocCodeSnippets {
|
||||
|
||||
private String key1 = "key1";
|
||||
private String key2 = "key2";
|
||||
private String value1 = "val1";
|
||||
private String value2 = "val2";
|
||||
|
||||
/**
|
||||
* Generates code sample for creating a {@link ConfigurationClient}
|
||||
*
|
||||
* @return An instance of {@link ConfigurationClient}
|
||||
* @throws IllegalStateException If configuration credentials cannot be created.
|
||||
*/
|
||||
public ConfigurationClient createAsyncConfigurationClientWithPipeline() {
|
||||
|
||||
/**
|
||||
* Generates code sample for creating a {@link ConfigurationClient}
|
||||
*
|
||||
* @return An instance of {@link ConfigurationClient}
|
||||
* @throws IllegalStateException If configuration credentials cannot be created
|
||||
*/
|
||||
public ConfigurationClient createSyncConfigurationClient() {
|
||||
String connectionString = getConnectionString();
|
||||
// BEGIN: com.azure.data.applicationconfig.configurationclient.instantiation
|
||||
ConfigurationClient configurationClient = new ConfigurationClientBuilder()
|
||||
.connectionString(connectionString)
|
||||
.buildClient();
|
||||
// END: com.azure.data.applicationconfig.configurationclient.instantiation
|
||||
return configurationClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates code sample for using {@link ConfigurationClient#addConfigurationSetting(String, String, String)}
|
||||
*/
|
||||
public void addConfigurationSetting() {
|
||||
ConfigurationClient configurationClient = createSyncConfigurationClient();
|
||||
// BEGIN: com.azure.data.appconfiguration.ConfigurationClient.addConfigurationSetting#String-String-String
|
||||
ConfigurationSetting result = configurationClient
|
||||
.addConfigurationSetting("prodDBConnection", "westUS", "db_connection");
|
||||
System.out.printf("Key: %s, Label: %s, Value: %s", result.getKey(), result.getLabel(), result.getValue());
|
||||
// END: com.azure.data.appconfiguration.ConfigurationClient.addConfigurationSetting#String-String-String
|
||||
}
|
||||
|
||||
public void encodedHtmlWorks(){
|
||||
// BEGIN: com.azure.core.http.rest.pagedflux.instantiation
|
||||
// A supplier that fetches the first page of data from source/service
|
||||
Supplier<Mono<PagedResponse<Integer>>> firstPageRetriever = () -> getFirstPage();
|
||||
|
||||
// A function that fetches subsequent pages of data from source/service given a continuation token
|
||||
Function<String, Mono<PagedResponse<Integer>>> nextPageRetriever =
|
||||
continuationToken -> getNextPage(continuationToken);
|
||||
|
||||
PagedFlux<Integer> pagedFlux = new PagedFlux<>(firstPageRetriever,
|
||||
nextPageRetriever);
|
||||
// END: com.azure.core.http.rest.pagedflux.instantiation
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
public ConfigurationClient createSyncConfigurationClient() {
|
||||
String connectionString = getConnectionString();
|
||||
// BEGIN: com.azure.data.applicationconfig.configurationclient.instantiation
|
||||
ConfigurationClient configurationClient = new ConfigurationClientBuilder()
|
||||
.connectionString(connectionString)
|
||||
.buildClient();
|
||||
// END: com.azure.data.applicationconfig.configurationclient.instantiation
|
||||
return configurationClient;
|
||||
}
|
||||
|
||||
public ConfigurationClient createSyncConfigurationClient() {
|
||||
String connectionString = getConnectionString();
|
||||
// BEGIN: com.azure.data.applicationconfig.configurationclient.instantiation
|
||||
ConfigurationClient configurationClient = new ConfigurationClientBuilder()
|
||||
.connectionString(connectionString)
|
||||
.buildClient();
|
||||
// END: com.azure.data.applicationconfig.configurationclient.instantiation
|
||||
return configurationClient;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
public ConfigurationClient createSyncConfigurationClient() {
|
||||
String connectionString = getConnectionString();
|
||||
// BEGIN: com.azure.data.applicationconfig.configurationclient.instantiation
|
||||
ConfigurationClient configurationClient = new ConfigurationClientBuilder()
|
||||
.connectionString(connectionString)
|
||||
.buildClient();
|
||||
// END: com.azure.data.applicationconfig.configurationclient.instantiation
|
||||
return configurationClient;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
public ConfigurationClient createSyncConfigurationClient() {
|
||||
String connectionString = getConnectionString();
|
||||
// BEGIN: com.azure.data.applicationconfig.configurationclient.testEmpty
|
||||
// END: com.azure.data.applicationconfig.configurationclient.testEmpty
|
||||
return configurationClient;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?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>azuresdk.plugin</groupId>
|
||||
<artifactId>snippet-replacer-maven-plugin</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>Test MyMojo</name>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-my-plugin</artifactId>
|
||||
<configuration>
|
||||
<!-- Specify the MyMojo parameter -->
|
||||
<outputDirectory>target/test-harness/project-to-test</outputDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,20 @@
|
|||
##### Create a Configuration Client
|
||||
|
||||
Once you have the value of the connection string you can create the configuration client:
|
||||
|
||||
```Java com.azure.data.applicationconfig.configurationclient.instantiation
|
||||
ConfigurationClient configurationClient = new ConfigurationClientBuilder()
|
||||
.connectionString(connectionString)
|
||||
.buildClient();
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
``` Java com.azure.core.http.rest.pagedflux.instantiation
|
||||
Supplier<Mono<PagedResponse<Integer>>> firstPageRetriever = () -> getFirstPage();
|
||||
|
||||
// A function that fetches subsequent pages of data from source/service given a continuation token
|
||||
Function<String, Mono<PagedResponse<Integer>>> nextPageRetriever =
|
||||
continuationToken -> getNextPage(continuationToken);
|
||||
|
||||
```
|
|
@ -0,0 +1,84 @@
|
|||
import java.time.OffsetDateTime;
|
||||
|
||||
/**
|
||||
* This class provides a client that contains all the operations for {@link ConfigurationSetting ConfigurationSettings}
|
||||
* in Azure App Configuration Store. Operations allowed by the client are adding, retrieving, deleting, set read-only
|
||||
* status ConfigurationSettings, and listing settings or revision of a setting based on a
|
||||
* {@link SettingSelector filter}.
|
||||
*
|
||||
* <p><strong>Instantiating a synchronous Configuration Client</strong></p>
|
||||
*
|
||||
* <!-- src_embed com.azure.data.applicationconfig.configurationclient.instantiation -->
|
||||
* <pre>
|
||||
* ConfigurationClient configurationClient = new ConfigurationClientBuilder()
|
||||
* .connectionString(connectionString)
|
||||
* .buildClient()
|
||||
* </pre>
|
||||
* <!-- end com.azure.data.applicationconfig.configurationclient.instantiation -->
|
||||
*
|
||||
* <p>View {@link ConfigurationClientBuilder this} for additional ways to construct the client.</p>
|
||||
*
|
||||
* @see ConfigurationClientBuilder
|
||||
*/
|
||||
@ServiceClient(builder = ConfigurationClientBuilder.class, serviceInterfaces = ConfigurationService.class)
|
||||
public final class ConfigurationClient {
|
||||
private final ConfigurationAsyncClient client;
|
||||
|
||||
/**
|
||||
* Creates a ConfigurationClient that sends requests to the configuration service at {@code serviceEndpoint}. Each
|
||||
* service call goes through the {@code pipeline}.
|
||||
*
|
||||
* @param client The {@link ConfigurationAsyncClient} that the client routes its request through.
|
||||
*/
|
||||
ConfigurationClient(ConfigurationAsyncClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a configuration value in the service if that key does not exist. The {@code label} is optional.
|
||||
*
|
||||
* <p><strong>Code Samples</strong></p>
|
||||
*
|
||||
* <p>Add a setting with the key "prodDBConnection", label "westUS" and value "db_connection".</p>
|
||||
*
|
||||
* <!-- src_embed com.azure.data.appconfiguration.ConfigurationClient.addConfigurationSetting#String-String-String -->
|
||||
* <pre>
|
||||
* ConfigurationSetting result = configurationClient
|
||||
* .addConfigurationSetting("prodDBConnection", "westUS", "db_connection");
|
||||
* System.out.printf("Key: %s, Label: %s, Value: %s", result.getKey(), result.getLabel(), result.getValue());
|
||||
* </pre>
|
||||
* <!-- end com.azure.data.appconfiguration.ConfigurationClient.addConfigurationSetting#String-String-String -->
|
||||
*
|
||||
* @param key The key of the configuration setting to add.
|
||||
* @param label The label of the configuration setting to create. If {@code null} no label will be used.
|
||||
* @param value The value associated with this configuration setting key.
|
||||
* @return The {@link ConfigurationSetting} that was created, or {@code null} if a key collision occurs or the key
|
||||
* is an invalid value (which will also throw ServiceRequestException described below).
|
||||
* @throws IllegalArgumentException If {@code key} is {@code null}.
|
||||
* @throws ResourceModifiedException If a ConfigurationSetting with the same key exists.
|
||||
* @throws HttpResponseException If {@code key} is an empty string.
|
||||
*/
|
||||
@ServiceMethod(returns = ReturnType.SINGLE)
|
||||
public ConfigurationSetting addConfigurationSetting(String key, String label, String value) {
|
||||
return addConfigurationSettingWithResponse(
|
||||
new ConfigurationSetting().setKey(key).setLabel(label).setValue(value), Context.NONE).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* <!-- src_embed com.azure.core.http.rest.pagedflux.instantiation -->
|
||||
* <pre>
|
||||
* // A supplier that fetches the first page of data from source/service
|
||||
* Supplier<Mono<PagedResponse<Integer>>> firstPageRetriever = () -> getFirstPage();
|
||||
*
|
||||
* // A function that fetches subsequent pages of data from source/service given a continuation token
|
||||
* Function<String, Mono<PagedResponse<Integer>>> nextPageRetriever =
|
||||
* continuationToken -> getNextPage(continuationToken);
|
||||
*
|
||||
* </pre>
|
||||
* <!-- end com.azure.core.http.rest.pagedflux.instantiation -->
|
||||
*/
|
||||
public ConfigurationSetting addConfigurationSetting(String key, String label, String value) {
|
||||
return addConfigurationSettingWithResponse(
|
||||
new ConfigurationSetting().setKey(key).setLabel(label).setValue(value), Context.NONE).getValue();
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче