diff --git a/server-core/src/main/java/io/onedev/server/CoreModule.java b/server-core/src/main/java/io/onedev/server/CoreModule.java index ce79fd6bd1..f10775e743 100644 --- a/server-core/src/main/java/io/onedev/server/CoreModule.java +++ b/server-core/src/main/java/io/onedev/server/CoreModule.java @@ -71,9 +71,9 @@ import io.onedev.commons.utils.ExceptionUtils; import io.onedev.commons.utils.StringUtils; import io.onedev.k8shelper.KubernetesHelper; import io.onedev.k8shelper.OsInfo; -import io.onedev.server.ai.McpHelperResource; import io.onedev.server.attachment.AttachmentManager; import io.onedev.server.attachment.DefaultAttachmentManager; +import io.onedev.server.buildspec.BuildSpecSchemaResource; import io.onedev.server.buildspec.job.log.instruction.LogInstruction; import io.onedev.server.cluster.ClusterResource; import io.onedev.server.codequality.CodeProblemContribution; @@ -331,6 +331,7 @@ import io.onedev.server.rest.DefaultServletContainer; import io.onedev.server.rest.JerseyConfigurator; import io.onedev.server.rest.ResourceConfigProvider; import io.onedev.server.rest.WebApplicationExceptionHandler; +import io.onedev.server.rest.resource.McpHelperResource; import io.onedev.server.rest.resource.ProjectResource; import io.onedev.server.search.code.CodeIndexManager; import io.onedev.server.search.code.CodeSearchManager; @@ -655,6 +656,7 @@ public class CoreModule extends AbstractPluginModule { contribute(JerseyConfigurator.class, resourceConfig -> resourceConfig.packages(ProjectResource.class.getPackage().getName())); contribute(JerseyConfigurator.class, resourceConfig -> resourceConfig.register(ClusterResource.class)); contribute(JerseyConfigurator.class, resourceConfig -> resourceConfig.register(McpHelperResource.class)); + contribute(JerseyConfigurator.class, resourceConfig -> resourceConfig.register(BuildSpecSchemaResource.class)); } private void configureWeb() { diff --git a/server-core/src/main/java/io/onedev/server/annotation/DependsOn.java b/server-core/src/main/java/io/onedev/server/annotation/DependsOn.java new file mode 100644 index 0000000000..1ae7678a2b --- /dev/null +++ b/server-core/src/main/java/io/onedev/server/annotation/DependsOn.java @@ -0,0 +1,17 @@ +package io.onedev.server.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD}) +public @interface DependsOn { + + String property(); + + String value() default ""; + + boolean inverse() default false; +} diff --git a/server-core/src/main/java/io/onedev/server/buildspec/BuildSpec.java b/server-core/src/main/java/io/onedev/server/buildspec/BuildSpec.java index 5777885217..d5098d492a 100644 --- a/server-core/src/main/java/io/onedev/server/buildspec/BuildSpec.java +++ b/server-core/src/main/java/io/onedev/server/buildspec/BuildSpec.java @@ -284,7 +284,7 @@ public class BuildSpec implements Serializable, Validatable { for (ConstraintViolation violation: getValidator().validate(job)) { context.buildConstraintViolationWithTemplate(violation.getMessage()) .addPropertyNode(PROP_JOBS) - .addBeanNode() + .addPropertyNode(violation.getPropertyPath().toString()) .inIterable().atIndex(index) .addConstraintViolation(); isValid = false; @@ -306,7 +306,7 @@ public class BuildSpec implements Serializable, Validatable { for (ConstraintViolation violation: getValidator().validate(service)) { context.buildConstraintViolationWithTemplate(violation.getMessage()) .addPropertyNode(PROP_SERVICES) - .addBeanNode() + .addPropertyNode(violation.getPropertyPath().toString()) .inIterable().atIndex(index) .addConstraintViolation(); isValid = false; @@ -328,7 +328,7 @@ public class BuildSpec implements Serializable, Validatable { for (ConstraintViolation violation: getValidator().validate(stepTemplate)) { context.buildConstraintViolationWithTemplate(violation.getMessage()) .addPropertyNode(PROP_STEP_TEMPLATES) - .addBeanNode() + .addPropertyNode(violation.getPropertyPath().toString()) .inIterable().atIndex(index) .addConstraintViolation(); isValid = false; @@ -350,7 +350,7 @@ public class BuildSpec implements Serializable, Validatable { for (ConstraintViolation violation: getValidator().validate(property)) { context.buildConstraintViolationWithTemplate(violation.getMessage()) .addPropertyNode(PROP_PROPERTIES) - .addBeanNode() + .addPropertyNode(violation.getPropertyPath().toString()) .inIterable().atIndex(index) .addConstraintViolation(); isValid = false; @@ -373,7 +373,7 @@ public class BuildSpec implements Serializable, Validatable { for (ConstraintViolation violation: validator.validate(aImport)) { context.buildConstraintViolationWithTemplate(violation.getMessage()) .addPropertyNode(PROP_IMPORTS) - .addBeanNode() + .addPropertyNode(violation.getPropertyPath().toString()) .inIterable().atIndex(index) .addConstraintViolation(); isValid = false; @@ -2312,4 +2312,27 @@ public class BuildSpec implements Serializable, Validatable { }); } + @SuppressWarnings("unused") + private void migrate41(VersionedYamlDoc doc, Stack versions) { + for (NodeTuple specTuple: doc.getValue()) { + String specKey = ((ScalarNode)specTuple.getKeyNode()).getValue(); + if (specKey.equals("jobs")) { + SequenceNode jobsNode = (SequenceNode) specTuple.getValueNode(); + for (Node jobsNodeItem: jobsNode.getValue()) { + MappingNode jobNode = (MappingNode) jobsNodeItem; + for (var itJobTuple = jobNode.getValue().iterator(); itJobTuple.hasNext();) { + var jobTuple = itJobTuple.next(); + var keyNode = (ScalarNode) jobTuple.getKeyNode(); + if (keyNode.getValue().equals("retryCondition")) { + var valueNode = (ScalarNode) jobTuple.getValueNode(); + if (valueNode.getValue().equals("never")) { + itJobTuple.remove(); + } + } + } + } + } + } + } + } diff --git a/server-core/src/main/java/io/onedev/server/buildspec/BuildSpecSchemaResource.java b/server-core/src/main/java/io/onedev/server/buildspec/BuildSpecSchemaResource.java new file mode 100644 index 0000000000..e38023ec88 --- /dev/null +++ b/server-core/src/main/java/io/onedev/server/buildspec/BuildSpecSchemaResource.java @@ -0,0 +1,339 @@ +package io.onedev.server.buildspec; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; + +import io.onedev.commons.loader.ImplementationRegistry; +import io.onedev.commons.utils.ClassUtils; +import io.onedev.commons.utils.ExplicitException; +import io.onedev.server.annotation.DependsOn; +import io.onedev.server.annotation.Editable; +import io.onedev.server.annotation.ImplementationProvider; +import io.onedev.server.buildspec.job.Job; +import io.onedev.server.data.migration.MigrationHelper; +import io.onedev.server.model.support.build.JobProperty; +import io.onedev.server.rest.annotation.Api; +import io.onedev.server.util.Pair; +import io.onedev.server.util.ReflectionUtils; +import io.onedev.server.web.editable.BeanDescriptor; +import io.onedev.server.web.editable.EditableUtils; +import io.onedev.server.web.editable.PropertyDescriptor; + +@Api(internal = true) +@Path("/build-spec-schema.yml") +@Consumes(MediaType.APPLICATION_JSON) +@Produces("application/x-yaml") +@Singleton +public class BuildSpecSchemaResource { + + private final ImplementationRegistry implementationRegistry; + + private final Yaml yaml; + + private String schema; + + @Inject + public BuildSpecSchemaResource(ImplementationRegistry implementationRegistry) { + this.implementationRegistry = implementationRegistry; + + // Configure YAML output + DumperOptions options = new DumperOptions(); + options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + options.setPrettyFlow(true); + this.yaml = new Yaml(options); + } + + private void processProperty(Map currentNode, PropertyDescriptor property) { + var description = property.getDescription(); + if (description != null) + currentNode.put("description", description); + var returnType = property.getPropertyClass(); + + if (Collection.class.isAssignableFrom(returnType)) { + var elementClass = ReflectionUtils.getCollectionElementClass(property.getPropertyGetter().getGenericReturnType()); + if (elementClass == null) + throw new ExplicitException("Unknown collection element class (bean: " + property.getBeanClass() + ", property: " + property.getPropertyName() + ")"); + processCollectionProperty(currentNode, elementClass); + } else { + processType(currentNode, returnType); + } + } + + @SuppressWarnings("unchecked") + private void processBean(Map currentNode, Class beanClass, + Map processedProperties) { + var propsNode = (Map) currentNode.get("properties"); + if (propsNode == null) { + propsNode = new HashMap<>(); + currentNode.put("properties", propsNode); + } + var requiredNode = (List) currentNode.get("required"); + if (requiredNode == null) { + requiredNode = new ArrayList<>(); + currentNode.put("required", requiredNode); + } + + var dependents = new ArrayList>(); + for (var groupProperties: new BeanDescriptor(beanClass).getProperties().values()) { + for (var property: groupProperties) { + if (processedProperties.putIfAbsent(property.getPropertyName(), property) == null) { + if (property.getPropertyName().equals("type")) + throw new ExplicitException("Property 'type' is reserved (class: " + beanClass.getName() + ")"); + var dependsOn = property.getPropertyGetter().getAnnotation(DependsOn.class); + if (dependsOn != null) { + dependents.add(new Pair<>(property, dependsOn)); + } else { + if (property.isPropertyRequired()) + requiredNode.add(property.getPropertyName()); + var propNode = new HashMap(); + propsNode.put(property.getPropertyName(), propNode); + processProperty(propNode, property); + } + } + } + } + if (!dependents.isEmpty()) { + var allOfNode = new ArrayList>(); + currentNode.put("allOf", allOfNode); + for (var dependent: dependents) { + var allOfItemNode = new HashMap(); + allOfNode.add(allOfItemNode); + var dependsOn = dependent.getRight(); + var dependencyProperty = processedProperties.get(dependsOn.property()); + if (dependencyProperty == null) + throw new ExplicitException("Dependency property not found: " + dependsOn.property()); + + var ifNode = new HashMap(); + allOfItemNode.put("if", ifNode); + var ifPropsNode = new HashMap(); + ifNode.put("properties", ifPropsNode); + var dependencyPropertyNode = new HashMap(); + ifPropsNode.put(dependencyProperty.getPropertyName(), dependencyPropertyNode); + + var inverse = dependsOn.inverse(); + var dependencyPropertyClass = dependencyProperty.getPropertyClass(); + if (dependencyPropertyClass == boolean.class) { + if (dependsOn.value().length() != 0) { + dependencyPropertyNode.put("const", Boolean.parseBoolean(dependsOn.value())); + } else { + dependencyPropertyNode.put("const", true); + } + } else if (dependencyPropertyClass == int.class || dependencyPropertyClass == long.class + || dependencyPropertyClass == double.class || dependencyPropertyClass == float.class) { + if (dependsOn.value().length() != 0) { + dependencyPropertyNode.put("const", Integer.parseInt(dependsOn.value())); + } else { + dependencyPropertyNode.put("const", 0); + inverse = !inverse; + } + } else { + if (dependsOn.value().length() != 0) { + if (dependencyPropertyClass == Boolean.class) + dependencyPropertyNode.put("const", Boolean.parseBoolean(dependsOn.value())); + else if (dependencyPropertyClass == Integer.class || dependencyPropertyClass == Long.class || dependencyPropertyClass == Double.class || dependencyPropertyClass == Float.class) + dependencyPropertyNode.put("const", Integer.parseInt(dependsOn.value())); + else + dependencyPropertyNode.put("const", dependsOn.value()); + } else { + var typeList = new ArrayList(); + typeList.add("object"); + typeList.add("string"); + typeList.add("integer"); + typeList.add("number"); + typeList.add("boolean"); + dependencyPropertyNode.put("type", typeList); + } + } + + Map branchNode; + if (!inverse) { + branchNode = new HashMap<>(); + allOfItemNode.put("then", branchNode); + } else { + branchNode = new HashMap<>(); + allOfItemNode.put("else", branchNode); + } + + var property = dependent.getLeft(); + var branchPropsNode = new HashMap(); + branchNode.put("properties", branchPropsNode); + var propNode = new HashMap(); + branchPropsNode.put(property.getPropertyName(), propNode); + processProperty(propNode, property); + if (property.isPropertyRequired()) { + var requiredList = new ArrayList(); + requiredList.add(property.getPropertyName()); + branchNode.put("required", requiredList); + } + } + } + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private void processType(Map currentNode, Class type) { + if (type == String.class) { + currentNode.put("type", "string"); + } else if (type == Boolean.class || type == boolean.class) { + currentNode.put("type", "boolean"); + } else if (type == Integer.class || type == int.class || type == Long.class || type == long.class) { + currentNode.put("type", "integer"); + } else if (type == Float.class || type == float.class || type == Double.class || type == double.class) { + currentNode.put("type", "number"); + } else if (Enum.class.isAssignableFrom(type)) { + currentNode.put("type", "string"); + var enumList = new ArrayList(); + var enumClass = (Class) type; + for (var enumValue: EnumSet.allOf(enumClass)) { + enumList.add(((Enum) enumValue).name()); + } + currentNode.put("enum", enumList); + } else if (type == Date.class) { + currentNode.put("type", "string"); + currentNode.put("format", "date-time"); + } else if (type.getAnnotation(Editable.class) != null) { + if (ClassUtils.isConcrete(type)) { + currentNode.put("type", "object"); + processBean(currentNode, type, new HashMap<>()); + currentNode.put("additionalProperties", false); + } else { + processPolymorphic(currentNode, type); + } + } else { + throw new ExplicitException("Unsupported type: " + type); + } + } + + @SuppressWarnings("unchecked") + private void processPolymorphic(Map currentNode, Class baseClass) { + Collection> implementations = new ArrayList<>(); + var implementationProvider = baseClass.getAnnotation(ImplementationProvider.class); + if (implementationProvider != null) + implementations.addAll((Collection>) ReflectionUtils.invokeStaticMethod(baseClass, implementationProvider.value())); + else + implementations.addAll(implementationRegistry.getImplementations(baseClass)); + + currentNode.put("type", "object"); + + var propsNode = new HashMap(); + currentNode.put("properties", propsNode); + var typeNode = new HashMap(); + propsNode.put("type", typeNode); + typeNode.put("type", "string"); + + var enumList = new ArrayList(); + typeNode.put("enum", enumList); + + var requiredList = new ArrayList(); + requiredList.add("type"); + currentNode.put("required", requiredList); + + var processedProperties = new HashMap(); + processBean(currentNode, baseClass, processedProperties); + + var oneOfList = new ArrayList>(); + currentNode.put("oneOf", oneOfList); + + for (var implementation: implementations) { + enumList.add(implementation.getSimpleName()); + var oneOfItemNode = new HashMap(); + oneOfList.add(oneOfItemNode); + var description = EditableUtils.getDescription(implementation); + if (description != null) + oneOfItemNode.put("description", description); + processBean(oneOfItemNode, implementation, new HashMap<>(processedProperties)); + var implementationPropsNode = (Map) oneOfItemNode.get("properties"); + var typeConstNode = new HashMap(); + typeConstNode.put("const", implementation.getSimpleName()); + implementationPropsNode.put("type", typeConstNode); + } + } + + private void processCollectionProperty(Map currentNode, Class collectionElementClass) { + currentNode.put("type", "array"); + var itemsNode = new HashMap(); + currentNode.put("items", itemsNode); + if (Collection.class.isAssignableFrom(collectionElementClass)) { + itemsNode.put("type", "array"); + var nestedItemsNode = new HashMap(); + nestedItemsNode.put("type", "string"); + itemsNode.put("items", nestedItemsNode); + } else { + processType(itemsNode, collectionElementClass); + } + } + + @Path("/") + @GET + @SuppressWarnings("unchecked") + public String getBuildSpecSchema() { + if (schema == null) { + var rootNode = new HashMap(); + rootNode.put("$schema", "https://json-schema.org/draft/2020-12/schema"); + rootNode.put("title", "YAML schema of build spec file"); + rootNode.put("type", "object"); + + var propsNode = new HashMap(); + rootNode.put("properties", propsNode); + + var versionNode = new HashMap(); + propsNode.put("version", versionNode); + versionNode.put("type", "integer"); + versionNode.put("const", Integer.parseInt(MigrationHelper.getVersion(BuildSpec.class))); + + var jobsNode = new HashMap(); + propsNode.put("jobs", jobsNode); + processCollectionProperty(jobsNode, Job.class); + + var servicesNode = new HashMap(); + propsNode.put("services", servicesNode); + processCollectionProperty(servicesNode, Service.class); + + var propertiesNode = new HashMap(); + propsNode.put("properties", propertiesNode); + processCollectionProperty(propertiesNode, JobProperty.class); + + var importsNode = new HashMap(); + propsNode.put("imports", importsNode); + processCollectionProperty(importsNode, Import.class); + + var jobPropsNode = (Map) ((Map) jobsNode.get("items")).get("properties"); + + var stepTemplatesNode = new HashMap(); + propsNode.put("stepTemplates", stepTemplatesNode); + stepTemplatesNode.put("type", "array"); + var stepTemplateNode = new HashMap(); + stepTemplatesNode.put("items", stepTemplateNode); + stepTemplateNode.put("type", "object"); + var stepTemplatePropsNode = new HashMap(); + stepTemplateNode.put("properties", stepTemplatePropsNode); + stepTemplatePropsNode.put("steps", jobPropsNode.get("steps")); + stepTemplatePropsNode.put("paramSpecs", jobPropsNode.get("paramSpecs")); + + var requiredList = new ArrayList(); + requiredList.add("version"); + rootNode.put("required", requiredList); + rootNode.put("additionalProperties", false); + + schema = yaml.dump(rootNode); + } + return schema; + } + + } \ No newline at end of file diff --git a/server-core/src/main/java/io/onedev/server/buildspec/job/Job.java b/server-core/src/main/java/io/onedev/server/buildspec/job/Job.java index e82b02bb05..215e6f9152 100644 --- a/server-core/src/main/java/io/onedev/server/buildspec/job/Job.java +++ b/server-core/src/main/java/io/onedev/server/buildspec/job/Job.java @@ -32,6 +32,7 @@ import io.onedev.commons.codeassist.InputSuggestion; import io.onedev.server.OneDev; import io.onedev.server.annotation.ChoiceProvider; import io.onedev.server.annotation.ClassValidating; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; import io.onedev.server.annotation.Interpolative; import io.onedev.server.annotation.RetryCondition; @@ -105,7 +106,7 @@ public class Job implements NamedElement, Validatable { private String sequentialGroup; - private String retryCondition = "never"; + private String retryCondition; private int maxRetries = 3; @@ -279,8 +280,7 @@ public class Job implements NamedElement, Validatable { this.sequentialGroup = sequentialGroup; } - @Editable(order=9400, group="More Settings", description="Specify condition to retry build upon failure") - @NotEmpty + @Editable(order=9400, placeholder="Never retry", group="More Settings", description="Specify condition to retry build upon failure") @RetryCondition public String getRetryCondition() { return retryCondition; @@ -292,6 +292,7 @@ public class Job implements NamedElement, Validatable { @Editable(order=9410, group="More Settings", description="Maximum of retries before giving up") @Min(value=1, message="This value should not be less than 1") + @DependsOn(property="retryCondition") public int getMaxRetries() { return maxRetries; } @@ -304,6 +305,7 @@ public class Job implements NamedElement, Validatable { "Delay of subsequent retries will be calculated using an exponential back-off based on " + "this value") @Min(value=1, message="This value should not be less than 1") + @DependsOn(property="retryCondition") public int getRetryDelay() { return retryDelay; } diff --git a/server-core/src/main/java/io/onedev/server/buildspec/job/action/CreateIssueAction.java b/server-core/src/main/java/io/onedev/server/buildspec/job/action/CreateIssueAction.java index 63ea1b1ca6..b6b2110030 100644 --- a/server-core/src/main/java/io/onedev/server/buildspec/job/action/CreateIssueAction.java +++ b/server-core/src/main/java/io/onedev/server/buildspec/job/action/CreateIssueAction.java @@ -1,10 +1,29 @@ package io.onedev.server.buildspec.job.action; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +import javax.annotation.Nullable; +import javax.validation.Valid; +import javax.validation.ValidationException; +import javax.validation.constraints.NotEmpty; + +import org.apache.shiro.subject.Subject; + import edu.emory.mathcs.backport.java.util.Collections; import io.onedev.commons.codeassist.InputSuggestion; import io.onedev.commons.utils.ExplicitException; import io.onedev.server.OneDev; -import io.onedev.server.annotation.*; +import io.onedev.server.annotation.ChoiceProvider; +import io.onedev.server.annotation.DependsOn; +import io.onedev.server.annotation.Editable; +import io.onedev.server.annotation.FieldNamesProvider; +import io.onedev.server.annotation.Interpolative; +import io.onedev.server.annotation.Multiline; +import io.onedev.server.annotation.OmitName; import io.onedev.server.buildspec.BuildSpec; import io.onedev.server.buildspec.job.Job; import io.onedev.server.entitymanager.IssueManager; @@ -20,18 +39,9 @@ import io.onedev.server.model.support.issue.field.instance.FieldInstance; import io.onedev.server.persistence.TransactionManager; import io.onedev.server.security.SecurityUtils; import io.onedev.server.security.permission.AccessProject; -import io.onedev.server.util.EditContext; import io.onedev.server.util.facade.ProjectCache; import io.onedev.server.web.page.project.ProjectPage; import io.onedev.server.web.util.WicketUtils; -import org.apache.shiro.subject.Subject; - -import javax.annotation.Nullable; -import javax.validation.Valid; -import javax.validation.ValidationException; -import javax.validation.constraints.NotEmpty; -import java.util.*; -import java.util.stream.Collectors; @Editable(name="Create issue", order=300) public class CreateIssueAction extends PostBuildAction { @@ -80,7 +90,7 @@ public class CreateIssueAction extends PostBuildAction { @Editable(order=910, description="Specify a secret to be used as access token to create issue in " + "above project if it is not publicly accessible") @ChoiceProvider("getAccessTokenSecretChoices") - @ShowCondition("isProjectSpecified") + @DependsOn(property="projectPath") @Nullable public String getAccessTokenSecret() { return accessTokenSecret; @@ -89,11 +99,6 @@ public class CreateIssueAction extends PostBuildAction { public void setAccessTokenSecret(String accessTokenSecret) { this.accessTokenSecret = accessTokenSecret; } - - @SuppressWarnings("unused") - private static boolean isProjectSpecified() { - return EditContext.get().getInputValue("projectPath") != null; - } @SuppressWarnings("unused") private static List getAccessTokenSecretChoices() { diff --git a/server-core/src/main/java/io/onedev/server/buildspec/job/retrycondition/NeverCriteria.java b/server-core/src/main/java/io/onedev/server/buildspec/job/retrycondition/NeverCriteria.java deleted file mode 100644 index 83de013a4f..0000000000 --- a/server-core/src/main/java/io/onedev/server/buildspec/job/retrycondition/NeverCriteria.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.onedev.server.buildspec.job.retrycondition; - -import javax.annotation.Nullable; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.From; -import javax.persistence.criteria.Predicate; - -import io.onedev.server.util.ProjectScope; -import io.onedev.server.util.criteria.Criteria; - -public class NeverCriteria extends Criteria { - - private static final long serialVersionUID = 1L; - - @Override - public Predicate getPredicate(@Nullable ProjectScope projectScope, CriteriaQuery query, From from, CriteriaBuilder builder) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean matches(RetryContext context) { - return false; - } - - @Override - public String toStringWithoutParens() { - return RetryCondition.getRuleName(RetryConditionLexer.Never); - } - -} diff --git a/server-core/src/main/java/io/onedev/server/buildspec/job/retrycondition/RetryCondition.g4 b/server-core/src/main/java/io/onedev/server/buildspec/job/retrycondition/RetryCondition.g4 index e8ad53ba5a..7a5f896a43 100644 --- a/server-core/src/main/java/io/onedev/server/buildspec/job/retrycondition/RetryCondition.g4 +++ b/server-core/src/main/java/io/onedev/server/buildspec/job/retrycondition/RetryCondition.g4 @@ -1,7 +1,7 @@ grammar RetryCondition; condition - : WS* (criteria|Never) WS* EOF + : WS* criteria WS* EOF ; criteria @@ -12,11 +12,7 @@ criteria | Not WS* LParens WS* criteria WS* RParens #NotCriteria | LParens WS* criteria WS* RParens #ParensCriteria ; - -Never - : 'never' - ; - + Contains : 'contains' ; diff --git a/server-core/src/main/java/io/onedev/server/buildspec/job/retrycondition/RetryCondition.java b/server-core/src/main/java/io/onedev/server/buildspec/job/retrycondition/RetryCondition.java index 51b75de33d..4ccac506b1 100644 --- a/server-core/src/main/java/io/onedev/server/buildspec/job/retrycondition/RetryCondition.java +++ b/server-core/src/main/java/io/onedev/server/buildspec/job/retrycondition/RetryCondition.java @@ -87,60 +87,57 @@ public class RetryCondition extends Criteria { Criteria criteria; - if (conditionContext.Never() != null) { - criteria = new NeverCriteria(); - } else { - criteria = new RetryConditionBaseVisitor>() { - - @Override - public Criteria visitParensCriteria(ParensCriteriaContext ctx) { - return visit(ctx.criteria()).withParens(true); - } - - @Override - public Criteria visitFieldOperatorCriteria(FieldOperatorCriteriaContext ctx) { - String fieldName = getValue(ctx.Quoted().getText()); - int operator = ctx.operator.getType(); - checkField(job, fieldName, operator); - return new ParamEmptyCriteria(fieldName, operator); - } - - @Override - public Criteria visitFieldOperatorValueCriteria(FieldOperatorValueCriteriaContext ctx) { - String fieldName = getValue(ctx.Quoted(0).getText()); - String fieldValue = getValue(ctx.Quoted(1).getText()); - int operator = ctx.operator.getType(); - checkField(job, fieldName, operator); + criteria = new RetryConditionBaseVisitor>() { - if (fieldName.equals(NAME_LOG)) - return new LogCriteria(fieldValue); - else - return new ParamCriteria(fieldName, fieldValue, operator); - } - - @Override - public Criteria visitOrCriteria(OrCriteriaContext ctx) { - List> childCriterias = new ArrayList<>(); - for (CriteriaContext childCtx: ctx.criteria()) - childCriterias.add(visit(childCtx)); - return new OrCriteria(childCriterias); - } - - @Override - public Criteria visitAndCriteria(AndCriteriaContext ctx) { - List> childCriterias = new ArrayList<>(); - for (CriteriaContext childCtx: ctx.criteria()) - childCriterias.add(visit(childCtx)); - return new AndCriteria(childCriterias); - } - - @Override - public Criteria visitNotCriteria(NotCriteriaContext ctx) { - return new NotCriteria(visit(ctx.criteria())); - } - - }.visit(conditionContext.criteria()); - } + @Override + public Criteria visitParensCriteria(ParensCriteriaContext ctx) { + return visit(ctx.criteria()).withParens(true); + } + + @Override + public Criteria visitFieldOperatorCriteria(FieldOperatorCriteriaContext ctx) { + String fieldName = getValue(ctx.Quoted().getText()); + int operator = ctx.operator.getType(); + checkField(job, fieldName, operator); + return new ParamEmptyCriteria(fieldName, operator); + } + + @Override + public Criteria visitFieldOperatorValueCriteria(FieldOperatorValueCriteriaContext ctx) { + String fieldName = getValue(ctx.Quoted(0).getText()); + String fieldValue = getValue(ctx.Quoted(1).getText()); + int operator = ctx.operator.getType(); + checkField(job, fieldName, operator); + + if (fieldName.equals(NAME_LOG)) + return new LogCriteria(fieldValue); + else + return new ParamCriteria(fieldName, fieldValue, operator); + } + + @Override + public Criteria visitOrCriteria(OrCriteriaContext ctx) { + List> childCriterias = new ArrayList<>(); + for (CriteriaContext childCtx: ctx.criteria()) + childCriterias.add(visit(childCtx)); + return new OrCriteria(childCriterias); + } + + @Override + public Criteria visitAndCriteria(AndCriteriaContext ctx) { + List> childCriterias = new ArrayList<>(); + for (CriteriaContext childCtx: ctx.criteria()) + childCriterias.add(visit(childCtx)); + return new AndCriteria(childCriterias); + } + + @Override + public Criteria visitNotCriteria(NotCriteriaContext ctx) { + return new NotCriteria(visit(ctx.criteria())); + } + + }.visit(conditionContext.criteria()); + return new RetryCondition(criteria); } diff --git a/server-core/src/main/java/io/onedev/server/buildspec/param/spec/choiceparam/ChoiceParam.java b/server-core/src/main/java/io/onedev/server/buildspec/param/spec/choiceparam/ChoiceParam.java index 2b6dce2dc3..a93965b7fe 100755 --- a/server-core/src/main/java/io/onedev/server/buildspec/param/spec/choiceparam/ChoiceParam.java +++ b/server-core/src/main/java/io/onedev/server/buildspec/param/spec/choiceparam/ChoiceParam.java @@ -7,15 +7,14 @@ import java.util.Map; import javax.validation.Valid; import javax.validation.constraints.NotNull; +import io.onedev.server.annotation.DependsOn; +import io.onedev.server.annotation.Editable; import io.onedev.server.buildspec.param.spec.ParamSpec; import io.onedev.server.buildspec.param.spec.choiceparam.defaultmultivalueprovider.DefaultMultiValueProvider; import io.onedev.server.buildspec.param.spec.choiceparam.defaultvalueprovider.DefaultValueProvider; import io.onedev.server.buildspecmodel.inputspec.choiceinput.ChoiceInput; import io.onedev.server.buildspecmodel.inputspec.choiceinput.choiceprovider.ChoiceProvider; import io.onedev.server.buildspecmodel.inputspec.choiceinput.choiceprovider.SpecifiedChoices; -import io.onedev.server.util.EditContext; -import io.onedev.server.annotation.Editable; -import io.onedev.server.annotation.ShowCondition; @Editable(order=145, name= ParamSpec.ENUMERATION) public class ChoiceParam extends ParamSpec { @@ -39,8 +38,8 @@ public class ChoiceParam extends ParamSpec { this.choiceProvider = choiceProvider; } - @ShowCondition("isDefaultValueProviderVisible") @Editable(order=1100, name="Default Value", placeholder="No default value") + @DependsOn(property="allowMultiple", value="false") @Valid public DefaultValueProvider getDefaultValueProvider() { return defaultValueProvider; @@ -50,13 +49,8 @@ public class ChoiceParam extends ParamSpec { this.defaultValueProvider = defaultValueProvider; } - @SuppressWarnings("unused") - private static boolean isDefaultValueProviderVisible() { - return EditContext.get().getInputValue("allowMultiple").equals(false); - } - - @ShowCondition("isDefaultMultiValueProviderVisible") @Editable(order=1100, name="Default Value", placeholder="No default value") + @DependsOn(property="allowMultiple") @Valid public DefaultMultiValueProvider getDefaultMultiValueProvider() { return defaultMultiValueProvider; @@ -66,11 +60,6 @@ public class ChoiceParam extends ParamSpec { this.defaultMultiValueProvider = defaultMultiValueProvider; } - @SuppressWarnings("unused") - private static boolean isDefaultMultiValueProviderVisible() { - return EditContext.get().getInputValue("allowMultiple").equals(true); - } - @Override public List getPossibleValues() { return ChoiceInput.getPossibleValues(choiceProvider); diff --git a/server-core/src/main/java/io/onedev/server/buildspec/param/spec/userchoiceparam/UserChoiceParam.java b/server-core/src/main/java/io/onedev/server/buildspec/param/spec/userchoiceparam/UserChoiceParam.java index 301d27a8c1..0def616369 100755 --- a/server-core/src/main/java/io/onedev/server/buildspec/param/spec/userchoiceparam/UserChoiceParam.java +++ b/server-core/src/main/java/io/onedev/server/buildspec/param/spec/userchoiceparam/UserChoiceParam.java @@ -6,15 +6,14 @@ import java.util.Map; import javax.validation.Valid; import javax.validation.constraints.NotNull; +import io.onedev.server.annotation.DependsOn; +import io.onedev.server.annotation.Editable; import io.onedev.server.buildspec.param.spec.ParamSpec; import io.onedev.server.buildspec.param.spec.userchoiceparam.defaultmultivalueprovider.DefaultMultiValueProvider; import io.onedev.server.buildspec.param.spec.userchoiceparam.defaultvalueprovider.DefaultValueProvider; import io.onedev.server.buildspecmodel.inputspec.userchoiceinput.UserChoiceInput; import io.onedev.server.buildspecmodel.inputspec.userchoiceinput.choiceprovider.AllUsers; import io.onedev.server.buildspecmodel.inputspec.userchoiceinput.choiceprovider.ChoiceProvider; -import io.onedev.server.util.EditContext; -import io.onedev.server.annotation.Editable; -import io.onedev.server.annotation.ShowCondition; @Editable(order=150, name= ParamSpec.USER) public class UserChoiceParam extends ParamSpec { @@ -39,7 +38,7 @@ public class UserChoiceParam extends ParamSpec { } @Editable(order=1100, name="Default Value", placeholder="No default value") - @ShowCondition("isDefaultValueProviderVisible") + @DependsOn(property="allowMultiple", value="false") @Valid public DefaultValueProvider getDefaultValueProvider() { return defaultValueProvider; @@ -49,13 +48,8 @@ public class UserChoiceParam extends ParamSpec { this.defaultValueProvider = defaultValueProvider; } - @SuppressWarnings("unused") - private static boolean isDefaultValueProviderVisible() { - return EditContext.get().getInputValue("allowMultiple").equals(false); - } - - @ShowCondition("isDefaultMultiValueProviderVisible") @Editable(order=1100, name="Default Value", placeholder="No default value") + @DependsOn(property="allowMultiple") @Valid public DefaultMultiValueProvider getDefaultMultiValueProvider() { return defaultMultiValueProvider; @@ -65,11 +59,6 @@ public class UserChoiceParam extends ParamSpec { this.defaultMultiValueProvider = defaultMultiValueProvider; } - @SuppressWarnings("unused") - private static boolean isDefaultMultiValueProviderVisible() { - return EditContext.get().getInputValue("allowMultiple").equals(true); - } - @Override public List getPossibleValues() { return UserChoiceInput.getPossibleValues(); diff --git a/server-core/src/main/java/io/onedev/server/buildspec/step/CommandStep.java b/server-core/src/main/java/io/onedev/server/buildspec/step/CommandStep.java index f9ac3a1402..2a3bf3375d 100644 --- a/server-core/src/main/java/io/onedev/server/buildspec/step/CommandStep.java +++ b/server-core/src/main/java/io/onedev/server/buildspec/step/CommandStep.java @@ -11,10 +11,10 @@ import javax.validation.constraints.NotNull; import io.onedev.commons.codeassist.InputSuggestion; import io.onedev.k8shelper.StepFacade; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; import io.onedev.server.annotation.Interpolative; import io.onedev.server.annotation.RegEx; -import io.onedev.server.annotation.ShowCondition; import io.onedev.server.buildspec.BuildSpec; import io.onedev.server.buildspec.job.EnvVar; import io.onedev.server.buildspec.param.ParamCombination; @@ -23,7 +23,6 @@ import io.onedev.server.buildspec.step.commandinterpreter.Interpreter; import io.onedev.server.model.Build; import io.onedev.server.model.support.administration.jobexecutor.DockerAware; import io.onedev.server.model.support.administration.jobexecutor.JobExecutor; -import io.onedev.server.util.EditContext; @Editable(order=100, name="Execute Commands") public class CommandStep extends Step { @@ -57,14 +56,9 @@ public class CommandStep extends Step { public void setRunInContainer(boolean runInContainer) { this.runInContainer = runInContainer; } - - @SuppressWarnings("unused") - private static boolean isRunInContainerEnabled() { - return (boolean) EditContext.get().getInputValue("runInContainer"); - } @Editable(order=100, name="container:image", description="Specify container image to execute commands inside") - @ShowCondition("isRunInContainerEnabled") + @DependsOn(property="runInContainer") @Interpolative(variableSuggester="suggestVariables") @NotEmpty public String getImage() { @@ -92,7 +86,7 @@ public class CommandStep extends Step { @Editable(order=8000, name="Run As", group = "More Settings", placeholder = "root", description = "Optionally specify uid:gid to run container as. " + "Note: This setting should be left empty if container runtime is rootless or " + "using user namespace remapping") - @ShowCondition("isRunInContainerEnabled") + @DependsOn(property="runInContainer") @RegEx(pattern="\\d+:\\d+", message = "Should be specified in form of :") public String getRunAs() { return runAs; @@ -105,7 +99,7 @@ public class CommandStep extends Step { @Editable(order=8500, group="More Settings", description="Optionally specify registry logins to override " + "those defined in job executor. For built-in registry, use @server_url@ for registry url, " + "@job_token@ for user name, and access token secret for password secret") - @ShowCondition("isRunInContainerEnabled") + @DependsOn(property="runInContainer") public List getRegistryLogins() { return registryLogins; } @@ -125,7 +119,7 @@ public class CommandStep extends Step { } @Editable(order=10000, name="Enable TTY Mode", group = "More Settings", description=USE_TTY_HELP) - @ShowCondition("isRunInContainerEnabled") + @DependsOn(property="runInContainer") public boolean isUseTTY() { return useTTY; } diff --git a/server-core/src/main/java/io/onedev/server/buildspec/step/SetupCacheStep.java b/server-core/src/main/java/io/onedev/server/buildspec/step/SetupCacheStep.java index 6ca6f4b0f8..63f2d36843 100644 --- a/server-core/src/main/java/io/onedev/server/buildspec/step/SetupCacheStep.java +++ b/server-core/src/main/java/io/onedev/server/buildspec/step/SetupCacheStep.java @@ -1,6 +1,5 @@ package io.onedev.server.buildspec.step; -import static io.onedev.k8shelper.SetupCacheFacade.UploadStrategy.UPLOAD_IF_CHANGED; import static io.onedev.k8shelper.SetupCacheFacade.UploadStrategy.UPLOAD_IF_NOT_HIT; import static java.util.stream.Collectors.toList; @@ -15,16 +14,15 @@ import io.onedev.commons.codeassist.InputSuggestion; import io.onedev.k8shelper.SetupCacheFacade; import io.onedev.k8shelper.StepFacade; import io.onedev.server.annotation.ChoiceProvider; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; import io.onedev.server.annotation.Interpolative; import io.onedev.server.annotation.ProjectChoice; -import io.onedev.server.annotation.ShowCondition; import io.onedev.server.buildspec.BuildSpec; import io.onedev.server.buildspec.param.ParamCombination; import io.onedev.server.model.Build; import io.onedev.server.model.Project; import io.onedev.server.model.support.administration.jobexecutor.JobExecutor; -import io.onedev.server.util.EditContext; @Editable(order=55, name="Set Up Cache", description = "Set up job cache to speed up job execution. " + "Check this tutorial " + @@ -103,7 +101,7 @@ public class SetupCacheStep extends Step { "detect cache changes. Use '**', '*' or '?' for path wildcard match. " + "Multiple files should be separated by space, and single file containing space should be quoted") @Interpolative(variableSuggester="suggestVariables") - @ShowCondition("isUploadIfChanged") + @DependsOn(property="uploadStrategy", value="UPLOAD_IF_CHANGED") public String getChangeDetectionExcludes() { return changeDetectionExcludes; } @@ -111,11 +109,6 @@ public class SetupCacheStep extends Step { public void setChangeDetectionExcludes(String changeDetectionExcludes) { this.changeDetectionExcludes = changeDetectionExcludes; } - - @SuppressWarnings("unused") - private static boolean isUploadIfChanged() { - return UPLOAD_IF_CHANGED == EditContext.get().getInputValue("uploadStrategy"); - } @Editable(order=450, name="Upload to Project", placeholder = "Current project", description = "In case cache needs to be uploaded, this property " + "specifies target project for the upload. Leave empty for current project") diff --git a/server-core/src/main/java/io/onedev/server/data/migration/DataMigrator.java b/server-core/src/main/java/io/onedev/server/data/migration/DataMigrator.java index e984b635b6..f6f81774d0 100644 --- a/server-core/src/main/java/io/onedev/server/data/migration/DataMigrator.java +++ b/server-core/src/main/java/io/onedev/server/data/migration/DataMigrator.java @@ -8256,4 +8256,25 @@ public class DataMigrator { } } + private void migrate209(File dataDir, Stack versions) { + for (File file : dataDir.listFiles()) { + if (file.getName().startsWith("Settings.xml")) { + VersionedXmlDoc dom = VersionedXmlDoc.fromFile(file); + for (Element element : dom.getRootElement().elements()) { + String key = element.elementTextTrim("key"); + if (key.equals("BRANDING")) { + Element valueElement = element.element("value"); + if (valueElement != null) { + Element urlElement = valueElement.element("url"); + if (urlElement != null) { + urlElement.detach(); + } + } + } + } + dom.writeToFile(file, false); + } + } + } + } diff --git a/server-core/src/main/java/io/onedev/server/data/migration/VersionedYamlDoc.java b/server-core/src/main/java/io/onedev/server/data/migration/VersionedYamlDoc.java index 0ae16c3b14..0dffe1b409 100644 --- a/server-core/src/main/java/io/onedev/server/data/migration/VersionedYamlDoc.java +++ b/server-core/src/main/java/io/onedev/server/data/migration/VersionedYamlDoc.java @@ -1,12 +1,22 @@ package io.onedev.server.data.migration; -import edu.emory.mathcs.backport.java.util.Collections; -import io.onedev.commons.loader.ImplementationRegistry; -import io.onedev.commons.utils.ClassUtils; -import io.onedev.commons.utils.ExplicitException; -import io.onedev.server.OneDev; -import io.onedev.server.annotation.Editable; -import io.onedev.server.util.BeanUtils; +import java.beans.IntrospectionException; +import java.beans.PropertyDescriptor; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.hibernate.proxy.HibernateProxyHelper; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.DumperOptions.FlowStyle; @@ -18,19 +28,22 @@ import org.yaml.snakeyaml.introspector.BeanAccess; import org.yaml.snakeyaml.introspector.MethodProperty; import org.yaml.snakeyaml.introspector.Property; import org.yaml.snakeyaml.introspector.PropertyUtils; -import org.yaml.snakeyaml.nodes.*; +import org.yaml.snakeyaml.nodes.MappingNode; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.nodes.NodeTuple; +import org.yaml.snakeyaml.nodes.ScalarNode; +import org.yaml.snakeyaml.nodes.Tag; import org.yaml.snakeyaml.representer.Representer; import org.yaml.snakeyaml.resolver.Resolver; import org.yaml.snakeyaml.serializer.Serializer; -import java.beans.IntrospectionException; -import java.beans.PropertyDescriptor; -import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.*; +import edu.emory.mathcs.backport.java.util.Collections; +import io.onedev.commons.loader.ImplementationRegistry; +import io.onedev.commons.utils.ClassUtils; +import io.onedev.commons.utils.ExplicitException; +import io.onedev.server.OneDev; +import io.onedev.server.annotation.Editable; +import io.onedev.server.util.BeanUtils; public class VersionedYamlDoc extends MappingNode { @@ -96,7 +109,7 @@ public class VersionedYamlDoc extends MappingNode { getValue().add(0, new NodeTuple(keyNode, versionNode)); } } - + public String toYaml() { StringWriter writer = new StringWriter(); DumperOptions dumperOptions = new DumperOptions(); @@ -122,6 +135,12 @@ public class VersionedYamlDoc extends MappingNode { public Object construct(Node node) { return constructDocument(node); } + + @Override + protected String constructScalar(ScalarNode node) { + String value = super.constructScalar(node); + return (value != null && value.isEmpty()) ? null : value; + } @Override protected Class getClassForNode(Node node) { @@ -191,6 +210,8 @@ public class VersionedYamlDoc extends MappingNode { Method setter = BeanUtils.findSetter(getter); if (editable != null && setter != null) { String propertyName = BeanUtils.getPropertyName(getter); + if (propertyName.equals("type")) + throw new ExplicitException("Property 'type' is reserved (class: " + type.getName() + ")"); try { properties.add(new MethodProperty(new PropertyDescriptor(propertyName, getter, setter))); } catch (IntrospectionException e) { diff --git a/server-core/src/main/java/io/onedev/server/entitymanager/BuildManager.java b/server-core/src/main/java/io/onedev/server/entitymanager/BuildManager.java index b59b77bd8a..52065f7420 100644 --- a/server-core/src/main/java/io/onedev/server/entitymanager/BuildManager.java +++ b/server-core/src/main/java/io/onedev/server/entitymanager/BuildManager.java @@ -45,6 +45,9 @@ public interface BuildManager extends EntityManager { @Nullable String refName, @Nullable Optional request, @Nullable Optional issue, Map> params); + @Nullable + Build findPreviousSuccessfulSimilar(Build build); + Collection query(Project project, ObjectId commitId, @Nullable String jobName); Collection query(Project project, ObjectId commitId); diff --git a/server-core/src/main/java/io/onedev/server/entitymanager/impl/DefaultBuildManager.java b/server-core/src/main/java/io/onedev/server/entitymanager/impl/DefaultBuildManager.java index f0c93a4b2f..144372586f 100644 --- a/server-core/src/main/java/io/onedev/server/entitymanager/impl/DefaultBuildManager.java +++ b/server-core/src/main/java/io/onedev/server/entitymanager/impl/DefaultBuildManager.java @@ -328,6 +328,32 @@ public class DefaultBuildManager extends BaseEntityManager implements Bui return getSession().createQuery(query).list(); } + @Sessional + @Override + public Build findPreviousSuccessfulSimilar(Build build) { + CriteriaBuilder builder = getSession().getCriteriaBuilder(); + CriteriaQuery query = builder.createQuery(Build.class); + Root root = query.from(Build.class); + + List predicates = new ArrayList<>(); + predicates.add(builder.equal(root.get(Build.PROP_PROJECT), build.getProject())); + predicates.add(builder.equal(root.get(Build.PROP_JOB_NAME), build.getJobName())); + predicates.add(builder.equal(root.get(Build.PROP_STATUS), Build.Status.SUCCESSFUL)); + predicates.add(builder.lessThan(root.get(Build.PROP_NUMBER), build.getNumber())); + + var paramPredicate = getPredicate(root, builder, build.getParamMap()); + if (paramPredicate != null) + predicates.add(paramPredicate); + + query.where(predicates.toArray(new Predicate[0])); + query.orderBy(builder.desc(root.get(Build.PROP_NUMBER))); + + return getSession().createQuery(query) + .setFirstResult(0) + .setMaxResults(1) + .uniqueResult(); + } + @SuppressWarnings("unchecked") @Sessional @Override diff --git a/server-core/src/main/java/io/onedev/server/job/DefaultJobManager.java b/server-core/src/main/java/io/onedev/server/job/DefaultJobManager.java index 78f7da95be..9097959195 100644 --- a/server-core/src/main/java/io/onedev/server/job/DefaultJobManager.java +++ b/server-core/src/main/java/io/onedev/server/job/DefaultJobManager.java @@ -286,7 +286,7 @@ public class DefaultJobManager implements JobManager, Runnable, CodePullAuthoriz for (ConstraintViolation violation : validator.validate(buildSpec)) { String message = String.format("Error validating build spec (project: %s, commit: %s, location: %s, message: %s)", project.getPath(), commitId.name(), violation.getPropertyPath(), violation.getMessage()); - throw new ExplicitException(message); + throw new ValidationException(message); } } finally { Project.pop(); @@ -703,19 +703,23 @@ public class DefaultJobManager implements JobManager, Runnable, CodePullAuthoriz private boolean checkRetry(Job job, JobContext jobContext, TaskLogger jobLogger, @Nullable Throwable throwable, int retried) { if (retried < job.getMaxRetries() && sessionManager.call(() -> { - RetryCondition retryCondition = RetryCondition.parse(job, job.getRetryCondition()); - AtomicReference errorMessage = new AtomicReference<>(null); - if (throwable != null) { - log(throwable, new TaskLogger() { + if (job.getRetryCondition() != null) { + RetryCondition retryCondition = RetryCondition.parse(job, job.getRetryCondition()); + AtomicReference errorMessage = new AtomicReference<>(null); + if (throwable != null) { + log(throwable, new TaskLogger() { - @Override - public void log(String message, String sessionId) { - errorMessage.set(message); - } + @Override + public void log(String message, String sessionId) { + errorMessage.set(message); + } - }); + }); + } + return retryCondition.matches(new RetryContext(buildManager.load(jobContext.getBuildId()), errorMessage.get())); + } else { + return false; } - return retryCondition.matches(new RetryContext(buildManager.load(jobContext.getBuildId()), errorMessage.get())); })) { if (throwable != null) log(throwable, jobLogger); diff --git a/server-core/src/main/java/io/onedev/server/mail/DefaultMailManager.java b/server-core/src/main/java/io/onedev/server/mail/DefaultMailManager.java index 3c9d81b9f8..e41e59d15a 100644 --- a/server-core/src/main/java/io/onedev/server/mail/DefaultMailManager.java +++ b/server-core/src/main/java/io/onedev/server/mail/DefaultMailManager.java @@ -105,7 +105,6 @@ import io.onedev.server.model.PullRequestComment; import io.onedev.server.model.PullRequestWatch; import io.onedev.server.model.Setting; import io.onedev.server.model.User; -import io.onedev.server.model.support.administration.BrandingSetting; import io.onedev.server.model.support.administration.GlobalIssueSetting; import io.onedev.server.model.support.administration.IssueCreationSetting; import io.onedev.server.model.support.administration.emailtemplates.EmailTemplates; @@ -330,7 +329,7 @@ public class DefaultMailManager implements MailManager, Serializable { } } - if (senderName == null || senderName.equalsIgnoreCase(BrandingSetting.DEFAULT_NAME)) + if (senderName == null || senderName.equalsIgnoreCase("onedev")) senderName = getQuoteMark(); else senderName += " " + getQuoteMark(); diff --git a/server-core/src/main/java/io/onedev/server/model/Group.java b/server-core/src/main/java/io/onedev/server/model/Group.java index df547f4f70..3aa8c2cb08 100644 --- a/server-core/src/main/java/io/onedev/server/model/Group.java +++ b/server-core/src/main/java/io/onedev/server/model/Group.java @@ -15,14 +15,13 @@ import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.jetbrains.annotations.Nullable; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; import io.onedev.server.annotation.Multiline; -import io.onedev.server.annotation.ShowCondition; import io.onedev.server.security.permission.BasePermission; import io.onedev.server.security.permission.CreateRootProjects; import io.onedev.server.security.permission.ProjectPermission; import io.onedev.server.security.permission.SystemAdministration; -import io.onedev.server.util.EditContext; import io.onedev.server.util.facade.GroupFacade; import io.onedev.server.util.facade.UserFacade; @@ -91,13 +90,8 @@ public class Group extends AbstractEntity implements BasePermission { this.administrator = administrator; } - @SuppressWarnings("unused") - private static boolean isAdministratorDisabled() { - return !(boolean) EditContext.get().getInputValue("administrator"); - } - @Editable(order=350, name="Can Create Root Projects", description="Whether or not to allow creating root projects (project without parent)") - @ShowCondition("isAdministratorDisabled") + @DependsOn(property="administrator", value="false") public boolean isCreateRootProjects() { return createRootProjects; } diff --git a/server-core/src/main/java/io/onedev/server/model/Project.java b/server-core/src/main/java/io/onedev/server/model/Project.java index a727352bf0..dace7db8d9 100644 --- a/server-core/src/main/java/io/onedev/server/model/Project.java +++ b/server-core/src/main/java/io/onedev/server/model/Project.java @@ -71,11 +71,11 @@ import io.onedev.commons.utils.match.Matcher; import io.onedev.commons.utils.match.PathMatcher; import io.onedev.commons.utils.match.StringMatcher; import io.onedev.server.OneDev; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; import io.onedev.server.annotation.Markdown; import io.onedev.server.annotation.ProjectKey; import io.onedev.server.annotation.ProjectName; -import io.onedev.server.annotation.ShowCondition; import io.onedev.server.annotation.SubscriptionRequired; import io.onedev.server.buildspec.BuildSpec; import io.onedev.server.entitymanager.BuildManager; @@ -129,7 +129,6 @@ import io.onedev.server.model.support.pullrequest.ProjectPullRequestSetting; import io.onedev.server.search.entity.SortField; import io.onedev.server.security.SecurityUtils; import io.onedev.server.util.ComponentContext; -import io.onedev.server.util.EditContext; import io.onedev.server.util.StatusInfo; import io.onedev.server.util.diff.WhitespaceOption; import io.onedev.server.util.facade.ProjectFacade; @@ -1022,7 +1021,7 @@ public class Project extends AbstractEntity implements LabelSupport getEditableIssueLinks() { return editableIssueLinks; @@ -329,7 +320,7 @@ public class Role extends AbstractEntity implements BasePermission { @Editable(order=650, name="Build Management", description="Build administrative permission for all jobs inside a project, " + "including batch operations over multiple builds") - @ShowCondition("isManageProjectDisabled") + @DependsOn(property="manageProject", value="false") public boolean isManageBuilds() { return manageBuilds; } @@ -338,14 +329,9 @@ public class Role extends AbstractEntity implements BasePermission { this.manageBuilds = manageBuilds; } - @SuppressWarnings("unused") - private static boolean isManageBuildsDisabled() { - return !(boolean)EditContext.get().getInputValue("manageBuilds"); - } - @Editable(order=675, description = "Enable to allow to upload build cache generated during CI/CD job. " + "Uploaded cache can be used by subsequent builds of the project as long as cache key matches") - @ShowCondition("isManageBuildsDisabled") + @DependsOn(property="manageBuilds", value="false") public boolean isUploadCache() { return uploadCache; } @@ -355,7 +341,7 @@ public class Role extends AbstractEntity implements BasePermission { } @Editable(order=700) - @ShowCondition("isManageBuildsDisabled") + @DependsOn(property="manageBuilds", value="false") public List getJobPrivileges() { return jobPrivileges; } diff --git a/server-core/src/main/java/io/onedev/server/model/User.java b/server-core/src/main/java/io/onedev/server/model/User.java index ae1d8804f1..8c5e575115 100644 --- a/server-core/src/main/java/io/onedev/server/model/User.java +++ b/server-core/src/main/java/io/onedev/server/model/User.java @@ -38,9 +38,9 @@ import com.google.common.base.MoreObjects; import edu.emory.mathcs.backport.java.util.Collections; import io.onedev.commons.utils.ExplicitException; import io.onedev.server.OneDev; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; import io.onedev.server.annotation.Password; -import io.onedev.server.annotation.ShowCondition; import io.onedev.server.annotation.SubscriptionRequired; import io.onedev.server.annotation.UserName; import io.onedev.server.entitymanager.EmailAddressManager; @@ -54,7 +54,6 @@ import io.onedev.server.model.support.issue.NamedIssueQuery; import io.onedev.server.model.support.pack.NamedPackQuery; import io.onedev.server.model.support.pullrequest.NamedPullRequestQuery; import io.onedev.server.security.SecurityUtils; -import io.onedev.server.util.EditContext; import io.onedev.server.util.facade.UserFacade; import io.onedev.server.util.watch.QuerySubscriptionSupport; import io.onedev.server.util.watch.QueryWatchSupport; @@ -564,11 +563,6 @@ public class User extends AbstractEntity implements AuthenticationInfo { } } - @SuppressWarnings("unused") - private static boolean isServiceAccountDisabled() { - return !(Boolean) EditContext.get().getInputValue(PROP_SERVICE_ACCOUNT); - } - @Editable(name="Login Name", order=100) @UserName @NotEmpty @@ -586,7 +580,7 @@ public class User extends AbstractEntity implements AuthenticationInfo { * time */ @Editable(order=150) - @ShowCondition("isServiceAccountDisabled") + @DependsOn(property="serviceAccount", value="false") @Password(checkPolicy=true, autoComplete="new-password") @NotEmpty @Nullable @@ -622,7 +616,7 @@ public class User extends AbstractEntity implements AuthenticationInfo { } @Editable(order=400, name="Notify Own Events", description = "Whether or not to send notifications for events generated by yourself") - @ShowCondition("isServiceAccountDisabled") + @DependsOn(property="serviceAccount", value="false") public boolean isNotifyOwnEvents() { return notifyOwnEvents; } diff --git a/server-core/src/main/java/io/onedev/server/model/support/administration/BrandingSetting.java b/server-core/src/main/java/io/onedev/server/model/support/administration/BrandingSetting.java index 7627fd81a2..74624ac300 100644 --- a/server-core/src/main/java/io/onedev/server/model/support/administration/BrandingSetting.java +++ b/server-core/src/main/java/io/onedev/server/model/support/administration/BrandingSetting.java @@ -5,15 +5,9 @@ import java.io.Serializable; public class BrandingSetting implements Serializable { private static final long serialVersionUID = 1L; - - public static final String DEFAULT_NAME = "OneDev"; - - public static final String DEFAULT_URL = "https://onedev.io"; - - private String name = DEFAULT_NAME; - - private String url = DEFAULT_URL; - + + private String name = "OneDev"; + public String getName() { return name; } @@ -21,21 +15,5 @@ public class BrandingSetting implements Serializable { public void setName(String name) { this.name = name; } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public static boolean isOEM(String brandName) { - return "GitOn".equals(brandName); - } - - public boolean isOEM() { - return isOEM(getName()); - } - + } diff --git a/server-core/src/main/java/io/onedev/server/model/support/administration/GroovyScript.java b/server-core/src/main/java/io/onedev/server/model/support/administration/GroovyScript.java index 35dfcf9f99..c5b58a466a 100644 --- a/server-core/src/main/java/io/onedev/server/model/support/administration/GroovyScript.java +++ b/server-core/src/main/java/io/onedev/server/model/support/administration/GroovyScript.java @@ -1,18 +1,18 @@ package io.onedev.server.model.support.administration; -import io.onedev.server.job.JobAuthorizationContext; -import io.onedev.server.util.EditContext; -import io.onedev.server.util.usage.Usage; -import io.onedev.server.annotation.Code; -import io.onedev.server.annotation.RegEx; -import io.onedev.server.annotation.Editable; -import io.onedev.server.annotation.JobMatch; -import io.onedev.server.annotation.ShowCondition; +import java.io.Serializable; +import java.util.List; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.Size; -import java.io.Serializable; -import java.util.List; + +import io.onedev.server.annotation.Code; +import io.onedev.server.annotation.DependsOn; +import io.onedev.server.annotation.Editable; +import io.onedev.server.annotation.JobMatch; +import io.onedev.server.annotation.RegEx; +import io.onedev.server.job.JobAuthorizationContext; +import io.onedev.server.util.usage.Usage; @Editable public class GroovyScript implements Serializable { @@ -60,13 +60,8 @@ public class GroovyScript implements Serializable { this.canBeUsedByBuildJobs = canBeUsedByBuildJobs; } - @SuppressWarnings("unused") - private static boolean isCanBeUsedByBuildJobsEnabled() { - return (boolean) EditContext.get().getInputValue("canBeUsedByBuildJobs"); - } - @Editable(order=500, placeholder="Any job", description="Optionally specify jobs allowed to use this script") - @ShowCondition("isCanBeUsedByBuildJobsEnabled") + @DependsOn(property="canBeUsedByBuildJobs") @JobMatch(withProjectCriteria = true) public String getAuthorization() { return authorization; diff --git a/server-core/src/main/java/io/onedev/server/model/support/administration/SecuritySetting.java b/server-core/src/main/java/io/onedev/server/model/support/administration/SecuritySetting.java index 82a7c10bad..151b656e2e 100644 --- a/server-core/src/main/java/io/onedev/server/model/support/administration/SecuritySetting.java +++ b/server-core/src/main/java/io/onedev/server/model/support/administration/SecuritySetting.java @@ -4,10 +4,9 @@ import io.onedev.server.OneDev; import io.onedev.server.annotation.Editable; import io.onedev.server.annotation.GroupChoice; import io.onedev.server.annotation.Patterns; -import io.onedev.server.annotation.ShowCondition; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.entitymanager.GroupManager; import io.onedev.server.model.Group; -import io.onedev.server.util.EditContext; import io.onedev.server.util.usage.Usage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -60,7 +59,7 @@ public class SecuritySetting implements Serializable { @Editable(order=225, name="Allowed Self Sign-Up Email Domain", placeholder = "Any domain", description = "Optionally specify allowed email domain for self sign-up users. Use '*' or '?' for pattern match") @Patterns - @ShowCondition("isEnableSelfRegisterEnabled") + @DependsOn(property="enableSelfRegister") public String getAllowedSelfRegisterEmailDomain() { return allowedSelfRegisterEmailDomain; } @@ -69,11 +68,6 @@ public class SecuritySetting implements Serializable { this.allowedSelfRegisterEmailDomain = allowedSelfRegisterEmailDomain; } - @SuppressWarnings("unused") - private static boolean isEnableSelfRegisterEnabled() { - return (boolean) EditContext.get().getInputValue("enableSelfRegister"); - } - @Editable(order=250, name="Enforce Password Policy", description="Enforce password policy for new users") public PasswordPolicy getPasswordPolicy() { return passwordPolicy; diff --git a/server-core/src/main/java/io/onedev/server/model/support/administration/SystemSetting.java b/server-core/src/main/java/io/onedev/server/model/support/administration/SystemSetting.java index e7bb8cb6f0..fd43b98d8b 100644 --- a/server-core/src/main/java/io/onedev/server/model/support/administration/SystemSetting.java +++ b/server-core/src/main/java/io/onedev/server/model/support/administration/SystemSetting.java @@ -17,6 +17,7 @@ import com.google.common.base.Preconditions; import io.onedev.server.OneDev; import io.onedev.server.ServerConfig; import io.onedev.server.annotation.ClassValidating; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; import io.onedev.server.annotation.ShowCondition; import io.onedev.server.git.location.CurlLocation; @@ -167,7 +168,7 @@ public class SystemSetting implements Serializable, Validatable { } @Editable(order=600, description="User avatar will be requested by appending a hash to this url") - @ShowCondition("isUseAvatarServiceEnabled") + @DependsOn(property="useAvatarService") @NotEmpty public String getAvatarServiceUrl() { return avatarServiceUrl; @@ -177,11 +178,6 @@ public class SystemSetting implements Serializable, Validatable { this.avatarServiceUrl = avatarServiceUrl; } - @SuppressWarnings("unused") - private static boolean isUseAvatarServiceEnabled() { - return (boolean) EditContext.get().getInputValue(PROP_USE_AVATAR_SERVICE); - } - public String getEffectiveSshRootUrl() { if (getSshRootUrl() != null) return getSshRootUrl(); diff --git a/server-core/src/main/java/io/onedev/server/model/support/channelnotification/ChannelNotification.java b/server-core/src/main/java/io/onedev/server/model/support/channelnotification/ChannelNotification.java index c2864cef7f..05550923ed 100644 --- a/server-core/src/main/java/io/onedev/server/model/support/channelnotification/ChannelNotification.java +++ b/server-core/src/main/java/io/onedev/server/model/support/channelnotification/ChannelNotification.java @@ -8,10 +8,10 @@ import javax.validation.constraints.Pattern; import io.onedev.server.annotation.BuildQuery; import io.onedev.server.annotation.CodeCommentQuery; import io.onedev.server.annotation.CommitQuery; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; import io.onedev.server.annotation.IssueQuery; import io.onedev.server.annotation.PullRequestQuery; -import io.onedev.server.annotation.ShowCondition; import io.onedev.server.event.project.ProjectEvent; import io.onedev.server.event.project.RefUpdated; import io.onedev.server.event.project.build.BuildEvent; @@ -19,7 +19,6 @@ import io.onedev.server.event.project.codecomment.CodeCommentEvent; import io.onedev.server.event.project.issue.IssueEvent; import io.onedev.server.event.project.pullrequest.PullRequestEvent; import io.onedev.server.search.entity.issue.IssueQueryParseOption; -import io.onedev.server.util.EditContext; @Editable public class ChannelNotification implements Serializable { @@ -70,7 +69,7 @@ public class ChannelNotification implements Serializable { @Editable(order=200, name="Applicable Issues", placeholder="All") @IssueQuery(withOrder=false) - @ShowCondition("isIssuesEnabled") + @DependsOn(property="issues") public String getIssueQuery() { return issueQuery; } @@ -79,11 +78,6 @@ public class ChannelNotification implements Serializable { this.issueQuery = issueQuery; } - @SuppressWarnings("unused") - private static boolean isIssuesEnabled() { - return (boolean) EditContext.get().getInputValue("issues"); - } - @Editable(order=300, name="Notify Pull Request Events") public boolean isPullRequests() { return pullRequests; @@ -95,7 +89,7 @@ public class ChannelNotification implements Serializable { @Editable(order=400, name="Applicable Pull Requests", placeholder="All") @PullRequestQuery(withOrder=false) - @ShowCondition("isPullRequestsEnabled") + @DependsOn(property="pullRequests") public String getPullRequestQuery() { return pullRequestQuery; } @@ -104,11 +98,6 @@ public class ChannelNotification implements Serializable { this.pullRequestQuery = pullRequestQuery; } - @SuppressWarnings("unused") - private static boolean isPullRequestsEnabled() { - return (boolean) EditContext.get().getInputValue("pullRequests"); - } - @Editable(order=500, name="Notify Build Events") public boolean isBuilds() { return builds; @@ -120,7 +109,7 @@ public class ChannelNotification implements Serializable { @Editable(order=600, name="Applicable Builds", placeholder="All") @BuildQuery(withOrder=false, withUnfinishedCriteria=true) - @ShowCondition("isBuildsEnabled") + @DependsOn(property="builds") public String getBuildQuery() { return buildQuery; } @@ -129,11 +118,6 @@ public class ChannelNotification implements Serializable { this.buildQuery = buildQuery; } - @SuppressWarnings("unused") - private static boolean isBuildsEnabled() { - return (boolean) EditContext.get().getInputValue("builds"); - } - @Editable(order=700, name="Notify Code Push Events") public boolean isCodePush() { return codePush; @@ -145,7 +129,7 @@ public class ChannelNotification implements Serializable { @Editable(order=800, name="Applicable Commits", placeholder="All") @CommitQuery - @ShowCondition("isCodePushEnabled") + @DependsOn(property="codePush") public String getCommitQuery() { return commitQuery; } @@ -154,11 +138,6 @@ public class ChannelNotification implements Serializable { this.commitQuery = commitQuery; } - @SuppressWarnings("unused") - private static boolean isCodePushEnabled() { - return (boolean) EditContext.get().getInputValue("codePush"); - } - @Editable(order=900, name="Notify Code Comment Events") public boolean isCodeComments() { return codeComments; @@ -170,7 +149,7 @@ public class ChannelNotification implements Serializable { @Editable(order=1000, name="Applicable Code Comments", placeholder="All") @CodeCommentQuery(withOrder=false) - @ShowCondition("isCodeCommentsEnabled") + @DependsOn(property="codeComments") public String getCodeCommentQuery() { return codeCommentQuery; } @@ -179,11 +158,6 @@ public class ChannelNotification implements Serializable { this.codeCommentQuery = codeCommentQuery; } - @SuppressWarnings("unused") - private static boolean isCodeCommentsEnabled() { - return (boolean) EditContext.get().getInputValue("codeComments"); - } - public boolean matches(ProjectEvent event) { if (event instanceof IssueEvent) { if (isIssues()) { diff --git a/server-core/src/main/java/io/onedev/server/model/support/code/BranchProtection.java b/server-core/src/main/java/io/onedev/server/model/support/code/BranchProtection.java index c6862524c6..42992bdb4a 100644 --- a/server-core/src/main/java/io/onedev/server/model/support/code/BranchProtection.java +++ b/server-core/src/main/java/io/onedev/server/model/support/code/BranchProtection.java @@ -1,14 +1,36 @@ package io.onedev.server.model.support.code; +import static java.util.regex.Pattern.CASE_INSENSITIVE; +import static java.util.regex.Pattern.UNICODE_CHARACTER_CLASS; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import javax.annotation.Nullable; +import javax.validation.Valid; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; + +import org.eclipse.jgit.lib.ObjectId; + import com.google.common.base.Joiner; import com.google.common.base.Splitter; + import io.onedev.commons.codeassist.InputSuggestion; import io.onedev.commons.utils.match.PathMatcher; import io.onedev.server.OneDev; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; import io.onedev.server.annotation.JobChoice; import io.onedev.server.annotation.Patterns; -import io.onedev.server.annotation.ShowCondition; import io.onedev.server.buildspec.BuildSpec; import io.onedev.server.entitymanager.BuildManager; import io.onedev.server.git.service.GitService; @@ -16,26 +38,12 @@ import io.onedev.server.model.Build; import io.onedev.server.model.Build.Status; import io.onedev.server.model.Project; import io.onedev.server.model.User; -import io.onedev.server.util.EditContext; import io.onedev.server.util.patternset.PatternSet; import io.onedev.server.util.reviewrequirement.ReviewRequirement; import io.onedev.server.util.usage.Usage; import io.onedev.server.util.usermatch.Anyone; import io.onedev.server.util.usermatch.UserMatch; import io.onedev.server.web.util.SuggestionUtils; -import org.eclipse.jgit.lib.ObjectId; - -import javax.annotation.Nullable; -import javax.validation.Valid; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotEmpty; -import java.io.Serializable; -import java.util.*; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import static java.util.regex.Pattern.CASE_INSENSITIVE; -import static java.util.regex.Pattern.UNICODE_CHARACTER_CLASS; @Editable public class BranchProtection implements Serializable { @@ -166,14 +174,9 @@ public class BranchProtection implements Serializable { this.enforceConventionalCommits = enforceConventionalCommits; } - @SuppressWarnings("unused") - private static boolean isEnforceConventionalCommitsEnabled() { - return (boolean) EditContext.get().getInputValue("enforceConventionalCommits"); - } - @Editable(order=380, placeholder = "Arbitrary type", description = "Optionally specify valid " + "types of conventional commits (hit ENTER to add value). Leave empty to allow arbitrary type") - @ShowCondition("isEnforceConventionalCommitsEnabled") + @DependsOn(property="enforceConventionalCommits") public List getCommitTypes() { return commitTypes; } @@ -184,7 +187,7 @@ public class BranchProtection implements Serializable { @Editable(order=390, placeholder = "Arbitrary scope", description = "Optionally specify valid " + "scopes of conventional commits (hit ENTER to add value). Leave empty to allow arbitrary scope") - @ShowCondition("isEnforceConventionalCommitsEnabled") + @DependsOn(property="enforceConventionalCommits") public List getCommitScopes() { return commitScopes; } @@ -194,7 +197,7 @@ public class BranchProtection implements Serializable { } @Editable(order=391) - @ShowCondition("isEnforceConventionalCommitsEnabled") + @DependsOn(property="enforceConventionalCommits") public boolean isCheckCommitMessageFooter() { return checkCommitMessageFooter; } @@ -203,15 +206,10 @@ public class BranchProtection implements Serializable { this.checkCommitMessageFooter = checkCommitMessageFooter; } - @SuppressWarnings("unused") - private static boolean isCheckCommitMessageFooterEnabled() { - return (boolean) EditContext.get().getInputValue("checkCommitMessageFooter"); - } - @Editable(order=393, description = "A " + "Java regular expression " + "to validate commit message footer") - @ShowCondition("isCheckCommitMessageFooterEnabled") + @DependsOn(property="checkCommitMessageFooter") @NotEmpty public String getCommitMessageFooterPattern() { return commitMessageFooterPattern; @@ -223,7 +221,7 @@ public class BranchProtection implements Serializable { @Editable(order=394, description = "Optionally specify applicable commit types for commit message footer check (hit ENTER to add value). " + "Leave empty to all types") - @ShowCondition("isCheckCommitMessageFooterEnabled") + @DependsOn(property="checkCommitMessageFooter") public List getCommitTypesForFooterCheck() { return commitTypesForFooterCheck; } diff --git a/server-core/src/main/java/io/onedev/server/model/support/issue/TimeTrackingSetting.java b/server-core/src/main/java/io/onedev/server/model/support/issue/TimeTrackingSetting.java index ea17e7414d..11c0434cbd 100644 --- a/server-core/src/main/java/io/onedev/server/model/support/issue/TimeTrackingSetting.java +++ b/server-core/src/main/java/io/onedev/server/model/support/issue/TimeTrackingSetting.java @@ -18,10 +18,9 @@ import org.apache.commons.lang3.StringUtils; import io.onedev.server.OneDev; import io.onedev.server.annotation.ChoiceProvider; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; -import io.onedev.server.annotation.ShowCondition; import io.onedev.server.entitymanager.LinkSpecManager; -import io.onedev.server.util.EditContext; import io.onedev.server.util.usage.Usage; @Editable @@ -51,15 +50,10 @@ public class TimeTrackingSetting implements Serializable { this.useHoursAndMinutesOnly = useHoursAndMinutesOnly; } - @SuppressWarnings("unused") - private static boolean isUseHoursAndMinutesOnlyDisabled() { - return !(Boolean)EditContext.get().getInputValue("useHoursAndMinutesOnly"); - } - @Editable(order=100, description = "Specify working hours per day. This will affect " + "parsing and displaying of working periods. For instance 1d is the " + "same as 8h if this property is set to 8") - @ShowCondition("isUseHoursAndMinutesOnlyDisabled") + @DependsOn(property="useHoursAndMinutesOnly", value="false") @Max(24) @Min(1) public int getHoursPerDay() { @@ -73,7 +67,7 @@ public class TimeTrackingSetting implements Serializable { @Editable(order=200, description = "Specify working days per week. This will affect " + "parsing and displaying of working periods. For instance 1w is the " + "same as 5d if this property is set to 5") - @ShowCondition("isUseHoursAndMinutesOnlyDisabled") + @DependsOn(property="useHoursAndMinutesOnly", value="false") @Max(7) @Min(1) public int getDaysPerWeek() { diff --git a/server-core/src/main/java/io/onedev/server/model/support/issue/field/spec/FieldSpec.java b/server-core/src/main/java/io/onedev/server/model/support/issue/field/spec/FieldSpec.java index f428999e70..47ffede5ca 100644 --- a/server-core/src/main/java/io/onedev/server/model/support/issue/field/spec/FieldSpec.java +++ b/server-core/src/main/java/io/onedev/server/model/support/issue/field/spec/FieldSpec.java @@ -14,6 +14,7 @@ import org.apache.wicket.MarkupContainer; import io.onedev.commons.codeassist.InputSuggestion; import io.onedev.commons.utils.match.PathMatcher; import io.onedev.server.OneDev; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; import io.onedev.server.annotation.FieldName; import io.onedev.server.annotation.Multiline; @@ -113,7 +114,7 @@ public abstract class FieldSpec extends InputSpec { } @Editable(order=60) - @io.onedev.server.annotation.ShowCondition("isNameOfEmptyValueVisible") + @DependsOn(property="allowEmpty") @NotEmpty public String getNameOfEmptyValue() { return nameOfEmptyValue; @@ -123,11 +124,6 @@ public abstract class FieldSpec extends InputSpec { this.nameOfEmptyValue = nameOfEmptyValue; } - @SuppressWarnings("unused") - private static boolean isNameOfEmptyValueVisible() { - return (boolean) EditContext.get().getInputValue("allowEmpty"); - } - @Editable(order=10000, name="Include When Issue is Opened", description="Whether or not to include this field when issue is initially opened. " + "If not, you may include this field later when issue is transited to other states via issue transition rule") public boolean isPromptUponIssueOpen() { @@ -138,16 +134,11 @@ public abstract class FieldSpec extends InputSpec { this.promptUponIssueOpen = promptUponIssueOpen; } - @SuppressWarnings("unused") - private static boolean isPromptUponIssueOpenEnabled() { - return Boolean.TRUE.equals(EditContext.get().getInputValue("promptUponIssueOpen")); - } - @Editable(order=10100, placeholder="All projects", description="Specify applicable projects for above option. " + "Multiple projects should be separated by space. Use '**', '*' or '?' for " + "path wildcard match. " + "Prefix with '-' to exclude. Leave empty for all projects") - @io.onedev.server.annotation.ShowCondition("isPromptUponIssueOpenEnabled") + @DependsOn(property="promptUponIssueOpen") @Patterns(suggester="suggestProjects", path=true) public String getApplicableProjects() { return applicableProjects; diff --git a/server-core/src/main/java/io/onedev/server/model/support/issue/field/spec/choicefield/ChoiceField.java b/server-core/src/main/java/io/onedev/server/model/support/issue/field/spec/choicefield/ChoiceField.java index 5900be7ad2..6b2ff104c9 100644 --- a/server-core/src/main/java/io/onedev/server/model/support/issue/field/spec/choicefield/ChoiceField.java +++ b/server-core/src/main/java/io/onedev/server/model/support/issue/field/spec/choicefield/ChoiceField.java @@ -7,16 +7,15 @@ import java.util.Map; import javax.validation.Valid; import javax.validation.constraints.NotNull; +import io.onedev.server.annotation.DependsOn; +import io.onedev.server.annotation.Editable; import io.onedev.server.buildspecmodel.inputspec.choiceinput.ChoiceInput; import io.onedev.server.buildspecmodel.inputspec.choiceinput.choiceprovider.ChoiceProvider; import io.onedev.server.buildspecmodel.inputspec.choiceinput.choiceprovider.SpecifiedChoices; import io.onedev.server.model.support.issue.field.spec.FieldSpec; import io.onedev.server.model.support.issue.field.spec.choicefield.defaultmultivalueprovider.DefaultMultiValueProvider; import io.onedev.server.model.support.issue.field.spec.choicefield.defaultvalueprovider.DefaultValueProvider; -import io.onedev.server.util.EditContext; import io.onedev.server.util.usage.Usage; -import io.onedev.server.annotation.Editable; -import io.onedev.server.annotation.ShowCondition; @Editable(order=145, name= FieldSpec.ENUMERATION) public class ChoiceField extends FieldSpec { @@ -40,7 +39,7 @@ public class ChoiceField extends FieldSpec { this.choiceProvider = choiceProvider; } - @ShowCondition("isDefaultValueProviderVisible") + @DependsOn(property="allowMultiple", value="false") @Editable(order=1100, name="Default Value", placeholder="No default value") @Valid public DefaultValueProvider getDefaultValueProvider() { @@ -51,12 +50,7 @@ public class ChoiceField extends FieldSpec { this.defaultValueProvider = defaultValueProvider; } - @SuppressWarnings("unused") - private static boolean isDefaultValueProviderVisible() { - return EditContext.get().getInputValue("allowMultiple").equals(false); - } - - @ShowCondition("isDefaultMultiValueProviderVisible") + @DependsOn(property="allowMultiple") @Editable(order=1100, name="Default Value", placeholder="No default value") @Valid public DefaultMultiValueProvider getDefaultMultiValueProvider() { @@ -67,11 +61,6 @@ public class ChoiceField extends FieldSpec { this.defaultMultiValueProvider = defaultMultiValueProvider; } - @SuppressWarnings("unused") - private static boolean isDefaultMultiValueProviderVisible() { - return EditContext.get().getInputValue("allowMultiple").equals(true); - } - @Override public List getPossibleValues() { return ChoiceInput.getPossibleValues(choiceProvider); diff --git a/server-core/src/main/java/io/onedev/server/model/support/issue/field/spec/userchoicefield/UserChoiceField.java b/server-core/src/main/java/io/onedev/server/model/support/issue/field/spec/userchoicefield/UserChoiceField.java index fc20ee7d45..7dbf3e8a43 100644 --- a/server-core/src/main/java/io/onedev/server/model/support/issue/field/spec/userchoicefield/UserChoiceField.java +++ b/server-core/src/main/java/io/onedev/server/model/support/issue/field/spec/userchoicefield/UserChoiceField.java @@ -1,25 +1,23 @@ package io.onedev.server.model.support.issue.field.spec.userchoicefield; -import io.onedev.server.OneDev; +import java.util.List; +import java.util.Map; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; -import io.onedev.server.annotation.ShowCondition; import io.onedev.server.buildspecmodel.inputspec.userchoiceinput.UserChoiceInput; import io.onedev.server.buildspecmodel.inputspec.userchoiceinput.choiceprovider.AllUsers; import io.onedev.server.buildspecmodel.inputspec.userchoiceinput.choiceprovider.ChoiceProvider; -import io.onedev.server.SubscriptionManager; import io.onedev.server.model.support.issue.field.spec.FieldSpec; import io.onedev.server.model.support.issue.field.spec.userchoicefield.defaultmultivalueprovider.DefaultMultiValueProvider; import io.onedev.server.model.support.issue.field.spec.userchoicefield.defaultmultivalueprovider.SpecifiedDefaultMultiValue; import io.onedev.server.model.support.issue.field.spec.userchoicefield.defaultvalueprovider.DefaultValueProvider; import io.onedev.server.model.support.issue.field.spec.userchoicefield.defaultvalueprovider.SpecifiedDefaultValue; -import io.onedev.server.util.EditContext; import io.onedev.server.util.usage.Usage; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import java.util.List; -import java.util.Map; - @Editable(order=150, name= FieldSpec.USER) public class UserChoiceField extends FieldSpec { @@ -43,7 +41,7 @@ public class UserChoiceField extends FieldSpec { } @Editable(order=1100, name="Default Value", placeholder="No default value") - @ShowCondition("isDefaultValueProviderVisible") + @DependsOn(property="allowMultiple", value="false") @Valid public DefaultValueProvider getDefaultValueProvider() { return defaultValueProvider; @@ -53,13 +51,8 @@ public class UserChoiceField extends FieldSpec { this.defaultValueProvider = defaultValueProvider; } - @SuppressWarnings("unused") - private static boolean isDefaultValueProviderVisible() { - return EditContext.get().getInputValue("allowMultiple").equals(false); - } - - @ShowCondition("isDefaultMultiValueProviderVisible") @Editable(order=1100, name="Default Value", placeholder="No default value") + @DependsOn(property="allowMultiple") @Valid public DefaultMultiValueProvider getDefaultMultiValueProvider() { return defaultMultiValueProvider; @@ -69,16 +62,6 @@ public class UserChoiceField extends FieldSpec { this.defaultMultiValueProvider = defaultMultiValueProvider; } - @SuppressWarnings("unused") - private static boolean isDefaultMultiValueProviderVisible() { - return EditContext.get().getInputValue("allowMultiple").equals(true); - } - - @SuppressWarnings("unused") - private static boolean isSubscriptionActive() { - return OneDev.getInstance(SubscriptionManager.class).isSubscriptionActive(); - } - @Override public List getPossibleValues() { return UserChoiceInput.getPossibleValues(); diff --git a/server-core/src/main/java/io/onedev/server/model/support/role/JobPrivilege.java b/server-core/src/main/java/io/onedev/server/model/support/role/JobPrivilege.java index d53f7cf84c..038b122d34 100644 --- a/server-core/src/main/java/io/onedev/server/model/support/role/JobPrivilege.java +++ b/server-core/src/main/java/io/onedev/server/model/support/role/JobPrivilege.java @@ -4,17 +4,16 @@ import edu.emory.mathcs.backport.java.util.Collections; import io.onedev.commons.codeassist.InputSuggestion; import io.onedev.server.OneDev; import io.onedev.server.annotation.Editable; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Patterns; -import io.onedev.server.annotation.ShowCondition; import io.onedev.server.entitymanager.BuildManager; -import io.onedev.server.util.EditContext; import io.onedev.server.web.util.SuggestionUtils; import javax.annotation.Nullable; import javax.validation.constraints.NotEmpty; import java.io.Serializable; import java.util.ArrayList; -import java.util.List; +import java.util.List; @Editable public class JobPrivilege implements Serializable { @@ -63,14 +62,9 @@ public class JobPrivilege implements Serializable { this.manageJob = manageJob; } - @SuppressWarnings("unused") - private static boolean isManageJobDisabled() { - return !(boolean) EditContext.get().getInputValue("manageJob"); - } - @Editable(order=200, description="The permission to run job manually. It also implies the permission " + "to access build log, build pipeline and all published reports") - @ShowCondition("isManageJobDisabled") + @DependsOn(property="manageJob", value="false") public boolean isRunJob() { return runJob; } @@ -79,13 +73,8 @@ public class JobPrivilege implements Serializable { this.runJob = runJob; } - @SuppressWarnings("unused") - private static boolean isRunJobDisabled() { - return !(boolean) EditContext.get().getInputValue("runJob"); - } - @Editable(order=300, name="Access Build Log", description="The permission to access build log") - @ShowCondition("isRunJobDisabled") + @DependsOn(property="runJob", value="false") public boolean isAccessLog() { return accessLog; } @@ -95,7 +84,7 @@ public class JobPrivilege implements Serializable { } @Editable(order=350, name="Access Build Pipeline", description="The permission to access build pipeline") - @ShowCondition("isRunJobDisabled") + @DependsOn(property="runJob", value="false") public boolean isAccessPipeline() { return accessPipeline; } @@ -106,7 +95,7 @@ public class JobPrivilege implements Serializable { @Editable(order=400, name="Access Build Reports", placeholder="No accessible reports", description="Optionally specify space-separated reports. " + "Use '*' or '?' for wildcard match. Prefix with '-' to exclude") - @ShowCondition("isRunJobDisabled") + @DependsOn(property="runJob", value="false") @Patterns @Nullable public String getAccessibleReports() { diff --git a/server-core/src/main/java/io/onedev/server/ai/McpHelperResource.java b/server-core/src/main/java/io/onedev/server/rest/resource/McpHelperResource.java similarity index 97% rename from server-core/src/main/java/io/onedev/server/ai/McpHelperResource.java rename to server-core/src/main/java/io/onedev/server/rest/resource/McpHelperResource.java index b4e4573d0d..e268954146 100644 --- a/server-core/src/main/java/io/onedev/server/ai/McpHelperResource.java +++ b/server-core/src/main/java/io/onedev/server/rest/resource/McpHelperResource.java @@ -1,6 +1,7 @@ -package io.onedev.server.ai; +package io.onedev.server.rest.resource; import java.io.Serializable; +import java.nio.charset.StandardCharsets; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; @@ -18,6 +19,7 @@ import javax.inject.Inject; import javax.inject.Singleton; import javax.persistence.EntityNotFoundException; import javax.validation.Valid; +import javax.validation.ValidationException; import javax.validation.constraints.NotNull; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -40,6 +42,8 @@ import com.google.common.base.Splitter; import io.onedev.commons.utils.StringUtils; import io.onedev.server.SubscriptionManager; +import io.onedev.server.buildspec.BuildSpec; +import io.onedev.server.data.migration.VersionedYamlDoc; import io.onedev.server.entitymanager.BuildManager; import io.onedev.server.entitymanager.BuildParamManager; import io.onedev.server.entitymanager.IssueChangeManager; @@ -454,10 +458,8 @@ public class McpHelperResource { private Project getProject(String projectPath) { var project = projectManager.findByPath(projectPath); - if (project == null) - throw new NotFoundException("Project not found: " + projectPath); - if (!SecurityUtils.canAccessProject(project)) - throw new UnauthorizedException("Unable to access project: " + projectPath); + if (project == null || !SecurityUtils.canAccessProject(project)) + throw new NotFoundException("Project not found or inaccessible: " + projectPath); return project; } @@ -1331,7 +1333,6 @@ public class McpHelperResource { pullRequestMap.put("status", PullRequest.Status.OPEN.name() + " (ready to merge)"); } pullRequestMap.remove("uuid"); - pullRequestMap.remove("baseCommitHash"); pullRequestMap.remove("buildCommitHash"); pullRequestMap.remove("submitTimeGroups"); pullRequestMap.remove("closeTimeGroups"); @@ -1439,10 +1440,10 @@ public class McpHelperResource { return buildMap; } - - @Path("/get-previous-successful-build") + + @Path("/get-previous-successful-similar-build") @GET - public Map getPreviousSuccessfulBuild( + public Map getPreviousSuccessfulSimilarBuild( @QueryParam("currentProject") @NotNull String currentProjectPath, @QueryParam("reference") @NotNull String buildReference) { if (SecurityUtils.getAuthUser() == null) @@ -1452,18 +1453,30 @@ public class McpHelperResource { var build = getBuild(currentProject, buildReference); - var previousSuccessfulBuild = buildManager.findStreamPrevious(build, Build.Status.SUCCESSFUL); - if (previousSuccessfulBuild != null) { - var buildMap = getBuildMap(currentProject, previousSuccessfulBuild); - buildMap.put("params", previousSuccessfulBuild.getParamMap()); - buildMap.put("labels", previousSuccessfulBuild.getLabels().stream().map(it->it.getSpec().getName()).collect(Collectors.toList())); - buildMap.put("link", urlManager.urlFor(previousSuccessfulBuild, true)); + var foundBuild = buildManager.findPreviousSuccessfulSimilar(build); + if (foundBuild != null) { + var buildMap = getBuildMap(currentProject, foundBuild); + buildMap.put("params", foundBuild.getParamMap()); + buildMap.put("labels", foundBuild.getLabels().stream().map(it->it.getSpec().getName()).collect(Collectors.toList())); + buildMap.put("link", urlManager.urlFor(foundBuild, true)); return buildMap; } else { - throw new NotFoundException("Previous successful build not found"); + throw new NotFoundException("Previous successful similar build not found"); } } + @Path("/migrate-build-spec") + @POST + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.TEXT_PLAIN) + public String migrateBuildSpec(@NotNull String buildSpecString) { + if (SecurityUtils.getAuthUser() == null) + throw new UnauthenticatedException(); + + var buildSpec = BuildSpec.parse(buildSpecString.getBytes(StandardCharsets.UTF_8)); + return VersionedYamlDoc.fromBean(buildSpec).toYaml(); + } + @Path("/get-pull-request") @GET public Map getPullRequest( @@ -1489,6 +1502,11 @@ public class McpHelperResource { reviews.add(reviewMap); } pullRequestMap.put("reviews", reviews); + var builds = new ArrayList(); + for (var build : pullRequest.getBuilds()) { + builds.add(build.getReference().toString(currentProject) + " (job: " + build.getJobName() + ", status: " + build.getStatus() + ")"); + } + pullRequestMap.put("builds", builds); pullRequestMap.put("labels", pullRequest.getLabels().stream().map(it->it.getSpec().getName()).collect(Collectors.toList())); pullRequestMap.put("link", urlManager.urlFor(pullRequest, true)); @@ -2092,11 +2110,16 @@ public class McpHelperResource { if (reason == null) throw new NotAcceptableException("Reason is required"); - Build build = jobManager.submit(project, ObjectId.fromString(commitHash), jobName, - params, refName, SecurityUtils.getUser(), null, - null, reason); - if (build.isFinished()) - jobManager.resubmit(build, reason); + Build build; + try { + build = jobManager.submit(project, ObjectId.fromString(commitHash), jobName, + params, refName, SecurityUtils.getUser(), null, + null, reason); + if (build.isFinished()) + jobManager.resubmit(build, reason); + } catch (ValidationException e) { + throw new NotAcceptableException(e.getMessage()); + } var buildMap = getBuildMap(projectInfo.currentProject, build); buildMap.put("id", build.getId()); diff --git a/server-core/src/main/java/io/onedev/server/web/component/issue/workflowreconcile/UndefinedFieldResolution.java b/server-core/src/main/java/io/onedev/server/web/component/issue/workflowreconcile/UndefinedFieldResolution.java index 9f0e7aa89e..3aa1b443d7 100644 --- a/server-core/src/main/java/io/onedev/server/web/component/issue/workflowreconcile/UndefinedFieldResolution.java +++ b/server-core/src/main/java/io/onedev/server/web/component/issue/workflowreconcile/UndefinedFieldResolution.java @@ -4,18 +4,16 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; -import javax.validation.constraints.NotEmpty; - import io.onedev.server.OneDev; -import io.onedev.server.entitymanager.SettingManager; -import io.onedev.server.model.support.issue.field.spec.FieldSpec; -import io.onedev.server.util.EditContext; import io.onedev.server.annotation.ChoiceProvider; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; import io.onedev.server.annotation.OmitName; -import io.onedev.server.annotation.ShowCondition; +import io.onedev.server.entitymanager.SettingManager; +import io.onedev.server.model.support.issue.field.spec.FieldSpec; @Editable public class UndefinedFieldResolution implements Serializable { @@ -41,7 +39,7 @@ public class UndefinedFieldResolution implements Serializable { @Editable(order=100, name="new field") @ChoiceProvider("getFieldChoices") - @ShowCondition("isNewFieldVisible") + @DependsOn(property="fixType", value="CHANGE_TO_ANOTHER_FIELD") @NotEmpty @OmitName public String getNewField() { @@ -51,11 +49,6 @@ public class UndefinedFieldResolution implements Serializable { public void setNewField(String newField) { this.newField = newField; } - - @SuppressWarnings("unused") - private static boolean isNewFieldVisible() { - return EditContext.get().getInputValue("fixType") == FixType.CHANGE_TO_ANOTHER_FIELD; - } @SuppressWarnings("unused") private static List getFieldChoices() { diff --git a/server-core/src/main/java/io/onedev/server/web/component/issue/workflowreconcile/UndefinedFieldValueResolution.java b/server-core/src/main/java/io/onedev/server/web/component/issue/workflowreconcile/UndefinedFieldValueResolution.java index febb0fd0e9..9fd9b4a759 100644 --- a/server-core/src/main/java/io/onedev/server/web/component/issue/workflowreconcile/UndefinedFieldValueResolution.java +++ b/server-core/src/main/java/io/onedev/server/web/component/issue/workflowreconcile/UndefinedFieldValueResolution.java @@ -4,24 +4,22 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; -import javax.validation.constraints.NotNull; - import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; import com.google.common.base.Preconditions; import io.onedev.server.OneDev; -import io.onedev.server.entitymanager.SettingManager; -import io.onedev.server.model.support.administration.GlobalIssueSetting; -import io.onedev.server.model.support.issue.field.spec.choicefield.ChoiceField; -import io.onedev.server.model.support.issue.field.spec.FieldSpec; -import io.onedev.server.util.ComponentContext; -import io.onedev.server.util.EditContext; -import io.onedev.server.web.component.issue.workflowreconcile.WorkflowReconcilePanel.UndefinedFieldValueContainer; import io.onedev.server.annotation.ChoiceProvider; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; import io.onedev.server.annotation.OmitName; -import io.onedev.server.annotation.ShowCondition; +import io.onedev.server.entitymanager.SettingManager; +import io.onedev.server.model.support.administration.GlobalIssueSetting; +import io.onedev.server.model.support.issue.field.spec.FieldSpec; +import io.onedev.server.model.support.issue.field.spec.choicefield.ChoiceField; +import io.onedev.server.util.ComponentContext; +import io.onedev.server.web.component.issue.workflowreconcile.WorkflowReconcilePanel.UndefinedFieldValueContainer; @Editable public class UndefinedFieldValueResolution implements Serializable { @@ -47,7 +45,7 @@ public class UndefinedFieldValueResolution implements Serializable { @Editable(order=100) @ChoiceProvider("getValueChoices") - @ShowCondition("isNewValueVisible") + @DependsOn(property="fixType", value="CHANGE_TO_ANOTHER_VALUE") @OmitName @NotEmpty public String getNewValue() { @@ -58,11 +56,6 @@ public class UndefinedFieldValueResolution implements Serializable { this.newValue = newValue; } - @SuppressWarnings("unused") - private static boolean isNewValueVisible() { - return EditContext.get().getInputValue("fixType") == FixType.CHANGE_TO_ANOTHER_VALUE; - } - @SuppressWarnings("unused") private static List getValueChoices() { UndefinedFieldValueContainer container = ComponentContext.get().getComponent() diff --git a/server-core/src/main/java/io/onedev/server/web/component/issue/workflowreconcile/UndefinedStateResolution.java b/server-core/src/main/java/io/onedev/server/web/component/issue/workflowreconcile/UndefinedStateResolution.java index c4875f31fc..c8fa2d4259 100644 --- a/server-core/src/main/java/io/onedev/server/web/component/issue/workflowreconcile/UndefinedStateResolution.java +++ b/server-core/src/main/java/io/onedev/server/web/component/issue/workflowreconcile/UndefinedStateResolution.java @@ -4,18 +4,16 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; -import javax.validation.constraints.NotEmpty; - import io.onedev.server.OneDev; -import io.onedev.server.entitymanager.SettingManager; -import io.onedev.server.model.support.administration.GlobalIssueSetting; -import io.onedev.server.util.EditContext; import io.onedev.server.annotation.ChoiceProvider; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; import io.onedev.server.annotation.OmitName; -import io.onedev.server.annotation.ShowCondition; +import io.onedev.server.entitymanager.SettingManager; +import io.onedev.server.model.support.administration.GlobalIssueSetting; @Editable public class UndefinedStateResolution implements Serializable { @@ -41,7 +39,7 @@ public class UndefinedStateResolution implements Serializable { @Editable(order=100) @ChoiceProvider("getStateChoices") - @ShowCondition("isNewStateVisible") + @DependsOn(property="fixType", value="CHANGE_TO_ANOTHER_STATE") @OmitName @NotEmpty public String getNewState() { @@ -51,12 +49,7 @@ public class UndefinedStateResolution implements Serializable { public void setNewState(String newState) { this.newState = newState; } - - @SuppressWarnings("unused") - private static boolean isNewStateVisible() { - return EditContext.get().getInputValue("fixType") == FixType.CHANGE_TO_ANOTHER_STATE; - } - + @SuppressWarnings("unused") private static List getStateChoices() { GlobalIssueSetting issueSetting = OneDev.getInstance(SettingManager.class).getIssueSetting(); diff --git a/server-core/src/main/java/io/onedev/server/web/component/user/accesstoken/AccessTokenEditBean.java b/server-core/src/main/java/io/onedev/server/web/component/user/accesstoken/AccessTokenEditBean.java index bdde653436..4488fd31dd 100644 --- a/server-core/src/main/java/io/onedev/server/web/component/user/accesstoken/AccessTokenEditBean.java +++ b/server-core/src/main/java/io/onedev/server/web/component/user/accesstoken/AccessTokenEditBean.java @@ -11,15 +11,14 @@ import java.util.stream.Collectors; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.Size; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; import io.onedev.server.annotation.Secret; -import io.onedev.server.annotation.ShowCondition; import io.onedev.server.model.AccessToken; import io.onedev.server.model.AccessTokenAuthorization; import io.onedev.server.model.Project; import io.onedev.server.model.Role; import io.onedev.server.security.SecurityUtils; -import io.onedev.server.util.EditContext; @Editable public class AccessTokenEditBean implements Serializable { @@ -68,7 +67,7 @@ public class AccessTokenEditBean implements Serializable { @Editable(order=300, name="Authorized Projects", description = "Only projects manageable by access token owner can be authorized") @Size(min=1, message = "At least one project should be authorized") - @ShowCondition("isHasOwnerPermissionsDisabled") + @DependsOn(property="hasOwnerPermissions", value="false") public List getAuthorizations() { return authorizations; } @@ -77,11 +76,6 @@ public class AccessTokenEditBean implements Serializable { this.authorizations = authorizations; } - @SuppressWarnings("unused") - private static boolean isHasOwnerPermissionsDisabled() { - return !(boolean) EditContext.get().getInputValue("hasOwnerPermissions"); - } - @Editable(order=400, placeholder = "Never expire") public Date getExpireDate() { return expireDate; diff --git a/server-core/src/main/java/io/onedev/server/web/editable/PropertyDescriptor.java b/server-core/src/main/java/io/onedev/server/web/editable/PropertyDescriptor.java index 1261e34722..803e405c30 100644 --- a/server-core/src/main/java/io/onedev/server/web/editable/PropertyDescriptor.java +++ b/server-core/src/main/java/io/onedev/server/web/editable/PropertyDescriptor.java @@ -15,10 +15,13 @@ import javax.validation.constraints.Size; import com.google.common.collect.Sets; +import io.onedev.commons.utils.ExplicitException; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.ShowCondition; import io.onedev.server.annotation.SubscriptionRequired; import io.onedev.server.util.BeanUtils; import io.onedev.server.util.ComponentContext; +import io.onedev.server.util.EditContext; import io.onedev.server.util.ReflectionUtils; public class PropertyDescriptor implements Serializable { @@ -166,6 +169,35 @@ public class PropertyDescriptor implements Serializable { ShowCondition showCondition = getPropertyGetter().getAnnotation(ShowCondition.class); if (showCondition != null && !(boolean)ReflectionUtils.invokeStaticMethod(getBeanClass(), showCondition.value())) return false; + DependsOn dependsOn = getPropertyGetter().getAnnotation(DependsOn.class); + if (dependsOn != null) { + var dependencyProperty = beanDescriptor.getProperty(dependsOn.property()); + if (dependencyProperty == null) { + throw new ExplicitException("Dependency property not found: " + dependsOn.property()); + } + var dependencyPropertyValue = EditContext.get().getInputValue(dependsOn.property()); + if (dependsOn.value().length() != 0) { + if (dependencyPropertyValue != null && dependencyPropertyValue.toString().equals(dependsOn.value())) { + if (dependsOn.inverse()) + return false; + } else if (!dependsOn.inverse()) { + return false; + } + } else { + if (dependencyProperty.getPropertyClass() == boolean.class) { + boolean requiredPropertyValue = !dependsOn.inverse(); + if (requiredPropertyValue != (boolean)dependencyPropertyValue) + return false; + } else if (dependencyProperty.getPropertyClass() == int.class || dependencyProperty.getPropertyClass() == long.class || dependencyProperty.getPropertyClass() == double.class || dependencyProperty.getPropertyClass() == float.class) { + int dependencyPropertyIntValue = (int) dependencyPropertyValue; + if (dependsOn.inverse() && dependencyPropertyIntValue != 0 || !dependsOn.inverse() && dependencyPropertyIntValue == 0) + return false; + } else { + if (dependsOn.inverse() && dependencyPropertyValue != null || !dependsOn.inverse() && dependencyPropertyValue == null) + return false; + } + } + } getDependencyPropertyNames().remove(getPropertyName()); for (String dependencyPropertyName: getDependencyPropertyNames()) { Set copyOfCheckedPropertyNames = new HashSet<>(checkedPropertyNames); diff --git a/server-core/src/main/java/io/onedev/server/web/editable/buildspec/job/postbuildaction/PostBuildActionEditPanel.html b/server-core/src/main/java/io/onedev/server/web/editable/buildspec/job/postbuildaction/PostBuildActionEditPanel.html index 32f006ca88..ef7ab8f77d 100644 --- a/server-core/src/main/java/io/onedev/server/web/editable/buildspec/job/postbuildaction/PostBuildActionEditPanel.html +++ b/server-core/src/main/java/io/onedev/server/web/editable/buildspec/job/postbuildaction/PostBuildActionEditPanel.html @@ -1,7 +1,7 @@
\ No newline at end of file diff --git a/server-core/src/main/java/io/onedev/server/web/page/admin/brandingsetting/BrandSettingEditBean.java b/server-core/src/main/java/io/onedev/server/web/page/admin/brandingsetting/BrandSettingEditBean.java index d1b6ecb889..ffd92d27d6 100644 --- a/server-core/src/main/java/io/onedev/server/web/page/admin/brandingsetting/BrandSettingEditBean.java +++ b/server-core/src/main/java/io/onedev/server/web/page/admin/brandingsetting/BrandSettingEditBean.java @@ -1,21 +1,17 @@ package io.onedev.server.web.page.admin.brandingsetting; +import java.io.Serializable; + +import javax.validation.constraints.NotEmpty; + import io.onedev.server.annotation.Editable; import io.onedev.server.annotation.Image; -import io.onedev.server.annotation.ShowCondition; -import io.onedev.server.model.support.administration.BrandingSetting; -import io.onedev.server.util.EditContext; - -import javax.validation.constraints.NotEmpty; -import java.io.Serializable; @Editable public class BrandSettingEditBean implements Serializable { private String name; - - private String url; - + private String logoData; private String darkLogoData; @@ -29,23 +25,7 @@ public class BrandSettingEditBean implements Serializable { public void setName(String name) { this.name = name; } - - @SuppressWarnings("unused") - private static boolean isOEM() { - return BrandingSetting.isOEM((String) EditContext.get().getInputValue("name")); - } - - @Editable(order=150, description = "Specify url for your brand") - @ShowCondition("isOEM") - @NotEmpty - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - + @Editable(order=200, name="Logo for Light Mode", description = "Upload a 128x128 transparent png file to be used " + "as logo for light mode") @Image(accept = "image/png") diff --git a/server-core/src/main/java/io/onedev/server/web/page/admin/brandingsetting/BrandingSettingPage.java b/server-core/src/main/java/io/onedev/server/web/page/admin/brandingsetting/BrandingSettingPage.java index 37e1430970..c93ab27e48 100644 --- a/server-core/src/main/java/io/onedev/server/web/page/admin/brandingsetting/BrandingSettingPage.java +++ b/server-core/src/main/java/io/onedev/server/web/page/admin/brandingsetting/BrandingSettingPage.java @@ -23,7 +23,6 @@ import io.onedev.server.OneDev; import io.onedev.server.cluster.ClusterManager; import io.onedev.server.cluster.ClusterTask; import io.onedev.server.entitymanager.SettingManager; -import io.onedev.server.model.support.administration.BrandingSetting; import io.onedev.server.web.editable.BeanContext; import io.onedev.server.web.img.ImageScope; import io.onedev.server.web.page.admin.AdministrationPage; @@ -77,7 +76,6 @@ public class BrandingSettingPage extends AdministrationPage { var setting = getSettingManager().getBrandingSetting(); var bean = new BrandSettingEditBean(); bean.setName(setting.getName()); - bean.setUrl(setting.getUrl()); bean.setLogoData(getLogoData(false)); bean.setDarkLogoData(getLogoData(true)); @@ -86,7 +84,6 @@ public class BrandingSettingPage extends AdministrationPage { protected void onSubmit() { super.onSubmit(); setting.setName(bean.getName()); - setting.setUrl(bean.getUrl()); getSettingManager().saveBrandingSetting(setting); getAuditManager().audit(null, "changed branding settings", null, null); if (!bean.getLogoData().equals(getDefaultLogoData(false))) { @@ -106,8 +103,7 @@ public class BrandingSettingPage extends AdministrationPage { @Override public void onClick() { - setting.setName(BrandingSetting.DEFAULT_NAME); - setting.setUrl(BrandingSetting.DEFAULT_URL); + setting.setName("OneDev"); getSettingManager().saveBrandingSetting(setting); getAuditManager().audit(null, "changed branding settings", null, null); getClusterManager().runOnAllServers(new UpdateLogoTask(null, false)); @@ -119,7 +115,7 @@ public class BrandingSettingPage extends AdministrationPage { @Override protected void onConfigure() { super.onConfigure(); - setVisible(!setting.getName().equals(BrandingSetting.DEFAULT_NAME) + setVisible(!setting.getName().equals("OneDev") || getCustomLogoFile(false).exists() || getCustomLogoFile(true).exists()); } diff --git a/server-core/src/main/java/io/onedev/server/web/page/layout/LayoutPage.java b/server-core/src/main/java/io/onedev/server/web/page/layout/LayoutPage.java index 0ab8067d46..8c778cbe80 100644 --- a/server-core/src/main/java/io/onedev/server/web/page/layout/LayoutPage.java +++ b/server-core/src/main/java/io/onedev/server/web/page/layout/LayoutPage.java @@ -69,7 +69,6 @@ import io.onedev.server.entitymanager.AlertManager; import io.onedev.server.entitymanager.SettingManager; import io.onedev.server.model.Alert; import io.onedev.server.model.User; -import io.onedev.server.model.support.administration.BrandingSetting; import io.onedev.server.persistence.dao.EntityCriteria; import io.onedev.server.security.SecurityUtils; import io.onedev.server.updatecheck.UpdateCheckManager; @@ -512,11 +511,7 @@ public abstract class LayoutPage extends BasePage { }); var version = AppLoader.getProduct().getVersion(); - var brandingSetting = getSettingManager().getBrandingSetting(); - if (brandingSetting.isOEM()) - sidebar.add(new ExternalLink("productVersion", brandingSetting.getUrl(), brandingSetting.getName() + " " + version)); - else - sidebar.add(new ExternalLink("productVersion", BrandingSetting.DEFAULT_URL, BrandingSetting.DEFAULT_NAME + " " + version)); + sidebar.add(new ExternalLink("productVersion", "https://onedev.io", "OneDev " + version)); sidebar.add(new WebMarkupContainer("tryEE") { @Override diff --git a/server-core/src/main/java/io/onedev/server/web/page/project/blob/render/renderers/buildspec/BuildSpecEditPanel.java b/server-core/src/main/java/io/onedev/server/web/page/project/blob/render/renderers/buildspec/BuildSpecEditPanel.java index 98bd4570c2..80bd887625 100644 --- a/server-core/src/main/java/io/onedev/server/web/page/project/blob/render/renderers/buildspec/BuildSpecEditPanel.java +++ b/server-core/src/main/java/io/onedev/server/web/page/project/blob/render/renderers/buildspec/BuildSpecEditPanel.java @@ -1,36 +1,20 @@ package io.onedev.server.web.page.project.blob.render.renderers.buildspec; -import com.google.common.base.Throwables; -import io.onedev.commons.loader.AppLoader; -import io.onedev.server.OneDev; -import io.onedev.server.buildspec.*; -import io.onedev.server.buildspec.job.Job; -import io.onedev.server.buildspec.job.JobAware; -import io.onedev.server.buildspec.job.JobSuggestion; -import io.onedev.server.buildspec.param.spec.ParamSpec; -import io.onedev.server.buildspec.step.StepTemplate; -import io.onedev.server.data.migration.VersionedYamlDoc; -import io.onedev.server.model.support.build.JobProperty; -import io.onedev.server.util.CollectionUtils; -import io.onedev.server.util.Path; -import io.onedev.server.util.PathNode; -import io.onedev.server.util.PathNode.Indexed; -import io.onedev.server.util.PathNode.Named; -import io.onedev.server.util.ReflectionUtils; -import io.onedev.server.web.behavior.sortable.SortBehavior; -import io.onedev.server.web.behavior.sortable.SortPosition; -import io.onedev.server.web.component.MultilineLabel; -import io.onedev.server.web.component.floating.FloatingPanel; -import io.onedev.server.web.component.menu.MenuItem; -import io.onedev.server.web.component.menu.MenuLink; -import io.onedev.server.web.component.pipeline.JobSelectionChange; -import io.onedev.server.web.component.pipeline.PipelinePanel; -import io.onedev.server.web.component.pipeline.Sortable; -import io.onedev.server.web.editable.*; -import io.onedev.server.web.page.base.BasePage; -import io.onedev.server.web.page.project.blob.render.BlobRenderContext; -import io.onedev.server.web.page.project.blob.render.edit.EditCompleteAware; -import io.onedev.server.web.util.AjaxPayload; +import static io.onedev.server.web.page.project.blob.render.renderers.buildspec.BuildSpecRenderer.getActiveElementIndex; +import static io.onedev.server.web.page.project.blob.render.renderers.buildspec.BuildSpecRenderer.getUrlSegment; +import static io.onedev.server.web.translation.Translation._T; + +import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.annotation.Nullable; +import javax.validation.ConstraintViolation; +import javax.validation.Validator; + import org.apache.commons.lang3.SerializationUtils; import org.apache.commons.lang3.StringUtils; import org.apache.wicket.Component; @@ -58,19 +42,48 @@ import org.apache.wicket.model.Model; import org.apache.wicket.request.cycle.RequestCycle; import org.unbescape.html.HtmlEscape; -import javax.annotation.Nullable; -import javax.validation.ConstraintViolation; -import javax.validation.Validator; -import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; +import com.google.common.base.Throwables; -import static io.onedev.server.web.page.project.blob.render.renderers.buildspec.BuildSpecRenderer.getActiveElementIndex; -import static io.onedev.server.web.page.project.blob.render.renderers.buildspec.BuildSpecRenderer.getUrlSegment; -import static io.onedev.server.web.translation.Translation._T; +import io.onedev.commons.loader.AppLoader; +import io.onedev.server.OneDev; +import io.onedev.server.buildspec.BuildSpec; +import io.onedev.server.buildspec.BuildSpecAware; +import io.onedev.server.buildspec.Import; +import io.onedev.server.buildspec.NamedElement; +import io.onedev.server.buildspec.ParamSpecAware; +import io.onedev.server.buildspec.Service; +import io.onedev.server.buildspec.job.Job; +import io.onedev.server.buildspec.job.JobAware; +import io.onedev.server.buildspec.job.JobSuggestion; +import io.onedev.server.buildspec.param.spec.ParamSpec; +import io.onedev.server.buildspec.step.StepTemplate; +import io.onedev.server.data.migration.VersionedYamlDoc; +import io.onedev.server.model.support.build.JobProperty; +import io.onedev.server.util.CollectionUtils; +import io.onedev.server.util.Path; +import io.onedev.server.util.PathNode; +import io.onedev.server.util.PathNode.Indexed; +import io.onedev.server.util.PathNode.Named; +import io.onedev.server.util.ReflectionUtils; +import io.onedev.server.web.behavior.sortable.SortBehavior; +import io.onedev.server.web.behavior.sortable.SortPosition; +import io.onedev.server.web.component.MultilineLabel; +import io.onedev.server.web.component.floating.FloatingPanel; +import io.onedev.server.web.component.menu.MenuItem; +import io.onedev.server.web.component.menu.MenuLink; +import io.onedev.server.web.component.pipeline.JobSelectionChange; +import io.onedev.server.web.component.pipeline.PipelinePanel; +import io.onedev.server.web.component.pipeline.Sortable; +import io.onedev.server.web.editable.BeanDescriptor; +import io.onedev.server.web.editable.BeanEditor; +import io.onedev.server.web.editable.BeanUpdating; +import io.onedev.server.web.editable.PropertyContext; +import io.onedev.server.web.editable.PropertyEditor; +import io.onedev.server.web.editable.PropertyUpdating; +import io.onedev.server.web.page.base.BasePage; +import io.onedev.server.web.page.project.blob.render.BlobRenderContext; +import io.onedev.server.web.page.project.blob.render.edit.EditCompleteAware; +import io.onedev.server.web.util.AjaxPayload; public class BuildSpecEditPanel extends FormComponentPanel implements BuildSpecAware, EditCompleteAware { @@ -836,7 +849,7 @@ public class BuildSpecEditPanel extends FormComponentPanel implements Bu } else { setConvertedInput(getModelObject()); } - } + } private void pushState(AjaxRequestTarget target, String selection) { String position = BuildSpecRenderer.getPosition(selection); diff --git a/server-core/src/main/java/io/onedev/server/web/page/security/LoginPage.html b/server-core/src/main/java/io/onedev/server/web/page/security/LoginPage.html index 15d606ebd0..747e3001a3 100644 --- a/server-core/src/main/java/io/onedev/server/web/page/security/LoginPage.html +++ b/server-core/src/main/java/io/onedev/server/web/page/security/LoginPage.html @@ -1,6 +1,6 @@
-
Powered by
+
Powered by OneDev
diff --git a/server-core/src/main/java/io/onedev/server/web/page/security/LoginPage.java b/server-core/src/main/java/io/onedev/server/web/page/security/LoginPage.java index ab82be6220..8179c5c96b 100644 --- a/server-core/src/main/java/io/onedev/server/web/page/security/LoginPage.java +++ b/server-core/src/main/java/io/onedev/server/web/page/security/LoginPage.java @@ -37,7 +37,6 @@ import io.onedev.server.entitymanager.SsoProviderManager; import io.onedev.server.entitymanager.UserManager; import io.onedev.server.model.SsoProvider; import io.onedev.server.model.User; -import io.onedev.server.model.support.administration.BrandingSetting; import io.onedev.server.security.SecurityUtils; import io.onedev.server.security.realm.PasswordAuthenticatingRealm; import io.onedev.server.web.component.link.ViewStateAwarePageLink; @@ -189,21 +188,11 @@ public class LoginPage extends SimplePage { fragment.add(ssoButtonsView.setVisible(!ssoProviders.isEmpty())); add(fragment); - - var brandingSetting = getSettingManager().getBrandingSetting(); - if (brandingSetting.isOEM()) - add(new ExternalLink("vendor", brandingSetting.getUrl(), brandingSetting.getName())); - else - add(new ExternalLink("vendor", BrandingSetting.DEFAULT_URL, BrandingSetting.DEFAULT_NAME)); } private UserManager getUserManager() { return OneDev.getInstance(UserManager.class); } - - private SettingManager getSettingManager() { - return OneDev.getInstance(SettingManager.class); - } private void afterLogin(User user) { RememberMeManager rememberMeManager = OneDev.getInstance(RememberMeManager.class); diff --git a/server-core/src/main/java/io/onedev/server/web/translation/Translation_zh.java b/server-core/src/main/java/io/onedev/server/web/translation/Translation_zh.java index fd7d2aa023..ec5d8b136d 100644 --- a/server-core/src/main/java/io/onedev/server/web/translation/Translation_zh.java +++ b/server-core/src/main/java/io/onedev/server/web/translation/Translation_zh.java @@ -27,9 +27,10 @@ public class Translation_zh extends TranslationResourceBundle { "'image' should be translated to '图片' or '镜像' depending on context\n" + "'docker aware executor' should be translated to 'docker 相关执行器'\n" + "When used together with 'subscription', word 'active' should be translated to '有效'\n" + - "Two factor authentication should be translated to '两阶段验证'\n" + + "'two factor authentication' should be translated to '两阶段验证'\n" + "Space should be added between English words and Chinese words\n" + - "SSO provider should be translated as SSO 提供方") + "'SSO provider' should be translated as SSO 提供方\n" + + "'post build' should be translated as 构建后") public static void init(Map m) { m.clear(); m.put(" Project path can be omitted if reference from current project", "如果从当前项目引用,则可以省略项目路径"); @@ -555,7 +556,6 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Can not disable root account", "不能禁用根账户"); m.put("Can not disable yourself", "不能禁用自己"); m.put("Can not find issue board: ", "找不到工单看板:"); - m.put("Can not link to self", "不能链接到自己"); m.put("Can not move project \"{0}\" to be under itself or its descendants", "不能将项目 \"{0}\" 移动到其自身或其子项目下"); m.put("Can not perform this operation now", "当前无法执行此操作"); m.put("Can not reset password for service account or disabled user", "无法重置服务账户或禁用用户的密码"); @@ -643,6 +643,7 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Choose group...", "选择组..."); m.put("Choose groups...", "选择组..."); m.put("Choose issue...", "选择工单..."); + m.put("Choose issues...", "选择工单..."); m.put("Choose iteration...", "选择迭代..."); m.put("Choose iterations...", "选择迭代..."); m.put("Choose job...", "选择任务..."); @@ -781,6 +782,7 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Confirm password here", "在此确认密码"); m.put("Confirm your action", "确认你的操作"); m.put("Connect New Agent", "连接新代理"); + m.put("Connect with your SSO account", "使用您的 SSO 账户连接"); m.put("Contact Email", "联系邮箱"); m.put("Contact Name", "联系人"); m.put("Container Image", "容器镜像"); @@ -826,6 +828,7 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Create Merge Commit If Necessary", "仅当必要时创建合并提交"); m.put("Create New", "新建"); m.put("Create New File", "创建新文件"); + m.put("Create New User", "创建新用户"); m.put("Create Project", "创建项目"); m.put("Create Pull Request", "创建合并请求"); m.put("Create Pull Request for This Change", "为此变更创建合并请求"); @@ -928,6 +931,8 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Delete Build", "删除构建"); m.put("Delete Comment", "删除评论"); m.put("Delete Pull Request", "删除合并请求"); + m.put("Delete SSO account here to reconnect corresponding SSO subject upon next login. Note that SSO subject with verified email will be connected to user with same verified email automatically", + "在此删除 SSO 账户以便在下次登录时重新连接相应的 SSO 主题。请注意,具有已验证电子邮件的 SSO 主题将自动连接到具有相同已验证电子邮件的用户"); m.put("Delete Selected", "删除选中的"); m.put("Delete Selected Builds", "删除选定的构建"); m.put("Delete Selected Comments", "删除选中的评论"); @@ -1013,6 +1018,7 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Do you really want to cancel this build?", "您确定要取消此构建吗?"); m.put("Do you really want to change target branch to {0}?", "确定要将目标分支更改为 {0} 吗?"); m.put("Do you really want to delete \"{0}\"?", "您真的要删除 \"{0}\" 吗?"); + m.put("Do you really want to delete SSO provider \"{0}\"?", "您真的想删除 SSO 提供方 \"{0}\" 吗?"); m.put("Do you really want to delete board \"{0}\"?", "您确定要删除看板 \"{0}\" 吗?"); m.put("Do you really want to delete build #{0}?", "您确定要删除构建 #{0} 吗?"); m.put("Do you really want to delete group \"{0}\"?", "您真的要删除组 \"{0}\" 吗?"); @@ -1024,6 +1030,7 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Do you really want to delete tag {0}?", "确定要删除标签 {0} 吗?"); m.put("Do you really want to delete this GPG key?", "您确定要删除此 GPG 密钥吗?"); m.put("Do you really want to delete this SSH key?", "您确定要删除此 SSH 密钥吗?"); + m.put("Do you really want to delete this SSO account?", "您真的想删除此 SSO 账户吗?"); m.put("Do you really want to delete this access token?", "您确定要删除此访问令牌吗?"); m.put("Do you really want to delete this board?", "您确定要删除此看板吗?"); m.put("Do you really want to delete this build?", "您确定要删除此构建吗?"); @@ -1124,6 +1131,9 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Email Verification", "邮件验证"); m.put("Email Verification Template", "邮箱验证模板"); m.put("Email address", "电子邮件地址"); + m.put("Email address \"{0}\" already used by another account", "电子邮件地址 \"{0}\" 已被另一个账户使用"); + m.put("Email address \"{0}\" used by account \"{1}\"", "电子邮件地址 \"{0}\" 被账户 \"{1}\" 使用"); + m.put("Email address \"{0}\" used by disabled account \"{1}\"", "电子邮件地址 \"{0}\" 被已禁用的账户 \"{1}\" 使用"); m.put("Email address already in use: {0}", "电子邮件地址已被使用: {0}"); m.put("Email address already invited: {0}", "电子邮件地址已被邀请: {0}"); m.put("Email address already used by another user", "电子邮件地址已被另一个用户使用"); @@ -1184,6 +1194,7 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Environment variable serverUrl in above command is taken from OneDev server url specified in Administration / System Setting. Change it if necessary", "上面的命令中的环境变量 serverUrl 取自 管理 / 系统设置 中指定的 OneDev 服务器 URL。如果需要,请更改它"); m.put("Equal", "等于"); + m.put("Error authenticating user", "用户认证错误"); m.put("Error calculating commits: check log for details", "计算提交时出错:请检查日志"); m.put("Error cherry-picking to {0}: Merge conflicts detected", "cherry-pick 到 {0} 时出错:合并冲突检测到"); m.put("Error cherry-picking to {0}: {1}", "cherry-pick 到 {0} 时出错:{1}"); @@ -1245,8 +1256,10 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Export XLSX", "导出 XLSX"); m.put("Export as OCI layout", "导出为 OCI 布局"); m.put("Extend Trial Subscription", "延长试用订阅"); + m.put("External Authentication", "外部认证"); m.put("External Issue Transformers", "外部工单转换"); m.put("External Participants", "外部参与者"); + m.put("External Password Authenticator", "外部密码认证器"); m.put("External System", "外部系统"); m.put("External authenticator settings saved", "外部认证器设置已保存"); m.put("External participants do not have accounts and involve in the issue via email", "外部参与者没有账户,通过电子邮件参与工单"); @@ -1547,6 +1560,7 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Image URL should be specified", "图片 URL 应该指定"); m.put("Imap Ssl Setting", "IMAP SSL 设置"); m.put("Imap With Ssl", "IMAP 使用 SSL"); + m.put("Impersonate", "模拟"); m.put("Implicit SSL", "隐式 SSL"); m.put("Import", "导入"); m.put("Import All Projects", "导入所有项目"); @@ -1699,7 +1713,6 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Issue Votes", "工单投票"); m.put("Issue administrative permission inside a project, including batch operations over multiple issues", "工单管理权限,包括对多个工单的批量操作"); - m.put("Issue already linked", "工单已链接"); m.put("Issue count", "工单数量"); m.put("Issue in state", "工单状态"); m.put("Issue list", "工单列表"); @@ -1845,11 +1858,13 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Line: ", "行:"); m.put("Lines", "行"); m.put("Link", "链接"); + m.put("Link Existing User", "链接现有用户"); m.put("Link Spec", "链接规范"); m.put("Link Spec Opposite", "链接规范相反"); m.put("Link Text", "链接文本"); m.put("Link URL", "链接 URL"); m.put("Link URL should be specified", "链接 URL 应该指定"); + m.put("Link User Bean", "链接用户 Bean"); m.put("Linkable Issues", "可链接的工单"); m.put("Linkable Issues On the Other Side", "另一侧可链接的工单"); m.put("Links", "链接"); @@ -1996,6 +2011,7 @@ public class Translation_zh extends TranslationResourceBundle { m.put("My GPG Keys", "我的 GPG 密钥"); m.put("My Profile", "我的个人资料"); m.put("My SSH Keys", "我的 SSH 密钥"); + m.put("My SSO Accounts", "我的 SSO 账户"); m.put("Mypy Report", "Mypy 报告"); m.put("N/A", "不适用"); m.put("NPM(s)", "NPM"); @@ -2037,6 +2053,7 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Network Options", "网络选项"); m.put("Never", "从不"); m.put("Never expire", "永不过期"); + m.put("Never retry", "从不重试"); m.put("New Board", "新建看板"); m.put("New Invitation Bean", "新邀请Bean"); m.put("New Issue", "新工单"); @@ -2100,6 +2117,8 @@ public class Translation_zh extends TranslationResourceBundle { m.put("No diffs to navigate", "没有差异可导航"); m.put("No directories to skip", "无要跳过的目录"); m.put("No executors defined. Jobs will use auto-discovered executors instead", "未定义执行器。作业将使用自动发现的执行器"); + m.put("No external password authenticator", "没有外部密码认证器"); + m.put("No external password authenticator to authenticate user \"{0}\"", "没有外部密码认证器来认证用户 \"{0}\""); m.put("No fields to prompt", "无要提示的字段"); m.put("No fields to remove", "无要删除的字段"); m.put("No file attachments", "没有文件附件"); @@ -2234,6 +2253,7 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Only projects manageable by access token owner can be authorized", "只有受访问令牌所有者管理的项目才能被授权"); m.put("Only system level audit events are displayed here. To view audit events for a specific project, please visit the project audit log page", "这里只显示系统级别的审计事件。要查看特定项目的审计事件,请访问项目审计日志页面"); + m.put("Only users able to authenticate via password can be linked", "只有能够通过密码认证的用户才能被链接"); m.put("Open", "打开"); m.put("Open new pull request", "创建新的合并请求"); m.put("Open terminal of current running step", "打开当前运行步骤的终端"); @@ -2554,6 +2574,7 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Passcode", "Passcode"); m.put("Passed", "通过"); m.put("Password", "密码"); + m.put("Password Authenticator", "密码认证器"); m.put("Password Edit Bean", "密码编辑 Bean"); m.put("Password Must Contain Digit", "密码必须包含数字"); m.put("Password Must Contain Lowercase", "密码必须包含小写字母"); @@ -2569,6 +2590,7 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Password has been changed", "密码已更改"); m.put("Password has been removed", "密码已删除"); m.put("Password has been set", "密码已设置"); + m.put("Password of the user", "用户的密码"); m.put("Password or Access Token for Remote Repository", "密码或远程仓库的访问令牌"); m.put("Password reset request has been sent", "密码重置请求已发送"); m.put("Password reset url is invalid or obsolete", "密码重置URL无效或已过期"); @@ -2678,9 +2700,9 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Populate Tag Mappings", "填充标签映射"); m.put("Port", "端口"); m.put("Post", "发布"); - m.put("Post Build Action", "发布构建操作"); - m.put("Post Build Action Bean", "发布构建操作 Bean"); - m.put("Post Build Actions", "发布构建操作"); + m.put("Post Build Action", "构建后操作"); + m.put("Post Build Action Bean", "构建后操作 Bean"); + m.put("Post Build Actions", "构建后操作"); m.put("Post Url", "发布 URL"); m.put("PowerShell", "PowerShell"); m.put("Prefix Pattern", "前缀模式"); @@ -3071,6 +3093,12 @@ public class Translation_zh extends TranslationResourceBundle { m.put("SSH key deleted", "SSH 密钥已删除"); m.put("SSH settings have been saved and SSH server restarted", "SSH 设置已保存并重启 SSH 服务器"); m.put("SSL Setting", "SSL 设置"); + m.put("SSO Accounts", "SSO 账户"); + m.put("SSO Providers", "SSO 提供方"); + m.put("SSO account deleted", "SSO 账户已删除"); + m.put("SSO provider \"{0}\" deleted", "SSO 提供方 \"{0}\" 已删除"); + m.put("SSO provider created", "SSO 提供方已创建"); + m.put("SSO provider updated", "SSO 提供方已更新"); m.put("SUCCESSFUL", "成功"); m.put("Save", "保存"); m.put("Save Query", "保存查询"); @@ -3156,6 +3184,7 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Service Desk Settings", "服务台设置"); m.put("Service Locator", "服务定位器"); m.put("Service Locators", "服务定位器"); + m.put("Service account not allowed to login", "服务账户不允许登录"); m.put("Service desk setting", "服务台设置"); m.put("Service desk settings have been saved", "服务台设置已保存"); m.put("Services", "服务"); @@ -3257,6 +3286,7 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Signing Key ID", "签署密钥 ID"); m.put("Similar Issues", "相似工单"); m.put("Single Sign On", "单点登录"); + m.put("Single Sign-On", "单点登录"); m.put("Single sign on via discord.com", "通过 discord.com 单点登录"); m.put("Single sign on via twitch.tv", "通过 twitch.tv 单点登录"); m.put("Site", "站点"); @@ -3646,6 +3676,7 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Ssh Setting", "SSH 设置"); m.put("Ssl Setting", "SSL 设置"); m.put("Sso Connector", "SSO 连接器"); + m.put("Sso Provider Bean", "Sso 提供方 Bean"); m.put("Start At", "开始于"); m.put("Start Date", "开始日期"); m.put("Start Page", "起始页面"); @@ -4055,6 +4086,7 @@ public class Translation_zh extends TranslationResourceBundle { m.put("Unable to create protected tag", "无法创建受保护的标签"); m.put("Unable to diff as some line is too long.", "无法比较,因为某些行太长"); m.put("Unable to diff as the file is too large.", "无法比较,因为文件太大"); + m.put("Unable to find SSO provider: ", "无法找到 SSO 提供方:"); m.put("Unable to find agent {0}", "无法找到代理 {0}"); m.put("Unable to find build #{0} in project {1}", "在项目 {1} 中找不到构建 #{0}"); m.put("Unable to find commit to import build spec (import project: {0}, import revision: {1})", @@ -4242,6 +4274,8 @@ public class Translation_zh extends TranslationResourceBundle { m.put("When determine if the user is author/committer of a git commit, all emails listed here will be checked", "确定用户是否是 git 提交的作者/提交者时,将检查此处列出的所有电子邮件"); m.put("When evaluating this template, below variables will be available:", "使用此模板时,以下变量将可用:"); + m.put("When login via OneDev's built-in form, submitted user credentials can be checked against authenticator defined here, besides the internal database", + "通过 OneDev 的内置表单登录时,提交的用户凭据可以在此处定义的认证器以及内部数据库中进行检查"); m.put("When target branch of a pull request has new commits, merge commit of the pull request will be recalculated, and this option tells whether or not to accept pull request builds ran on previous merged commit. If enabled, you will need to re-run required builds on the new merge commit. This setting takes effect only when required builds are specified", "当合并请求的目标分支有新提交时,合并请求的合并提交将被重新计算,此选项决定是否接受在之前合并提交上运行的合并请求构建。如果启用,您需要在新的合并提交上重新运行所需的构建。此设置仅在指定了所需构建时生效"); m.put("When this work starts", "此工作开始时"); @@ -4588,39 +4622,6 @@ public class Translation_zh extends TranslationResourceBundle { m.put("{javax.validation.constraints.NotEmpty.message}", "不能为空"); m.put("{javax.validation.constraints.NotNull.message}", "不能为空"); m.put("{javax.validation.constraints.Size.message}", "至少需要指定一个值"); - m.put("Connect with your SSO account", "使用您的 SSO 账户连接"); - m.put("Create New User", "创建新用户"); - m.put("Delete SSO account here to reconnect corresponding SSO subject upon next login. Note that SSO subject with verified email will be connected to user with same verified email automatically", - "在此删除 SSO 账户以便在下次登录时重新连接相应的 SSO 主题。请注意,具有已验证电子邮件的 SSO 主题将自动连接到具有相同已验证电子邮件的用户"); - m.put("Do you really want to delete SSO provider \"{0}\"?", "您真的想删除 SSO 提供方 \"{0}\" 吗?"); - m.put("Do you really want to delete this SSO account?", "您真的想删除此 SSO 账户吗?"); - m.put("Email address \"{0}\" already used by another account", "电子邮件地址 \"{0}\" 已被另一个账户使用"); - m.put("Email address \"{0}\" used by account \"{1}\"", "电子邮件地址 \"{0}\" 被账户 \"{1}\" 使用"); - m.put("Email address \"{0}\" used by disabled account \"{1}\"", "电子邮件地址 \"{0}\" 被已禁用的账户 \"{1}\" 使用"); - m.put("Error authenticating user", "用户认证错误"); - m.put("External Authentication", "外部认证"); - m.put("External Password Authenticator", "外部密码认证器"); - m.put("Impersonate", "模拟"); - m.put("Link Existing User", "链接现有用户"); - m.put("Link User Bean", "链接用户 Bean"); - m.put("My SSO Accounts", "我的 SSO 账户"); - m.put("No external password authenticator", "没有外部密码认证器"); - m.put("No external password authenticator to authenticate user \"{0}\"", "没有外部密码认证器来认证用户 \"{0}\""); - m.put("Only users able to authenticate via password can be linked", "只有能够通过密码认证的用户才能被链接"); - m.put("Password Authenticator", "密码认证器"); - m.put("Password of the user", "用户的密码"); - m.put("SSO Accounts", "SSO 账户"); - m.put("SSO Providers", "SSO 提供方"); - m.put("SSO account deleted", "SSO 账户已删除"); - m.put("SSO provider \"{0}\" deleted", "SSO 提供方 \"{0}\" 已删除"); - m.put("SSO provider created", "SSO 提供方已创建"); - m.put("SSO provider updated", "SSO 提供方已更新"); - m.put("Service account not allowed to login", "服务账户不允许登录"); - m.put("Single Sign-On", "单点登录"); - m.put("Sso Provider Bean", "Sso 提供方 Bean"); - m.put("Unable to find SSO provider: ", "无法找到 SSO 提供方:"); - m.put("When login via OneDev's built-in form, submitted user credentials can be checked against authenticator defined here, besides the internal database", - "通过 OneDev 的内置表单登录时,提交的用户凭据可以在此处定义的认证器以及内部数据库中进行检查"); } @Override diff --git a/server-core/src/main/java/io/onedev/server/web/util/editbean/NewUserBean.java b/server-core/src/main/java/io/onedev/server/web/util/editbean/NewUserBean.java index bf96c87b98..db04f7184e 100644 --- a/server-core/src/main/java/io/onedev/server/web/util/editbean/NewUserBean.java +++ b/server-core/src/main/java/io/onedev/server/web/util/editbean/NewUserBean.java @@ -3,8 +3,8 @@ package io.onedev.server.web.util.editbean; import javax.validation.constraints.Email; import javax.validation.constraints.NotEmpty; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; -import io.onedev.server.annotation.ShowCondition; import io.onedev.server.model.User; @Editable @@ -17,7 +17,7 @@ public class NewUserBean extends User { private String emailAddress; @Editable(order=1000) - @ShowCondition("isServiceAccountDisabled") + @DependsOn(property="serviceAccount", value="false") @NotEmpty @Email public String getEmailAddress() { diff --git a/server-core/src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java b/server-core/src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java index 484255ef82..21fb42819f 100644 --- a/server-core/src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java +++ b/server-core/src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java @@ -242,6 +242,20 @@ public abstract class BaseConstructor { * @return Java instance */ protected Object constructObject(Node node) { + if (node instanceof MappingNode) { + MappingNode mappingNode = (MappingNode) node; + for (var it = mappingNode.getValue().iterator(); it.hasNext();) { + var tuple = it.next(); + if (tuple.getKeyNode() instanceof ScalarNode) { + ScalarNode keyNode = (ScalarNode) tuple.getKeyNode(); + if ("type".equals(keyNode.getValue())) { + String implementationName = ((ScalarNode) tuple.getValueNode()).getValue(); + mappingNode.setTag(new Tag("!" + implementationName)); + it.remove(); + } + } + } + } if (constructedObjects.containsKey(node)) { return constructedObjects.get(node); } diff --git a/server-core/src/main/java/org/yaml/snakeyaml/representer/Representer.java b/server-core/src/main/java/org/yaml/snakeyaml/representer/Representer.java index 24d7e915a4..d485742c0a 100644 --- a/server-core/src/main/java/org/yaml/snakeyaml/representer/Representer.java +++ b/server-core/src/main/java/org/yaml/snakeyaml/representer/Representer.java @@ -22,6 +22,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; + import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.DumperOptions.FlowStyle; import org.yaml.snakeyaml.TypeDescription; @@ -86,11 +87,7 @@ public class Representer extends SafeRepresenter { */ protected MappingNode representJavaBean(Set properties, Object javaBean) { List value = new ArrayList(properties.size()); - Tag tag; - Tag customTag = classTags.get(javaBean.getClass()); - tag = customTag != null ? customTag : new Tag("!" + javaBean.getClass().getSimpleName()); - // flow style will be chosen by BaseRepresenter - MappingNode node = new MappingNode(tag, value, FlowStyle.AUTO); + MappingNode node = new MappingNode(Tag.MAP, value, FlowStyle.AUTO); representedObjects.put(javaBean, node); DumperOptions.FlowStyle bestStyle = FlowStyle.FLOW; for (Property property : properties) { @@ -146,14 +143,13 @@ public class Representer extends SafeRepresenter { } } } else { - if (nodeId == NodeId.mapping) { - if (property.getType() == propertyValue.getClass()) { - if (!(propertyValue instanceof Map)) { - if (!nodeValue.getTag().equals(Tag.SET)) { - nodeValue.setTag(Tag.MAP); - } - } - } + if (nodeId == NodeId.mapping && !(propertyValue instanceof Map) + && !nodeValue.getTag().equals(Tag.SET) + && property.getType() != propertyValue.getClass()) { + var mappingNode = (MappingNode) nodeValue; + mappingNode.getValue().add(0, new NodeTuple( + new ScalarNode(Tag.STR, "type"), + new ScalarNode(Tag.STR, propertyValue.getClass().getSimpleName()))); } checkGlobalTag(property, nodeValue, propertyValue); } @@ -195,12 +191,13 @@ public class Representer extends SafeRepresenter { if (iter.hasNext()) { for (Node childNode : snode.getValue()) { Object member = iter.next(); - if (member != null) { - if (t.equals(member.getClass())) { - if (childNode.getNodeId() == NodeId.mapping) { - childNode.setTag(Tag.MAP); - } - } + if (member != null + && childNode.getNodeId() == NodeId.mapping + && !t.equals(member.getClass())) { + var childMappingMode = (MappingNode) childNode; + childMappingMode.getValue().add(0, new NodeTuple( + new ScalarNode(Tag.STR, "type"), + new ScalarNode(Tag.STR, member.getClass().getSimpleName()))); } } } @@ -212,10 +209,10 @@ public class Representer extends SafeRepresenter { for (Object member : set) { NodeTuple tuple = iter.next(); Node keyNode = tuple.getKeyNode(); - if (t.equals(member.getClass())) { - if (keyNode.getNodeId() == NodeId.mapping) { - keyNode.setTag(Tag.MAP); - } + if (keyNode.getNodeId() == NodeId.mapping && !t.equals(member.getClass())) { + mnode.getValue().add(0, new NodeTuple( + new ScalarNode(Tag.STR, "type"), + new ScalarNode(Tag.STR, member.getClass().getSimpleName()))); } } } else if (object instanceof Map) { // NodeId.mapping ends-up here diff --git a/server-ee b/server-ee index d2d0607194..5ec90bb5da 160000 --- a/server-ee +++ b/server-ee @@ -1 +1 @@ -Subproject commit d2d06071947cdb284f01173028b2c4281efbf036 +Subproject commit 5ec90bb5da921bbe3dbd22b6719819945d76a44b diff --git a/server-plugin/server-plugin-authenticator-ldap/src/main/java/io/onedev/server/plugin/authenticator/ldap/ActiveDirectoryAuthenticator.java b/server-plugin/server-plugin-authenticator-ldap/src/main/java/io/onedev/server/plugin/authenticator/ldap/ActiveDirectoryAuthenticator.java index ce65c72d35..76e9024be9 100644 --- a/server-plugin/server-plugin-authenticator-ldap/src/main/java/io/onedev/server/plugin/authenticator/ldap/ActiveDirectoryAuthenticator.java +++ b/server-plugin/server-plugin-authenticator-ldap/src/main/java/io/onedev/server/plugin/authenticator/ldap/ActiveDirectoryAuthenticator.java @@ -1,12 +1,12 @@ package io.onedev.server.plugin.authenticator.ldap; +import java.util.List; + import javax.validation.constraints.NotEmpty; import javax.validation.constraints.Size; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; -import io.onedev.server.annotation.ShowCondition; - -import java.util.List; @Editable(name="Active Directory", order=100) public class ActiveDirectoryAuthenticator extends LdapAuthenticator { @@ -34,7 +34,7 @@ public class ActiveDirectoryAuthenticator extends LdapAuthenticator { + "Specify manager DN to authenticate OneDev itself to Active Directory. The manager DN should be specified " + "in form of <account name>@<domain>, for instance: manager@example.com") @NotEmpty - @ShowCondition("isAuthenticationRequiredEnabled") + @DependsOn(property=PROP_AUTHENTICATION_REQUIRED) @Override public String getManagerDN() { return super.getManagerDN(); diff --git a/server-plugin/server-plugin-authenticator-ldap/src/main/java/io/onedev/server/plugin/authenticator/ldap/LdapAuthenticator.java b/server-plugin/server-plugin-authenticator-ldap/src/main/java/io/onedev/server/plugin/authenticator/ldap/LdapAuthenticator.java index ec7f03283a..8627a2afef 100644 --- a/server-plugin/server-plugin-authenticator-ldap/src/main/java/io/onedev/server/plugin/authenticator/ldap/LdapAuthenticator.java +++ b/server-plugin/server-plugin-authenticator-ldap/src/main/java/io/onedev/server/plugin/authenticator/ldap/LdapAuthenticator.java @@ -1,33 +1,49 @@ package io.onedev.server.plugin.authenticator.ldap; -import io.onedev.commons.utils.ExplicitException; -import io.onedev.commons.utils.StringUtils; -import io.onedev.server.annotation.Editable; -import io.onedev.server.annotation.Password; -import io.onedev.server.annotation.ShowCondition; -import io.onedev.server.model.support.administration.authenticator.Authenticated; -import io.onedev.server.model.support.administration.authenticator.Authenticator; -import io.onedev.server.security.TrustCertsSSLSocketFactory; -import io.onedev.server.util.EditContext; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; + +import javax.annotation.Nullable; +import javax.naming.AuthenticationException; +import javax.naming.CompositeName; +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.PartialResultException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import javax.naming.directory.DirContext; +import javax.naming.directory.InitialDirContext; +import javax.naming.directory.SearchControls; +import javax.naming.directory.SearchResult; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.Nullable; -import javax.naming.*; -import javax.naming.directory.*; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; -import java.util.*; +import io.onedev.commons.utils.ExplicitException; +import io.onedev.commons.utils.StringUtils; +import io.onedev.server.annotation.DependsOn; +import io.onedev.server.annotation.Editable; +import io.onedev.server.annotation.Password; +import io.onedev.server.model.support.administration.authenticator.Authenticated; +import io.onedev.server.model.support.administration.authenticator.Authenticator; +import io.onedev.server.security.TrustCertsSSLSocketFactory; @Editable(name="Generic LDAP", order=200) public class LdapAuthenticator extends Authenticator { private static final long serialVersionUID = 1L; - private static final String PROP_AUTHENTICATION_REQUIRED = "authenticationRequired"; + protected static final String PROP_AUTHENTICATION_REQUIRED = "authenticationRequired"; private static final Logger logger = LoggerFactory.getLogger(LdapAuthenticator.class); @@ -74,14 +90,9 @@ public class LdapAuthenticator extends Authenticator { public void setAuthenticationRequired(boolean authenticationRequired) { this.authenticationRequired = authenticationRequired; } - - @SuppressWarnings("unused") - private static boolean isAuthenticationRequiredEnabled() { - return (boolean) EditContext.get().getInputValue(PROP_AUTHENTICATION_REQUIRED); - } @Editable(order=300, description="Specify manager DN to authenticate OneDev itself to LDAP server") - @ShowCondition("isAuthenticationRequiredEnabled") + @DependsOn(property=PROP_AUTHENTICATION_REQUIRED) @NotEmpty public String getManagerDN() { return managerDN; @@ -93,7 +104,7 @@ public class LdapAuthenticator extends Authenticator { @Editable(order=400, description="Specifies password of above manager DN") @Password - @ShowCondition("isAuthenticationRequiredEnabled") + @DependsOn(property=PROP_AUTHENTICATION_REQUIRED) @NotEmpty public String getManagerPassword() { return managerPassword; diff --git a/server-plugin/server-plugin-executor-kubernetes/src/main/java/io/onedev/server/plugin/executor/kubernetes/KubernetesExecutor.java b/server-plugin/server-plugin-executor-kubernetes/src/main/java/io/onedev/server/plugin/executor/kubernetes/KubernetesExecutor.java index c9cd67d519..98552a1efb 100644 --- a/server-plugin/server-plugin-executor-kubernetes/src/main/java/io/onedev/server/plugin/executor/kubernetes/KubernetesExecutor.java +++ b/server-plugin/server-plugin-executor-kubernetes/src/main/java/io/onedev/server/plugin/executor/kubernetes/KubernetesExecutor.java @@ -1,5 +1,50 @@ package io.onedev.server.plugin.executor.kubernetes; +import static com.google.common.collect.Lists.newArrayList; +import static io.onedev.k8shelper.ExecuteCondition.ALWAYS; +import static io.onedev.k8shelper.KubernetesHelper.ENV_JOB_TOKEN; +import static io.onedev.k8shelper.KubernetesHelper.ENV_SERVER_URL; +import static io.onedev.k8shelper.KubernetesHelper.IMAGE_REPO; +import static io.onedev.k8shelper.KubernetesHelper.LOG_END_MESSAGE; +import static io.onedev.k8shelper.KubernetesHelper.parseStepPosition; +import static io.onedev.k8shelper.KubernetesHelper.stringifyStepPosition; +import static io.onedev.k8shelper.RegistryLoginFacade.merge; +import static io.onedev.server.util.CollectionUtils.newHashMap; +import static io.onedev.server.util.CollectionUtils.newLinkedHashMap; +import static java.lang.Integer.parseInt; +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.stream.Collectors.toList; +import static org.apache.commons.codec.binary.Base64.encodeBase64String; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.time.Instant; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +import javax.annotation.Nullable; +import javax.validation.constraints.NotEmpty; + +import org.apache.commons.lang.SerializationUtils; +import org.apache.commons.lang3.RandomUtils; +import org.apache.commons.lang3.SystemUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.yaml.snakeyaml.Yaml; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -7,60 +52,48 @@ import com.google.common.base.Preconditions; import com.google.common.base.Splitter; import com.google.common.collect.Lists; import com.google.common.collect.Sets; + import io.onedev.commons.bootstrap.Bootstrap; -import io.onedev.commons.utils.*; +import io.onedev.commons.utils.ExceptionUtils; +import io.onedev.commons.utils.ExplicitException; +import io.onedev.commons.utils.FileUtils; +import io.onedev.commons.utils.StringUtils; +import io.onedev.commons.utils.TaskLogger; import io.onedev.commons.utils.command.Commandline; import io.onedev.commons.utils.command.LineConsumer; -import io.onedev.k8shelper.*; +import io.onedev.k8shelper.Action; +import io.onedev.k8shelper.BuildImageFacade; +import io.onedev.k8shelper.CommandFacade; +import io.onedev.k8shelper.CompositeFacade; +import io.onedev.k8shelper.KubernetesHelper; +import io.onedev.k8shelper.LeafFacade; +import io.onedev.k8shelper.PruneBuilderCacheFacade; +import io.onedev.k8shelper.RegistryLoginFacade; +import io.onedev.k8shelper.RunContainerFacade; +import io.onedev.k8shelper.RunImagetoolsFacade; +import io.onedev.k8shelper.ServiceFacade; +import io.onedev.k8shelper.SetupCacheFacade; import io.onedev.server.OneDev; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; import io.onedev.server.annotation.OmitName; -import io.onedev.server.annotation.ShowCondition; import io.onedev.server.buildspecmodel.inputspec.SecretInput; import io.onedev.server.cluster.ClusterManager; import io.onedev.server.entitymanager.SettingManager; import io.onedev.server.job.JobContext; import io.onedev.server.job.JobManager; import io.onedev.server.job.JobRunnable; -import io.onedev.server.model.support.administration.jobexecutor.*; +import io.onedev.server.model.support.administration.jobexecutor.JobExecutor; +import io.onedev.server.model.support.administration.jobexecutor.KubernetesAware; +import io.onedev.server.model.support.administration.jobexecutor.NodeSelectorEntry; +import io.onedev.server.model.support.administration.jobexecutor.RegistryLogin; +import io.onedev.server.model.support.administration.jobexecutor.ServiceLocator; import io.onedev.server.plugin.executor.kubernetes.KubernetesExecutor.TestData; import io.onedev.server.terminal.CommandlineShell; import io.onedev.server.terminal.Shell; import io.onedev.server.terminal.Terminal; -import io.onedev.server.util.EditContext; import io.onedev.server.util.FilenameUtils; import io.onedev.server.web.util.Testable; -import org.apache.commons.lang.SerializationUtils; -import org.apache.commons.lang3.RandomUtils; -import org.apache.commons.lang3.SystemUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.yaml.snakeyaml.Yaml; - -import javax.annotation.Nullable; -import javax.validation.constraints.NotEmpty; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.Serializable; -import java.time.Instant; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; -import java.util.*; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; - -import static com.google.common.collect.Lists.newArrayList; -import static io.onedev.k8shelper.ExecuteCondition.ALWAYS; -import static io.onedev.k8shelper.KubernetesHelper.*; -import static io.onedev.k8shelper.RegistryLoginFacade.merge; -import static io.onedev.server.util.CollectionUtils.newHashMap; -import static io.onedev.server.util.CollectionUtils.newLinkedHashMap; -import static java.lang.Integer.parseInt; -import static java.nio.charset.StandardCharsets.UTF_8; -import static java.util.stream.Collectors.toList; -import static org.apache.commons.codec.binary.Base64.encodeBase64String; @Editable(order=KubernetesExecutor.ORDER, description="This executor runs build jobs as pods in a kubernetes cluster. " + "No any agents are required." @@ -130,17 +163,12 @@ public class KubernetesExecutor extends JobExecutor implements KubernetesAware, public void setBuildWithPV(boolean buildWithPV) { this.buildWithPV = buildWithPV; } - - @SuppressWarnings("unused") - private static boolean isBuildWithPVEnabled() { - return (boolean) EditContext.get().getInputValue("buildWithPV"); - } @Editable(order=400, name="Build Volume Storage Class", placeholder = "Use default storage class", description = "" + "Optionally specify a storage class to allocate build volume dynamically. Leave empty to use default storage class. " + "NOTE: Reclaim policy of the storage class should be set to Delete, " + "as the volume is only used to hold temporary build files") - @ShowCondition("isBuildWithPVEnabled") + @DependsOn(property="buildWithPV") public String getStorageClass() { return storageClass; } @@ -152,7 +180,7 @@ public class KubernetesExecutor extends JobExecutor implements KubernetesAware, @Editable(order=500, name="Build Volume Storage Size", description = "Specify storage size to request " + "for the build volume. The size should conform to Kubernetes resource capacity format, " + "for instance 10Gi") - @ShowCondition("isBuildWithPVEnabled") + @DependsOn(property="buildWithPV") @NotEmpty public String getStorageSize() { return storageSize; diff --git a/server-plugin/server-plugin-import-bitbucketcloud/src/main/java/io/onedev/server/plugin/imports/bitbucketcloud/ImportRepositories.java b/server-plugin/server-plugin-import-bitbucketcloud/src/main/java/io/onedev/server/plugin/imports/bitbucketcloud/ImportRepositories.java index 0eee26246c..3c7f90d9d3 100644 --- a/server-plugin/server-plugin-import-bitbucketcloud/src/main/java/io/onedev/server/plugin/imports/bitbucketcloud/ImportRepositories.java +++ b/server-plugin/server-plugin-import-bitbucketcloud/src/main/java/io/onedev/server/plugin/imports/bitbucketcloud/ImportRepositories.java @@ -1,9 +1,16 @@ package io.onedev.server.plugin.imports.bitbucketcloud; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import javax.validation.ConstraintValidatorContext; +import javax.validation.constraints.Size; + import io.onedev.server.annotation.ChoiceProvider; import io.onedev.server.annotation.ClassValidating; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; -import io.onedev.server.annotation.ShowCondition; import io.onedev.server.security.SecurityUtils; import io.onedev.server.security.permission.CreateChildren; import io.onedev.server.util.ComponentContext; @@ -11,12 +18,6 @@ import io.onedev.server.util.EditContext; import io.onedev.server.validation.Validatable; import io.onedev.server.web.editable.BeanEditor; -import javax.validation.ConstraintValidatorContext; -import javax.validation.constraints.Size; -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; - @Editable @ClassValidating public class ImportRepositories extends ImportWorkspace implements Validatable { @@ -57,17 +58,8 @@ public class ImportRepositories extends ImportWorkspace implements Validatable { this.all = all; } - private static boolean isAllEnabled() { - return (Boolean)EditContext.get().getInputValue("all"); - } - - @SuppressWarnings("unused") - private static boolean isAllDisabled() { - return !isAllEnabled(); - } - @Editable(order=400, description="Whether or not to import forked Bitbucket repositories") - @ShowCondition("isAllEnabled") + @DependsOn(property="all") public boolean isIncludeForks() { return includeForks; } @@ -78,7 +70,7 @@ public class ImportRepositories extends ImportWorkspace implements Validatable { @Editable(order=500, name="Bitbucket Repositories to Import") @ChoiceProvider("getBitbucketRepositoryChoices") - @ShowCondition("isAllDisabled") + @DependsOn(property="all", value="false") @Size(min=1, message="At least one repository should be selected") public List getBitbucketRepositories() { return bitbucketRepositories; diff --git a/server-plugin/server-plugin-import-gitea/src/main/java/io/onedev/server/plugin/imports/gitea/ImportRepositories.java b/server-plugin/server-plugin-import-gitea/src/main/java/io/onedev/server/plugin/imports/gitea/ImportRepositories.java index 4637f46456..3ca49a22b1 100644 --- a/server-plugin/server-plugin-import-gitea/src/main/java/io/onedev/server/plugin/imports/gitea/ImportRepositories.java +++ b/server-plugin/server-plugin-import-gitea/src/main/java/io/onedev/server/plugin/imports/gitea/ImportRepositories.java @@ -1,10 +1,17 @@ package io.onedev.server.plugin.imports.gitea; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import javax.validation.ConstraintValidatorContext; +import javax.validation.constraints.Size; + import io.onedev.server.OneDev; import io.onedev.server.annotation.ChoiceProvider; import io.onedev.server.annotation.ClassValidating; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; -import io.onedev.server.annotation.ShowCondition; import io.onedev.server.entitymanager.ProjectManager; import io.onedev.server.security.SecurityUtils; import io.onedev.server.security.permission.CreateChildren; @@ -13,12 +20,6 @@ import io.onedev.server.util.EditContext; import io.onedev.server.validation.Validatable; import io.onedev.server.web.editable.BeanEditor; -import javax.validation.ConstraintValidatorContext; -import javax.validation.constraints.Size; -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; - @Editable @ClassValidating public class ImportRepositories extends ImportOrganization implements Validatable { @@ -59,18 +60,9 @@ public class ImportRepositories extends ImportOrganization implements Validatabl public void setAll(boolean all) { this.all = all; } - - private static boolean isAllEnabled() { - return (Boolean)EditContext.get().getInputValue("all"); - } - @SuppressWarnings("unused") - private static boolean isAllDisabled() { - return !isAllEnabled(); - } - @Editable(order=400, description="Whether or not to import forked Gitea repositories") - @ShowCondition("isAllEnabled") + @DependsOn(property="all") public boolean isIncludeForks() { return includeForks; } @@ -81,7 +73,7 @@ public class ImportRepositories extends ImportOrganization implements Validatabl @Editable(order=500, name="Gitea Repositories to Import") @ChoiceProvider("getGiteaRepositoryChoices") - @ShowCondition("isAllDisabled") + @DependsOn(property="all", value="false") @Size(min=1, message="At least one repository should be selected") public List getGiteaRepositories() { return giteaRepositories; diff --git a/server-plugin/server-plugin-import-github/src/main/java/io/onedev/server/plugin/imports/github/ImportRepositories.java b/server-plugin/server-plugin-import-github/src/main/java/io/onedev/server/plugin/imports/github/ImportRepositories.java index ea33b4eb37..fea36a7003 100644 --- a/server-plugin/server-plugin-import-github/src/main/java/io/onedev/server/plugin/imports/github/ImportRepositories.java +++ b/server-plugin/server-plugin-import-github/src/main/java/io/onedev/server/plugin/imports/github/ImportRepositories.java @@ -1,9 +1,16 @@ package io.onedev.server.plugin.imports.github; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import javax.validation.ConstraintValidatorContext; +import javax.validation.constraints.Size; + import io.onedev.server.annotation.ChoiceProvider; import io.onedev.server.annotation.ClassValidating; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; -import io.onedev.server.annotation.ShowCondition; import io.onedev.server.security.SecurityUtils; import io.onedev.server.security.permission.CreateChildren; import io.onedev.server.util.ComponentContext; @@ -11,12 +18,6 @@ import io.onedev.server.util.EditContext; import io.onedev.server.validation.Validatable; import io.onedev.server.web.editable.BeanEditor; -import javax.validation.ConstraintValidatorContext; -import javax.validation.constraints.Size; -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; - @Editable @ClassValidating public class ImportRepositories extends ImportOrganization implements Validatable { @@ -55,19 +56,10 @@ public class ImportRepositories extends ImportOrganization implements Validatabl public void setAll(boolean all) { this.all = all; - } - - private static boolean isAllEnabled() { - return (Boolean)EditContext.get().getInputValue("all"); - } - - @SuppressWarnings("unused") - private static boolean isAllDisabled() { - return !isAllEnabled(); - } + } @Editable(order=400, description="Whether or not to import forked GitHub repositories") - @ShowCondition("isAllEnabled") + @DependsOn(property="all") public boolean isIncludeForks() { return includeForks; } @@ -78,7 +70,7 @@ public class ImportRepositories extends ImportOrganization implements Validatabl @Editable(order=500, name="GitHub Repositories to Import") @ChoiceProvider("getGitHubRepositoryChoices") - @ShowCondition("isAllDisabled") + @DependsOn(property="all", value="false") @Size(min=1, message="At least one repository should be selected") public List getGitHubRepositories() { return gitHubRepositories; diff --git a/server-plugin/server-plugin-import-gitlab/src/main/java/io/onedev/server/plugin/imports/gitlab/ImportProjects.java b/server-plugin/server-plugin-import-gitlab/src/main/java/io/onedev/server/plugin/imports/gitlab/ImportProjects.java index 59e6e56f22..7c1886efd1 100644 --- a/server-plugin/server-plugin-import-gitlab/src/main/java/io/onedev/server/plugin/imports/gitlab/ImportProjects.java +++ b/server-plugin/server-plugin-import-gitlab/src/main/java/io/onedev/server/plugin/imports/gitlab/ImportProjects.java @@ -1,17 +1,18 @@ package io.onedev.server.plugin.imports.gitlab; +import java.util.Collection; +import java.util.List; + +import javax.validation.constraints.Size; + import io.onedev.server.annotation.ChoiceProvider; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; import io.onedev.server.annotation.ProjectChoice; -import io.onedev.server.annotation.ShowCondition; import io.onedev.server.util.ComponentContext; import io.onedev.server.util.EditContext; import io.onedev.server.web.editable.BeanEditor; -import javax.validation.constraints.Size; -import java.util.Collection; -import java.util.List; - @Editable public class ImportProjects extends ImportGroup { @@ -44,18 +45,9 @@ public class ImportProjects extends ImportGroup { public void setAll(boolean all) { this.all = all; } - - private static boolean isAllEnabled() { - return (Boolean)EditContext.get().getInputValue("all"); - } - @SuppressWarnings("unused") - private static boolean isAllDisabled() { - return !isAllEnabled(); - } - @Editable(order=400, description="Whether or not to import forked GitLab projects") - @ShowCondition("isAllEnabled") + @DependsOn(property="all") public boolean isIncludeForks() { return includeForks; } @@ -66,7 +58,7 @@ public class ImportProjects extends ImportGroup { @Editable(order=500, name="GitLab Projects to Import") @ChoiceProvider("getGitLabProjectChoices") - @ShowCondition("isAllDisabled") + @DependsOn(property="all", value="false") @Size(min=1, message="At least one project should be selected") public List getGitLabProjects() { return gitLabProjects; diff --git a/server-plugin/server-plugin-import-jiracloud/src/main/java/io/onedev/server/plugin/imports/jiracloud/ImportProjects.java b/server-plugin/server-plugin-import-jiracloud/src/main/java/io/onedev/server/plugin/imports/jiracloud/ImportProjects.java index 32f690681c..b46c92f030 100644 --- a/server-plugin/server-plugin-import-jiracloud/src/main/java/io/onedev/server/plugin/imports/jiracloud/ImportProjects.java +++ b/server-plugin/server-plugin-import-jiracloud/src/main/java/io/onedev/server/plugin/imports/jiracloud/ImportProjects.java @@ -1,23 +1,23 @@ package io.onedev.server.plugin.imports.jiracloud; -import io.onedev.server.annotation.ChoiceProvider; -import io.onedev.server.annotation.ClassValidating; -import io.onedev.server.annotation.Editable; -import io.onedev.server.annotation.ShowCondition; -import io.onedev.server.security.SecurityUtils; -import io.onedev.server.security.permission.CreateChildren; -import io.onedev.server.util.ComponentContext; -import io.onedev.server.util.EditContext; -import io.onedev.server.validation.Validatable; -import io.onedev.server.web.editable.BeanEditor; - -import javax.validation.ConstraintValidatorContext; -import javax.validation.constraints.Size; import java.io.Serializable; import java.util.Collection; import java.util.List; import java.util.stream.Collectors; +import javax.validation.ConstraintValidatorContext; +import javax.validation.constraints.Size; + +import io.onedev.server.annotation.ChoiceProvider; +import io.onedev.server.annotation.ClassValidating; +import io.onedev.server.annotation.DependsOn; +import io.onedev.server.annotation.Editable; +import io.onedev.server.security.SecurityUtils; +import io.onedev.server.security.permission.CreateChildren; +import io.onedev.server.util.ComponentContext; +import io.onedev.server.validation.Validatable; +import io.onedev.server.web.editable.BeanEditor; + @Editable @ClassValidating public class ImportProjects implements Serializable, Validatable { @@ -58,14 +58,9 @@ public class ImportProjects implements Serializable, Validatable { this.all = all; } - @SuppressWarnings("unused") - private static boolean isAllDisabled() { - return !(Boolean) EditContext.get().getInputValue("all"); - } - @Editable(order=500, name="JIRA Projects to Import") @ChoiceProvider("getJiraProjectChoices") - @ShowCondition("isAllDisabled") + @DependsOn(property="all", value="false") @Size(min=1, message="At least one project should be selected") public List getJiraProjects() { return jiraProjects; diff --git a/server-plugin/server-plugin-import-youtrack/src/main/java/io/onedev/server/plugin/imports/youtrack/ImportProjects.java b/server-plugin/server-plugin-import-youtrack/src/main/java/io/onedev/server/plugin/imports/youtrack/ImportProjects.java index 9c0c7d744e..15b05f04b3 100644 --- a/server-plugin/server-plugin-import-youtrack/src/main/java/io/onedev/server/plugin/imports/youtrack/ImportProjects.java +++ b/server-plugin/server-plugin-import-youtrack/src/main/java/io/onedev/server/plugin/imports/youtrack/ImportProjects.java @@ -10,12 +10,11 @@ import javax.validation.constraints.Size; import io.onedev.server.annotation.ChoiceProvider; import io.onedev.server.annotation.ClassValidating; +import io.onedev.server.annotation.DependsOn; import io.onedev.server.annotation.Editable; -import io.onedev.server.annotation.ShowCondition; import io.onedev.server.security.SecurityUtils; import io.onedev.server.security.permission.CreateChildren; import io.onedev.server.util.ComponentContext; -import io.onedev.server.util.EditContext; import io.onedev.server.validation.Validatable; import io.onedev.server.web.editable.BeanEditor; @@ -61,14 +60,9 @@ public class ImportProjects implements Serializable, Validatable { this.all = all; } - @SuppressWarnings("unused") - private static boolean isAllDisabled() { - return !(Boolean) EditContext.get().getInputValue("all"); - } - @Editable(order=500, name="YouTrack Projects to Import") @ChoiceProvider("getYouTrackProjectChoices") - @ShowCondition("isAllDisabled") + @DependsOn(property="all", value="false") @Size(min=1, message="At least one project should be selected") public List getYouTrackProjects() { return youTrackProjects;