diff --git a/allure-java-commons/src/main/java/io/qameta/allure/Link.java b/allure-java-commons/src/main/java/io/qameta/allure/Link.java
index 2a7f15a02..666da86a4 100644
--- a/allure-java-commons/src/main/java/io/qameta/allure/Link.java
+++ b/allure-java-commons/src/main/java/io/qameta/allure/Link.java
@@ -15,6 +15,8 @@
*/
package io.qameta.allure;
+import io.qameta.allure.util.ResultsUtils;
+
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
@@ -66,5 +68,5 @@
*
* @return the link type.
*/
- String type() default "custom";
+ String type() default ResultsUtils.CUSTOM_LINK_TYPE;
}
diff --git a/allure-java-commons/src/main/java/io/qameta/allure/LinkAnnotation.java b/allure-java-commons/src/main/java/io/qameta/allure/LinkAnnotation.java
new file mode 100644
index 000000000..6b5ee1220
--- /dev/null
+++ b/allure-java-commons/src/main/java/io/qameta/allure/LinkAnnotation.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2019 Qameta Software OÜ
+ *
+ * Licensed 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 io.qameta.allure;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import static io.qameta.allure.util.ResultsUtils.CUSTOM_LINK_TYPE;
+
+/**
+ * Marker annotation. Annotations marked by this annotation will be discovered
+ * by Allure and added to test results as a link.
+ *
+ * @see Link
+ * @see TmsLink
+ * @see Issue
+ */
+@Documented
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.ANNOTATION_TYPE})
+public @interface LinkAnnotation {
+
+ /**
+ * The value of link. In not specified will take value from value()
+ * method of target annotation.
+ *
+ * @return the value of the link to add.
+ */
+ String value() default "";
+
+ /**
+ * This type is used for create an icon for link. Also there is few reserved types such as issue and tms.
+ *
+ * @return the link type.
+ */
+ String type() default CUSTOM_LINK_TYPE;
+}
diff --git a/allure-java-commons/src/main/java/io/qameta/allure/util/AnnotationUtils.java b/allure-java-commons/src/main/java/io/qameta/allure/util/AnnotationUtils.java
index 7f2d388c7..c547d44ca 100644
--- a/allure-java-commons/src/main/java/io/qameta/allure/util/AnnotationUtils.java
+++ b/allure-java-commons/src/main/java/io/qameta/allure/util/AnnotationUtils.java
@@ -16,6 +16,7 @@
package io.qameta.allure.util;
import io.qameta.allure.LabelAnnotation;
+import io.qameta.allure.LinkAnnotation;
import io.qameta.allure.model.Label;
import io.qameta.allure.model.Link;
import org.slf4j.Logger;
@@ -26,17 +27,18 @@
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.ArrayList;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import static java.util.Arrays.asList;
+
/**
* Collection of utils used by Allure integration to extract meta information from
* test cases via reflection.
@@ -64,6 +66,7 @@ public static List getLinks(final AnnotatedElement annotatedElement) {
result.addAll(extractLinks(annotatedElement, io.qameta.allure.Link.class, ResultsUtils::createLink));
result.addAll(extractLinks(annotatedElement, io.qameta.allure.Issue.class, ResultsUtils::createLink));
result.addAll(extractLinks(annotatedElement, io.qameta.allure.TmsLink.class, ResultsUtils::createLink));
+ result.addAll(extractCustomLinks(asList(annotatedElement.getDeclaredAnnotations())));
return result;
}
@@ -74,7 +77,7 @@ public static List getLinks(final AnnotatedElement annotatedElement) {
* @return discovered links.
*/
public static List getLinks(final Annotation... annotations) {
- return getLinks(Arrays.asList(annotations));
+ return getLinks(asList(annotations));
}
/**
@@ -88,6 +91,7 @@ public static List getLinks(final Collection annotations) {
result.addAll(extractLinks(annotations, io.qameta.allure.Link.class, ResultsUtils::createLink));
result.addAll(extractLinks(annotations, io.qameta.allure.Issue.class, ResultsUtils::createLink));
result.addAll(extractLinks(annotations, io.qameta.allure.TmsLink.class, ResultsUtils::createLink));
+ result.addAll(extractCustomLinks(annotations));
return result;
}
@@ -109,7 +113,7 @@ public static Set