From dfd0904da6f783d151210a68184b4939fffa656e Mon Sep 17 00:00:00 2001 From: gy2006 <32008001@qq.com> Date: Mon, 6 Jan 2025 21:20:28 +0800 Subject: [PATCH] trigger new build --- .../flowci/build/business/CreateBuild.java | 8 ++ .../flowci/build/business/CreateNewBuild.java | 16 ---- .../build/business/FetchYamlFromGit.java | 7 ++ .../flowci/build/business/WaitForAgent.java | 5 ++ ...NewBuildImpl.java => CreateBuildImpl.java} | 7 +- .../business/impl/FetchYamlFromGitImpl.java | 13 ++++ .../build/business/impl/TriggerBuildImpl.java | 18 ++--- .../build/business/impl/WaitForAgentImpl.java | 19 +++++ .../java/com/flowci/build/model/Build.java | 6 +- .../com/flowci/build/model/BuildYaml.java | 3 +- .../java/com/flowci/build/model/GitRef.java | 11 +++ .../java/com/flowci/build/repo/BuildRepo.java | 8 ++ src/main/resources/db/migration/V1__Init.sql | 2 +- .../build/business/CreateBuildTest.java | 74 +++++++++++++++++++ .../com/flowci/build/repo/BuildRepoTest.java | 21 +++++- 15 files changed, 183 insertions(+), 35 deletions(-) create mode 100644 src/main/java/com/flowci/build/business/CreateBuild.java delete mode 100644 src/main/java/com/flowci/build/business/CreateNewBuild.java create mode 100644 src/main/java/com/flowci/build/business/FetchYamlFromGit.java create mode 100644 src/main/java/com/flowci/build/business/WaitForAgent.java rename src/main/java/com/flowci/build/business/impl/{CreateNewBuildImpl.java => CreateBuildImpl.java} (92%) create mode 100644 src/main/java/com/flowci/build/business/impl/FetchYamlFromGitImpl.java create mode 100644 src/main/java/com/flowci/build/business/impl/WaitForAgentImpl.java create mode 100644 src/main/java/com/flowci/build/model/GitRef.java create mode 100644 src/test/java/com/flowci/build/business/CreateBuildTest.java diff --git a/src/main/java/com/flowci/build/business/CreateBuild.java b/src/main/java/com/flowci/build/business/CreateBuild.java new file mode 100644 index 000000000..700c7f7b5 --- /dev/null +++ b/src/main/java/com/flowci/build/business/CreateBuild.java @@ -0,0 +1,8 @@ +package com.flowci.build.business; + +import com.flowci.build.model.Build; +import com.flowci.common.model.Variables; + +public interface CreateBuild { + Build invoke(Long flowId, Build.Trigger trigger, Variables inputs); +} diff --git a/src/main/java/com/flowci/build/business/CreateNewBuild.java b/src/main/java/com/flowci/build/business/CreateNewBuild.java deleted file mode 100644 index fe7dcde3e..000000000 --- a/src/main/java/com/flowci/build/business/CreateNewBuild.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.flowci.build.business; - -import com.flowci.build.model.Build; -import com.flowci.common.model.Variables; - -public interface CreateNewBuild { - /** - * Trigger a new build - * - * @param flowId flow id - * @param trigger trigger - * @param inputs extra variables - * @return build object - */ - Build invoke(Long flowId, Build.Trigger trigger, Variables inputs); -} diff --git a/src/main/java/com/flowci/build/business/FetchYamlFromGit.java b/src/main/java/com/flowci/build/business/FetchYamlFromGit.java new file mode 100644 index 000000000..b525abdb2 --- /dev/null +++ b/src/main/java/com/flowci/build/business/FetchYamlFromGit.java @@ -0,0 +1,7 @@ +package com.flowci.build.business; + +import com.flowci.build.model.Build; + +public interface FetchYamlFromGit { + void invoke(Build build); +} diff --git a/src/main/java/com/flowci/build/business/WaitForAgent.java b/src/main/java/com/flowci/build/business/WaitForAgent.java new file mode 100644 index 000000000..5494e5aea --- /dev/null +++ b/src/main/java/com/flowci/build/business/WaitForAgent.java @@ -0,0 +1,5 @@ +package com.flowci.build.business; + +public interface WaitForAgent { + void invoke(Long buildId); +} diff --git a/src/main/java/com/flowci/build/business/impl/CreateNewBuildImpl.java b/src/main/java/com/flowci/build/business/impl/CreateBuildImpl.java similarity index 92% rename from src/main/java/com/flowci/build/business/impl/CreateNewBuildImpl.java rename to src/main/java/com/flowci/build/business/impl/CreateBuildImpl.java index 4cbb8c423..b728e729f 100644 --- a/src/main/java/com/flowci/build/business/impl/CreateNewBuildImpl.java +++ b/src/main/java/com/flowci/build/business/impl/CreateBuildImpl.java @@ -1,6 +1,7 @@ package com.flowci.build.business.impl; -import com.flowci.build.business.CreateNewBuild; +import com.flowci.build.business.CreateBuild; +import com.flowci.build.business.TriggerBuild; import com.flowci.build.model.Build; import com.flowci.build.model.BuildYaml; import com.flowci.build.repo.BuildRepo; @@ -22,7 +23,7 @@ @Slf4j @Component @AllArgsConstructor -public class CreateNewBuildImpl implements CreateNewBuild { +public class CreateBuildImpl implements CreateBuild { private final FetchFlow fetchFlow; private final FetchFlowYamlContent fetchFlowYamlContent; @@ -43,7 +44,7 @@ public Build invoke(Long flowId, Build.Trigger trigger, Variables inputs) { : new HashSet<>(yamlObj.getAgents()); var build = new Build(); - build.setFlowId(flowId); + build.setFlowId(flow.getId()); build.setTrigger(trigger); build.setStatus(Build.Status.CREATED); build.setAgentTags(agentTags.toArray(new String[0])); diff --git a/src/main/java/com/flowci/build/business/impl/FetchYamlFromGitImpl.java b/src/main/java/com/flowci/build/business/impl/FetchYamlFromGitImpl.java new file mode 100644 index 000000000..c0b885bb6 --- /dev/null +++ b/src/main/java/com/flowci/build/business/impl/FetchYamlFromGitImpl.java @@ -0,0 +1,13 @@ +package com.flowci.build.business.impl; + +import com.flowci.build.business.FetchYamlFromGit; +import com.flowci.build.model.Build; +import org.springframework.stereotype.Component; + +@Component +public class FetchYamlFromGitImpl implements FetchYamlFromGit { + @Override + public void invoke(Build build) { + // TODO: + } +} diff --git a/src/main/java/com/flowci/build/business/impl/TriggerBuildImpl.java b/src/main/java/com/flowci/build/business/impl/TriggerBuildImpl.java index 785e97dc8..1f3fc2922 100644 --- a/src/main/java/com/flowci/build/business/impl/TriggerBuildImpl.java +++ b/src/main/java/com/flowci/build/business/impl/TriggerBuildImpl.java @@ -1,26 +1,26 @@ package com.flowci.build.business.impl; -import com.flowci.build.business.CreateNewBuild; +import com.flowci.build.business.CreateBuild; import com.flowci.build.business.TriggerBuild; +import com.flowci.build.business.WaitForAgent; import com.flowci.build.model.Build; import com.flowci.common.model.Variables; import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; -@Slf4j @Component @AllArgsConstructor public class TriggerBuildImpl implements TriggerBuild { - private final CreateNewBuild createNewBuild; + private final CreateBuild createBuild; + private final WaitForAgent waitForAgent; @Override + @Transactional public Build invoke(Long flowId, Build.Trigger trigger, Variables inputs) { - var build = createNewBuild.invoke(flowId, trigger, inputs); - - // put to queue, and wait - - return null; + var build = createBuild.invoke(flowId, trigger, inputs); + waitForAgent.invoke(build.getId()); + return build; } } diff --git a/src/main/java/com/flowci/build/business/impl/WaitForAgentImpl.java b/src/main/java/com/flowci/build/business/impl/WaitForAgentImpl.java new file mode 100644 index 000000000..a915bd1fd --- /dev/null +++ b/src/main/java/com/flowci/build/business/impl/WaitForAgentImpl.java @@ -0,0 +1,19 @@ +package com.flowci.build.business.impl; + +import com.flowci.build.business.WaitForAgent; +import com.flowci.build.model.Build; +import com.flowci.build.repo.BuildRepo; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Component; + +@Component +@AllArgsConstructor +public class WaitForAgentImpl implements WaitForAgent { + + private final BuildRepo buildRepo; + + @Override + public void invoke(Long buildId) { + buildRepo.updateBuildStatusById(buildId, Build.Status.QUEUED); + } +} diff --git a/src/main/java/com/flowci/build/model/Build.java b/src/main/java/com/flowci/build/model/Build.java index b6b8087b8..7588c7629 100644 --- a/src/main/java/com/flowci/build/model/Build.java +++ b/src/main/java/com/flowci/build/model/Build.java @@ -2,11 +2,13 @@ import com.flowci.common.model.EntityBase; import io.hypersistence.utils.hibernate.type.array.StringArrayType; +import io.hypersistence.utils.hibernate.type.json.JsonType; import jakarta.annotation.Nullable; import jakarta.persistence.*; import lombok.Data; import lombok.EqualsAndHashCode; import org.hibernate.annotations.Generated; +import org.hibernate.annotations.Type; import org.hibernate.generator.EventType; import java.util.Set; @@ -78,8 +80,8 @@ public enum Status { @org.hibernate.annotations.Type(StringArrayType.class) private String[] agentTags; - @Nullable - private String commitHash; + @Type(JsonType.class) + private GitRef gitRef; /** * Assigned agent id diff --git a/src/main/java/com/flowci/build/model/BuildYaml.java b/src/main/java/com/flowci/build/model/BuildYaml.java index 9f410d09e..0baac7f2f 100644 --- a/src/main/java/com/flowci/build/model/BuildYaml.java +++ b/src/main/java/com/flowci/build/model/BuildYaml.java @@ -3,7 +3,6 @@ import com.flowci.common.model.EntityBase; import com.flowci.common.model.Variables; import io.hypersistence.utils.hibernate.type.json.JsonType; -import jakarta.persistence.Convert; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Table; @@ -20,7 +19,7 @@ public class BuildYaml extends EntityBase { @Id private Long id; - // ref to flow variables + // ref to flow variables and extra inputs @Type(JsonType.class) private Variables variables; diff --git a/src/main/java/com/flowci/build/model/GitRef.java b/src/main/java/com/flowci/build/model/GitRef.java new file mode 100644 index 000000000..5ceba573a --- /dev/null +++ b/src/main/java/com/flowci/build/model/GitRef.java @@ -0,0 +1,11 @@ +package com.flowci.build.model; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class GitRef { + + private String commitHash; +} diff --git a/src/main/java/com/flowci/build/repo/BuildRepo.java b/src/main/java/com/flowci/build/repo/BuildRepo.java index 33676a4e8..30cd9207d 100644 --- a/src/main/java/com/flowci/build/repo/BuildRepo.java +++ b/src/main/java/com/flowci/build/repo/BuildRepo.java @@ -2,8 +2,16 @@ import com.flowci.build.model.Build; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; @Repository public interface BuildRepo extends JpaRepository { + + @Transactional + @Modifying(clearAutomatically = true, flushAutomatically = true) + @Query("update Build b set b.status = ?2 where b.id= ?1") + void updateBuildStatusById(Long buildId, Build.Status status); } diff --git a/src/main/resources/db/migration/V1__Init.sql b/src/main/resources/db/migration/V1__Init.sql index 11502ff2b..2dc3ccf86 100644 --- a/src/main/resources/db/migration/V1__Init.sql +++ b/src/main/resources/db/migration/V1__Init.sql @@ -51,7 +51,7 @@ CREATE TABLE build trigger varchar(20) NOT NULL, status varchar(20) NOT NULL, agent_tags varchar(20)[] NOT NULL, - commit_hash varchar(40), + git_ref json, agent_id BIGINT, created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL, created_by BIGINT, diff --git a/src/test/java/com/flowci/build/business/CreateBuildTest.java b/src/test/java/com/flowci/build/business/CreateBuildTest.java new file mode 100644 index 000000000..22c9a1c16 --- /dev/null +++ b/src/test/java/com/flowci/build/business/CreateBuildTest.java @@ -0,0 +1,74 @@ +package com.flowci.build.business; + +import com.flowci.SpringTest; +import com.flowci.build.model.Build; +import com.flowci.build.model.BuildYaml; +import com.flowci.common.model.Variables; +import com.flowci.flow.business.FetchFlow; +import com.flowci.flow.business.FetchFlowYamlContent; +import com.flowci.flow.model.Flow; +import com.flowci.flow.model.FlowYaml; +import com.flowci.yaml.business.ParseYamlV2; +import com.flowci.yaml.model.FlowV2; +import org.instancio.Instancio; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; + +import static com.flowci.TestUtils.newDummyInstance; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +class CreateBuildTest extends SpringTest { + + @MockBean + private FetchFlow fetchFlow; + + @MockBean + private FetchFlowYamlContent fetchFlowYamlContent; + + @MockBean + private ParseYamlV2 parseYamlV2; + + @Autowired + private MockRepositoriesConfig mockRepositoriesConfig; + + @Autowired + private CreateBuild createBuild; + + @Test + void givenFlow_whenCreating_thenBuildIsCreated() { + var mockFlow = newDummyInstance(Flow.class).create(); + when(fetchFlow.invoke(anyLong())).thenReturn(mockFlow); + var mockFlowYaml = newDummyInstance(FlowYaml.class).create(); + when(fetchFlowYamlContent.invoke(anyLong())).thenReturn(mockFlowYaml.getYaml()); + when(parseYamlV2.invoke(anyString())).thenReturn(Instancio.of(FlowV2.class).create()); + + var mockBuildRepo = mockRepositoriesConfig.getBuildRepo(); + var buildCaptor = ArgumentCaptor.forClass(Build.class); + when(mockBuildRepo.save(buildCaptor.capture())) + .thenAnswer(opt -> opt.getArgument(0)); + + var mockBuildYamlRepo = mockRepositoriesConfig.getBuildYamlRepo(); + var buildYamlCaptor = ArgumentCaptor.forClass(BuildYaml.class); + when(mockBuildYamlRepo.save(buildYamlCaptor.capture())) + .thenAnswer(opt -> opt.getArgument(0)); + + var inputs = new Variables(); + inputs.put("v1", "hello"); + inputs.put("v2", "world"); + createBuild.invoke(1L, Build.Trigger.API, inputs); + + var build = buildCaptor.getValue(); + assertEquals(mockFlow.getId(), build.getFlowId()); + assertEquals(Build.Trigger.API, build.getTrigger()); + + var buildYaml = buildYamlCaptor.getValue(); + assertEquals("hello", buildYaml.getVariables().get("v1")); + assertEquals("world", buildYaml.getVariables().get("v2")); + assertEquals(mockFlowYaml.getYaml(), buildYaml.getYaml()); + } +} diff --git a/src/test/java/com/flowci/build/repo/BuildRepoTest.java b/src/test/java/com/flowci/build/repo/BuildRepoTest.java index 270f5cabf..77394706e 100644 --- a/src/test/java/com/flowci/build/repo/BuildRepoTest.java +++ b/src/test/java/com/flowci/build/repo/BuildRepoTest.java @@ -1,6 +1,5 @@ package com.flowci.build.repo; - import com.flowci.SpringTestWithDB; import com.flowci.build.model.Build; import org.junit.jupiter.api.Test; @@ -8,6 +7,7 @@ import static com.flowci.TestUtils.newDummyInstance; import static org.instancio.Select.field; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; class BuildRepoTest extends SpringTestWithDB { @@ -29,6 +29,23 @@ void givenBuild_whenSaving_thenBuildIsSaved() { var saved = buildRepo.save(build); assertNotNull(saved.getBuildDate()); assertNotNull(saved.getBuildSequence()); - assertNotNull(saved.getBuildSequence()); + } + + @Test + void giveBuild_whenUpdateStatus_thenStatusIsUpdated() { + var mockFlowId = 100L; + var build = newDummyInstance(Build.class) + .set(field(Build::getFlowId), mockFlowId) + .ignore(field(Build::getId)) + .ignore(field(Build::getBuildDate)) + .ignore(field(Build::getBuildSequence)) + .ignore(field(Build::getBuildAlias)) + .create(); + + var saved = buildRepo.save(build); + assertNotNull(saved.getId()); + + buildRepo.updateBuildStatusById(saved.getId(), Build.Status.SUCCESS); + assertEquals(Build.Status.SUCCESS, buildRepo.findById(saved.getId()).get().getStatus()); } }