diff --git a/server/libs/modules/components/github/src/main/java/com/bytechef/component/github/GithubComponentHandler.java b/server/libs/modules/components/github/src/main/java/com/bytechef/component/github/GithubComponentHandler.java index 3407e089166..6d9a49d372b 100644 --- a/server/libs/modules/components/github/src/main/java/com/bytechef/component/github/GithubComponentHandler.java +++ b/server/libs/modules/components/github/src/main/java/com/bytechef/component/github/GithubComponentHandler.java @@ -23,14 +23,7 @@ import com.bytechef.component.ComponentHandler; import com.bytechef.component.definition.ComponentCategory; import com.bytechef.component.definition.ComponentDefinition; -import com.bytechef.component.github.action.GithubAddAssigneesToIssueAction; -import com.bytechef.component.github.action.GithubAddLabelsToIssueAction; -import com.bytechef.component.github.action.GithubCreateCommentOnIssueAction; -import com.bytechef.component.github.action.GithubCreateIssueAction; -import com.bytechef.component.github.action.GithubGetIssueAction; -import com.bytechef.component.github.action.GithubListIssuesAction; -import com.bytechef.component.github.action.GithubListRepositoryIssuesAction; -import com.bytechef.component.github.action.GithubStarRepositoryAction; +import com.bytechef.component.github.action.*; import com.bytechef.component.github.trigger.GithubNewIssueTrigger; import com.bytechef.component.github.trigger.GithubNewPullRequestTrigger; import com.google.auto.service.AutoService; @@ -65,7 +58,8 @@ public class GithubComponentHandler implements ComponentHandler { tool(GithubGetIssueAction.ACTION_DEFINITION), tool(GithubListIssuesAction.ACTION_DEFINITION), tool(GithubListRepositoryIssuesAction.ACTION_DEFINITION), - tool(GithubStarRepositoryAction.ACTION_DEFINITION)) + tool(GithubStarRepositoryAction.ACTION_DEFINITION), + tool(GitHubCreatePullRequestAction.ACTION_DEFINITION)) .triggers( GithubNewIssueTrigger.TRIGGER_DEFINITION, GithubNewPullRequestTrigger.TRIGGER_DEFINITION); diff --git a/server/libs/modules/components/github/src/main/java/com/bytechef/component/github/action/GitHubCreatePullRequestAction.java b/server/libs/modules/components/github/src/main/java/com/bytechef/component/github/action/GitHubCreatePullRequestAction.java new file mode 100644 index 00000000000..79dd5833fe8 --- /dev/null +++ b/server/libs/modules/components/github/src/main/java/com/bytechef/component/github/action/GitHubCreatePullRequestAction.java @@ -0,0 +1,99 @@ +/* + * Copyright 2025 ByteChef + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bytechef.component.github.action; + +import com.bytechef.component.definition.*; +import com.bytechef.component.github.util.GithubUtils; + +import java.util.Map; + +import static com.bytechef.component.definition.ComponentDsl.*; +import static com.bytechef.component.definition.Context.Http.responseType; +import static com.bytechef.component.github.constant.GithubConstants.*; +import static com.bytechef.component.github.util.GithubUtils.getOwnerName; + +/** + * @author Anas Elgarhy (@0x61nas) + */ +public class GitHubCreatePullRequestAction { + public static final ComponentDsl.ModifiableActionDefinition ACTION_DEFINITION = action("createPullRequest") + .title("Create Pull Request") + .description("Create Pull Request in GitHub Repository") + .properties( + string(REPOSITORY) + .label("Repository") + .description("Repository where new pull request will be created.") + .options((OptionsDataSource.ActionOptionsFunction) GithubUtils::getRepositoryOptions) + .required(true), + string(TITLE) + .label("Title") + .description("Title of the pull request.") + .maxLength(100) + .required(false), + string(BODY) + .label("Description") + .description("The description of the pull request.") + .required(false), + string(HEAD) + .label("Head") + .description("The name of the branch where your changes are implemented.") + .required(true), + string(HEAD_REPO) + .label("Head Repo") + .description("The name of the repository where the changes in the pull request were made.") + .required(false), + string(BASE) + .label("Base") + .description("The name of the branch you want the changes pulled into.") + .required(true), + integer(ISSUE) + .label("Issue") + .description("An issue in the repository to convert to a pull request.") + .required(false), + bool(DRAFT) + .label("Draft") + .description("Indicates whether the pull request is a draft.") + .defaultValue(false) + .required(true) + ) + .output(outputSchema(PULL_REQUEST_OUTPUT_PROBERTY)) + .perform(GitHubCreatePullRequestAction::perform); + + private GitHubCreatePullRequestAction() { + } + + public static Map perform( + Parameters inputParameters, Parameters connectionParameters, Context context) { + + return context + .http(http -> http.post( + "/repos/" + getOwnerName(context) + "/" + inputParameters.getRequiredString(REPOSITORY) + "/pulls")) + .body( + Context.Http.Body.of( + TITLE, inputParameters.getString(TITLE), + HEAD, inputParameters.getRequiredString(HEAD), + HEAD_REPO, inputParameters.getString(HEAD_REPO), + BASE, inputParameters.getRequiredString(BASE), + BODY, inputParameters.getString(BODY), + DRAFT, inputParameters.getBoolean(DRAFT), + ISSUE, inputParameters.getInteger(ISSUE))) + .configuration(responseType(Context.Http.ResponseType.JSON)) + .execute() + .getBody(new TypeReference<>() { + }); + } +} diff --git a/server/libs/modules/components/github/src/main/java/com/bytechef/component/github/constant/GithubConstants.java b/server/libs/modules/components/github/src/main/java/com/bytechef/component/github/constant/GithubConstants.java index 3df64dbf6c5..c89f5e224df 100644 --- a/server/libs/modules/components/github/src/main/java/com/bytechef/component/github/constant/GithubConstants.java +++ b/server/libs/modules/components/github/src/main/java/com/bytechef/component/github/constant/GithubConstants.java @@ -42,6 +42,10 @@ public class GithubConstants { public static final String REPOSITORY = "repository"; public static final String STATE = "state"; public static final String TITLE = "title"; + public static final String HEAD = "head"; + public static final String HEAD_REPO = "head_repo"; + public static final String BASE = "base"; + public static final String DRAFT = "draft"; public static final List> ISSUE_OUTPUT_PROPERTIES = List.of( string("url") @@ -108,6 +112,13 @@ public class GithubConstants { string("default_branch") .description("The name of the default branch in the repository, typically 'main' or 'master'.")); + public static final ModifiableObjectProperty PULL_REQUEST_OUTPUT_PROBERTY = object("pull_request") + .properties( + string("url") + .description("The URL of the created pull request."), + integer(ID) + .description("ID of the created pull request.")); + private GithubConstants() { } } diff --git a/server/libs/modules/components/github/src/test/java/com/bytechef/component/github/action/GitHubCreatePullRequestActionTest.java b/server/libs/modules/components/github/src/test/java/com/bytechef/component/github/action/GitHubCreatePullRequestActionTest.java new file mode 100644 index 00000000000..e079c185393 --- /dev/null +++ b/server/libs/modules/components/github/src/test/java/com/bytechef/component/github/action/GitHubCreatePullRequestActionTest.java @@ -0,0 +1,54 @@ +/* + * Copyright 2025 ByteChef + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bytechef.component.github.action; + +import com.bytechef.component.definition.Context; +import com.bytechef.component.definition.Parameters; +import com.bytechef.component.definition.TypeReference; +import com.bytechef.component.test.definition.MockParametersFactory; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static com.bytechef.component.github.constant.GithubConstants.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +/** + * @author Anas Elgarhy (@0x61nas) + */ +class GitHubCreatePullRequestActionTest extends AbstractGithubActionTest { + private final Map parameterMap = Map.of(TITLE, "name", HEAD, "feat/make-it-awesome", + HEAD_REPO, "happy-repo", BASE, "master", BODY, "description"); + private final Parameters mockedParameters = MockParametersFactory.create(parameterMap); + + @Test + void testPerform() { + when(mockedResponse.getBody(any(TypeReference.class))) + .thenReturn(responseMap); + + Map result = GitHubCreatePullRequestAction + .perform(mockedParameters, mockedParameters, mockedContext); + + assertEquals(responseMap, result); + + Context.Http.Body body = bodyArgumentCaptor.getValue(); + + assertEquals(parameterMap, body.getContent()); + } +}