mirror of https://github.com/halo-dev/halo
				
				
				
			fix: theme status phase is always FAILED even if version of Halo is satisfied (#3390)
#### What type of PR is this? /kind improvement /area core /milestone 2.3.x #### What this PR does / why we need it: 修复主题 requires 版本匹配后依然显示 FAILED 状态的问题 how to test it? 1. 安装一个主题后更新主题的 requires 为不匹配系统版本号,此时主题 status 会提示版本号不匹配的错误 2. 再更新 requires 为正确的,phase 会从 FAILED 变为 READY #### Which issue(s) this PR fixes: Fixes #3326 #### Does this PR introduce a user-facing change? ```release-note 修复主题状态显示不正确的问题 ```pull/3425/head
							parent
							
								
									166a440df1
								
							
						
					
					
						commit
						3146589d25
					
				| 
						 | 
				
			
			@ -6,8 +6,10 @@ import java.time.Instant;
 | 
			
		|||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
import org.apache.commons.lang3.ObjectUtils;
 | 
			
		||||
import org.apache.commons.lang3.StringUtils;
 | 
			
		||||
import org.springframework.retry.support.RetryTemplate;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
| 
						 | 
				
			
			@ -82,38 +84,40 @@ public class ThemeReconciler implements Reconciler<Request> {
 | 
			
		|||
            .build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void reconcileStatus(String name) {
 | 
			
		||||
    void reconcileStatus(String name) {
 | 
			
		||||
        client.fetch(Theme.class, name).ifPresent(theme -> {
 | 
			
		||||
            final Theme oldTheme = JsonUtils.deepCopy(theme);
 | 
			
		||||
            if (theme.getStatus() == null) {
 | 
			
		||||
                theme.setStatus(new Theme.ThemeStatus());
 | 
			
		||||
            }
 | 
			
		||||
            Theme.ThemeStatus status = theme.getStatus();
 | 
			
		||||
            final Theme.ThemeStatus status =
 | 
			
		||||
                ObjectUtils.defaultIfNull(theme.getStatus(), new Theme.ThemeStatus());
 | 
			
		||||
            final Theme.ThemeStatus oldStatus = JsonUtils.deepCopy(status);
 | 
			
		||||
            theme.setStatus(status);
 | 
			
		||||
 | 
			
		||||
            Path themePath = themePathPolicy.generate(theme);
 | 
			
		||||
            status.setLocation(themePath.toAbsolutePath().toString());
 | 
			
		||||
            if (status.getPhase() == null) {
 | 
			
		||||
                status.setPhase(Theme.ThemePhase.READY);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            status.setPhase(Theme.ThemePhase.READY);
 | 
			
		||||
            Condition.ConditionBuilder conditionBuilder = Condition.builder()
 | 
			
		||||
                .type(Theme.ThemePhase.READY.name())
 | 
			
		||||
                .status(ConditionStatus.TRUE)
 | 
			
		||||
                .reason(Theme.ThemePhase.READY.name())
 | 
			
		||||
                .message(StringUtils.EMPTY)
 | 
			
		||||
                .lastTransitionTime(Instant.now());
 | 
			
		||||
 | 
			
		||||
            // Check if this theme version is match requires param.
 | 
			
		||||
            String normalVersion = systemVersionSupplier.get().getNormalVersion();
 | 
			
		||||
            String requires = theme.getSpec().getRequires();
 | 
			
		||||
            if (!VersionUtils.satisfiesRequires(normalVersion, requires)) {
 | 
			
		||||
                status.setPhase(Theme.ThemePhase.FAILED);
 | 
			
		||||
                Condition condition = Condition.builder()
 | 
			
		||||
                conditionBuilder
 | 
			
		||||
                    .type(Theme.ThemePhase.FAILED.name())
 | 
			
		||||
                    .status(ConditionStatus.FALSE)
 | 
			
		||||
                    .reason("UnsatisfiedRequiresVersion")
 | 
			
		||||
                    .message(String.format(
 | 
			
		||||
                        "Theme requires a minimum system version of [%s], and you have [%s].",
 | 
			
		||||
                        requires, normalVersion))
 | 
			
		||||
                    .lastTransitionTime(Instant.now())
 | 
			
		||||
                    .build();
 | 
			
		||||
                Theme.nullSafeConditionList(theme).add(condition);
 | 
			
		||||
                        requires, normalVersion));
 | 
			
		||||
            }
 | 
			
		||||
            Theme.nullSafeConditionList(theme).addAndEvictFIFO(conditionBuilder.build());
 | 
			
		||||
 | 
			
		||||
            if (!oldTheme.equals(theme)) {
 | 
			
		||||
            if (!Objects.equals(oldStatus, status)) {
 | 
			
		||||
                client.update(theme);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -195,6 +195,38 @@ class ThemeReconcilerTest {
 | 
			
		|||
        verify(extensionClient, times(2)).fetch(eq(Setting.class), eq(settingName));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void reconcileStatus() {
 | 
			
		||||
        when(systemVersionSupplier.get()).thenReturn(Version.valueOf("2.3.0"));
 | 
			
		||||
        Path testWorkDir = tempDirectory.resolve("reconcile-delete");
 | 
			
		||||
        when(haloProperties.getWorkDir()).thenReturn(testWorkDir);
 | 
			
		||||
 | 
			
		||||
        final ThemeReconciler themeReconciler =
 | 
			
		||||
            new ThemeReconciler(extensionClient, haloProperties, systemVersionSupplier);
 | 
			
		||||
        Theme theme = fakeTheme();
 | 
			
		||||
        theme.setStatus(null);
 | 
			
		||||
        theme.getSpec().setRequires(">2.3.0");
 | 
			
		||||
        when(extensionClient.fetch(eq(Theme.class), eq("fake-theme")))
 | 
			
		||||
            .thenReturn(Optional.of(theme));
 | 
			
		||||
        themeReconciler.reconcileStatus("fake-theme");
 | 
			
		||||
        ArgumentCaptor<Theme> themeUpdateCaptor = ArgumentCaptor.forClass(Theme.class);
 | 
			
		||||
        verify(extensionClient).update(themeUpdateCaptor.capture());
 | 
			
		||||
        Theme value = themeUpdateCaptor.getValue();
 | 
			
		||||
        assertThat(value.getStatus()).isNotNull();
 | 
			
		||||
        assertThat(value.getStatus().getConditions().peekFirst().getType())
 | 
			
		||||
            .isEqualTo(Theme.ThemePhase.FAILED.name());
 | 
			
		||||
        assertThat(value.getStatus().getPhase())
 | 
			
		||||
            .isEqualTo(Theme.ThemePhase.FAILED);
 | 
			
		||||
 | 
			
		||||
        theme.getSpec().setRequires(">=2.3.0");
 | 
			
		||||
        when(extensionClient.fetch(eq(Theme.class), eq("fake-theme")))
 | 
			
		||||
            .thenReturn(Optional.of(theme));
 | 
			
		||||
        themeReconciler.reconcileStatus("fake-theme");
 | 
			
		||||
        verify(extensionClient, times(2)).update(themeUpdateCaptor.capture());
 | 
			
		||||
        assertThat(themeUpdateCaptor.getValue().getStatus().getPhase())
 | 
			
		||||
            .isEqualTo(Theme.ThemePhase.READY);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Theme fakeTheme() {
 | 
			
		||||
        Theme theme = new Theme();
 | 
			
		||||
        Metadata metadata = new Metadata();
 | 
			
		||||
| 
						 | 
				
			
			@ -206,7 +238,7 @@ class ThemeReconcilerTest {
 | 
			
		|||
        Theme.ThemeSpec themeSpec = new Theme.ThemeSpec();
 | 
			
		||||
        themeSpec.setSettingName("theme-test-setting");
 | 
			
		||||
        theme.setSpec(themeSpec);
 | 
			
		||||
        when(extensionClient.fetch(eq(Theme.class), eq(metadata.getName())))
 | 
			
		||||
        lenient().when(extensionClient.fetch(eq(Theme.class), eq(metadata.getName())))
 | 
			
		||||
            .thenReturn(Optional.of(theme));
 | 
			
		||||
        return theme;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue