-
-
Notifications
You must be signed in to change notification settings - Fork 10.2k
feat: Email notification when releasing by OpenAPI #5324
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,10 +30,12 @@ | |
import com.ctrip.framework.apollo.openapi.util.OpenApiBeanUtils; | ||
import com.ctrip.framework.apollo.portal.entity.model.NamespaceGrayDelReleaseModel; | ||
import com.ctrip.framework.apollo.portal.entity.model.NamespaceReleaseModel; | ||
import com.ctrip.framework.apollo.portal.listener.ConfigPublishEvent; | ||
import com.ctrip.framework.apollo.portal.service.NamespaceBranchService; | ||
import com.ctrip.framework.apollo.portal.service.ReleaseService; | ||
import com.ctrip.framework.apollo.portal.spi.UserService; | ||
import javax.servlet.http.HttpServletRequest; | ||
import org.springframework.context.ApplicationEventPublisher; | ||
import org.springframework.security.access.AccessDeniedException; | ||
import org.springframework.security.access.prepost.PreAuthorize; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
|
@@ -54,18 +56,21 @@ public class ReleaseController { | |
private final NamespaceBranchService namespaceBranchService; | ||
private final ConsumerPermissionValidator consumerPermissionValidator; | ||
private final ReleaseOpenApiService releaseOpenApiService; | ||
private final ApplicationEventPublisher publisher; | ||
|
||
public ReleaseController( | ||
final ReleaseService releaseService, | ||
final UserService userService, | ||
final NamespaceBranchService namespaceBranchService, | ||
final ConsumerPermissionValidator consumerPermissionValidator, | ||
ReleaseOpenApiService releaseOpenApiService) { | ||
ReleaseOpenApiService releaseOpenApiService, | ||
ApplicationEventPublisher publisher) { | ||
this.releaseService = releaseService; | ||
this.userService = userService; | ||
this.namespaceBranchService = namespaceBranchService; | ||
this.consumerPermissionValidator = consumerPermissionValidator; | ||
this.releaseOpenApiService = releaseOpenApiService; | ||
this.publisher = publisher; | ||
} | ||
|
||
@PreAuthorize(value = "@consumerPermissionValidator.hasReleaseNamespacePermission(#request, #appId, #namespaceName, #env)") | ||
|
@@ -83,7 +88,19 @@ public OpenReleaseDTO createRelease(@PathVariable String appId, @PathVariable St | |
throw BadRequestException.userNotExists(model.getReleasedBy()); | ||
} | ||
|
||
return this.releaseOpenApiService.publishNamespace(appId, env, clusterName, namespaceName, model); | ||
OpenReleaseDTO releaseDTO = this.releaseOpenApiService.publishNamespace(appId, env, | ||
clusterName, namespaceName, model); | ||
|
||
ConfigPublishEvent event = ConfigPublishEvent.instance(); | ||
event.withAppId(appId) | ||
.withCluster(clusterName) | ||
.withNamespace(namespaceName) | ||
.withReleaseId(releaseDTO.getId()) | ||
.setNormalPublishEvent(true) | ||
.setEnv(Env.valueOf(env)); | ||
publisher.publishEvent(event); | ||
|
||
return releaseDTO; | ||
} | ||
|
||
@GetMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases/latest") | ||
|
@@ -93,78 +110,91 @@ public OpenReleaseDTO loadLatestActiveRelease(@PathVariable String appId, @PathV | |
return this.releaseOpenApiService.getLatestActiveRelease(appId, env, clusterName, namespaceName); | ||
} | ||
|
||
@PreAuthorize(value = "@consumerPermissionValidator.hasReleaseNamespacePermission(#request, #appId, #namespaceName, #env)") | ||
@PostMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/merge") | ||
public OpenReleaseDTO merge(@PathVariable String appId, @PathVariable String env, | ||
@PathVariable String clusterName, @PathVariable String namespaceName, | ||
@PathVariable String branchName, @RequestParam(value = "deleteBranch", defaultValue = "true") boolean deleteBranch, | ||
@RequestBody NamespaceReleaseDTO model, HttpServletRequest request) { | ||
RequestPrecondition.checkArguments(!StringUtils.isContainEmpty(model.getReleasedBy(), model | ||
.getReleaseTitle()), | ||
"Params(releaseTitle and releasedBy) can not be empty"); | ||
|
||
if (userService.findByUserId(model.getReleasedBy()) == null) { | ||
throw BadRequestException.userNotExists(model.getReleasedBy()); | ||
} | ||
|
||
ReleaseDTO mergedRelease = namespaceBranchService.merge(appId, Env.valueOf(env.toUpperCase()), clusterName, namespaceName, branchName, | ||
model.getReleaseTitle(), model.getReleaseComment(), | ||
model.isEmergencyPublish(), deleteBranch, model.getReleasedBy()); | ||
|
||
return OpenApiBeanUtils.transformFromReleaseDTO(mergedRelease); | ||
@PreAuthorize(value = "@consumerPermissionValidator.hasReleaseNamespacePermission(#request, #appId, #namespaceName, #env)") | ||
@PostMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/merge") | ||
public OpenReleaseDTO merge(@PathVariable String appId, @PathVariable String env, | ||
@PathVariable String clusterName, @PathVariable String namespaceName, | ||
@PathVariable String branchName, | ||
@RequestParam(value = "deleteBranch", defaultValue = "true") boolean deleteBranch, | ||
@RequestBody NamespaceReleaseDTO model, HttpServletRequest request) { | ||
RequestPrecondition.checkArguments( | ||
!StringUtils.isContainEmpty(model.getReleasedBy(), model.getReleaseTitle()), | ||
"Params(releaseTitle and releasedBy) can not be empty"); | ||
|
||
if (userService.findByUserId(model.getReleasedBy()) == null) { | ||
throw BadRequestException.userNotExists(model.getReleasedBy()); | ||
} | ||
|
||
@PreAuthorize(value = "@consumerPermissionValidator.hasReleaseNamespacePermission(#request, #appId, #namespaceName, #env)") | ||
@PostMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/releases") | ||
public OpenReleaseDTO createGrayRelease(@PathVariable String appId, | ||
@PathVariable String env, @PathVariable String clusterName, | ||
@PathVariable String namespaceName, @PathVariable String branchName, | ||
@RequestBody NamespaceReleaseDTO model, | ||
HttpServletRequest request) { | ||
RequestPrecondition.checkArguments(!StringUtils.isContainEmpty(model.getReleasedBy(), model | ||
.getReleaseTitle()), | ||
"Params(releaseTitle and releasedBy) can not be empty"); | ||
|
||
if (userService.findByUserId(model.getReleasedBy()) == null) { | ||
throw BadRequestException.userNotExists(model.getReleasedBy()); | ||
} | ||
|
||
NamespaceReleaseModel releaseModel = BeanUtils.transform(NamespaceReleaseModel.class, model); | ||
|
||
releaseModel.setAppId(appId); | ||
releaseModel.setEnv(Env.valueOf(env).toString()); | ||
releaseModel.setClusterName(branchName); | ||
releaseModel.setNamespaceName(namespaceName); | ||
|
||
return OpenApiBeanUtils.transformFromReleaseDTO(releaseService.publish(releaseModel)); | ||
ReleaseDTO mergedRelease = namespaceBranchService.merge(appId, Env.valueOf(env.toUpperCase()), | ||
clusterName, namespaceName, branchName, model.getReleaseTitle(), model.getReleaseComment(), | ||
model.isEmergencyPublish(), deleteBranch, model.getReleasedBy()); | ||
|
||
ConfigPublishEvent event = ConfigPublishEvent.instance(); | ||
event.withAppId(appId).withCluster(clusterName).withNamespace(namespaceName) | ||
.withReleaseId(mergedRelease.getId()).setMergeEvent(true).setEnv(Env.valueOf(env)); | ||
publisher.publishEvent(event); | ||
|
||
return OpenApiBeanUtils.transformFromReleaseDTO(mergedRelease); | ||
} | ||
|
||
@PreAuthorize(value = "@consumerPermissionValidator.hasReleaseNamespacePermission(#request, #appId, #namespaceName, #env)") | ||
@PostMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/releases") | ||
public OpenReleaseDTO createGrayRelease(@PathVariable String appId, @PathVariable String env, | ||
@PathVariable String clusterName, @PathVariable String namespaceName, | ||
@PathVariable String branchName, @RequestBody NamespaceReleaseDTO model, | ||
HttpServletRequest request) { | ||
RequestPrecondition.checkArguments( | ||
!StringUtils.isContainEmpty(model.getReleasedBy(), model.getReleaseTitle()), | ||
"Params(releaseTitle and releasedBy) can not be empty"); | ||
|
||
if (userService.findByUserId(model.getReleasedBy()) == null) { | ||
throw BadRequestException.userNotExists(model.getReleasedBy()); | ||
} | ||
|
||
@PreAuthorize(value = "@consumerPermissionValidator.hasReleaseNamespacePermission(#request, #appId, #namespaceName, #env)") | ||
@PostMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/gray-del-releases") | ||
public OpenReleaseDTO createGrayDelRelease(@PathVariable String appId, | ||
@PathVariable String env, @PathVariable String clusterName, | ||
@PathVariable String namespaceName, @PathVariable String branchName, | ||
@RequestBody NamespaceGrayDelReleaseDTO model, | ||
HttpServletRequest request) { | ||
RequestPrecondition.checkArguments(!StringUtils.isContainEmpty(model.getReleasedBy(), model | ||
.getReleaseTitle()), | ||
"Params(releaseTitle and releasedBy) can not be empty"); | ||
RequestPrecondition.checkArguments(model.getGrayDelKeys() != null, | ||
"Params(grayDelKeys) can not be null"); | ||
|
||
if (userService.findByUserId(model.getReleasedBy()) == null) { | ||
throw BadRequestException.userNotExists(model.getReleasedBy()); | ||
} | ||
|
||
NamespaceGrayDelReleaseModel releaseModel = BeanUtils.transform(NamespaceGrayDelReleaseModel.class, model); | ||
releaseModel.setAppId(appId); | ||
releaseModel.setEnv(env.toUpperCase()); | ||
releaseModel.setClusterName(branchName); | ||
releaseModel.setNamespaceName(namespaceName); | ||
|
||
return OpenApiBeanUtils.transformFromReleaseDTO(releaseService.publish(releaseModel, releaseModel.getReleasedBy())); | ||
NamespaceReleaseModel releaseModel = BeanUtils.transform(NamespaceReleaseModel.class, model); | ||
|
||
releaseModel.setAppId(appId); | ||
releaseModel.setEnv(Env.valueOf(env).toString()); | ||
releaseModel.setClusterName(branchName); | ||
releaseModel.setNamespaceName(namespaceName); | ||
|
||
ReleaseDTO releaseDTO = releaseService.publish(releaseModel); | ||
|
||
ConfigPublishEvent event = ConfigPublishEvent.instance(); | ||
event.withAppId(appId).withCluster(clusterName).withNamespace(namespaceName) | ||
.withReleaseId(releaseDTO.getId()).setGrayPublishEvent(true).setEnv(Env.valueOf(env)); | ||
publisher.publishEvent(event); | ||
|
||
return OpenApiBeanUtils.transformFromReleaseDTO(releaseDTO); | ||
} | ||
|
||
@PreAuthorize(value = "@consumerPermissionValidator.hasReleaseNamespacePermission(#request, #appId, #namespaceName, #env)") | ||
@PostMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/gray-del-releases") | ||
public OpenReleaseDTO createGrayDelRelease(@PathVariable String appId, @PathVariable String env, | ||
@PathVariable String clusterName, @PathVariable String namespaceName, | ||
@PathVariable String branchName, @RequestBody NamespaceGrayDelReleaseDTO model, | ||
HttpServletRequest request) { | ||
RequestPrecondition.checkArguments( | ||
!StringUtils.isContainEmpty(model.getReleasedBy(), model.getReleaseTitle()), | ||
"Params(releaseTitle and releasedBy) can not be empty"); | ||
RequestPrecondition.checkArguments(model.getGrayDelKeys() != null, | ||
"Params(grayDelKeys) can not be null"); | ||
|
||
if (userService.findByUserId(model.getReleasedBy()) == null) { | ||
throw BadRequestException.userNotExists(model.getReleasedBy()); | ||
} | ||
|
||
NamespaceGrayDelReleaseModel releaseModel = BeanUtils.transform( | ||
NamespaceGrayDelReleaseModel.class, model); | ||
releaseModel.setAppId(appId); | ||
releaseModel.setEnv(env.toUpperCase()); | ||
releaseModel.setClusterName(branchName); | ||
releaseModel.setNamespaceName(namespaceName); | ||
|
||
return OpenApiBeanUtils.transformFromReleaseDTO( | ||
releaseService.publish(releaseModel, releaseModel.getReleasedBy())); | ||
} | ||
|
||
Comment on lines
+171
to
+197
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing event publishing in @@ -193,6 +193,16 @@ public OpenReleaseDTO createGrayDelRelease(...) {
return OpenApiBeanUtils.transformFromReleaseDTO(
releaseService.publish(releaseModel, releaseModel.getReleasedBy()));
+
+ // Potential fix: Publish event similarly
+ // ConfigPublishEvent event = ConfigPublishEvent.instance();
+ // event.withAppId(appId)
+ // .withCluster(clusterName)
+ // .withNamespace(namespaceName)
+ // .withReleaseId(<INSERT RELEASE ID>)
+ // .setEnv(Env.valueOf(env))
+ // .setGrayPublishEvent(true);
+ // publisher.publishEvent(event);
}
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was no event emit when createGrayDelRelease in Portal There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @BlackBear2003 Yes, that's correct. The event emission is missing in the ✏️ Learnings added
If you found this review helpful, would you consider giving us a shout-out on X? |
||
@PutMapping(path = "/releases/{releaseId}/rollback") | ||
public void rollback(@PathVariable String env, | ||
@PathVariable long releaseId, @RequestParam String operator, HttpServletRequest request) { | ||
|
@@ -185,6 +215,16 @@ public void rollback(@PathVariable String env, | |
throw new AccessDeniedException("Forbidden operation. you don't have release permission"); | ||
} | ||
|
||
ConfigPublishEvent event = ConfigPublishEvent.instance(); | ||
event.withAppId(release.getAppId()) | ||
.withCluster(release.getClusterName()) | ||
.withNamespace(release.getNamespaceName()) | ||
.withReleaseId(release.getId()) | ||
.setRollbackEvent(true) | ||
.setEnv(Env.valueOf(env)); | ||
publisher.publishEvent(event); | ||
|
||
|
||
this.releaseOpenApiService.rollbackRelease(env, releaseId, operator); | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,8 @@ Apollo 2.4.0 | |
* [Feature support portal restTemplate Client connection pool config](https://github.com/apolloconfig/apollo/pull/5200) | ||
* [Feature added the ability for administrators to globally search for Value](https://github.com/apolloconfig/apollo/pull/5182) | ||
* [Feature support the observe status access-key for pre-check and logging only](https://github.com/apolloconfig/apollo/pull/5236) | ||
* [Feature support to assign users management authority by the cluster (modify, publish)](https://github.com/apolloconfig/apollo/pull/5302) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The changes-2.4.0.md will be updated when 2.4.0 is released. So please update the CHANGES.md instead. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed~ |
||
* [Feature support to notification by email when releasing by OpenApi also](https://github.com/apolloconfig/apollo/pull/5324) | ||
|
||
------------------ | ||
All issues and pull requests are [here](https://github.com/apolloconfig/apollo/milestone/15?closed=1) |
Uh oh!
There was an error while loading. Please reload this page.