From 8f1bf22c6830359b2b95238377884be7ff2a3f23 Mon Sep 17 00:00:00 2001 From: Yuri V Date: Fri, 18 Oct 2024 21:36:31 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=89=20Initial=20project=20setup=20with?= =?UTF-8?q?=20GitHub=20Action=20configuration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit sets up the foundation for the Auto PR from Dev to Default Branch GitHub Action. Here's what's included: - ๐Ÿ“ Added README.md with comprehensive project documentation - โš™๏ธ Created action.yml to define the GitHub Action workflow - ๐Ÿ“œ Included MIT License for the project - ๐Ÿ™ˆ Set up .gitignore to exclude the diff/ directory Key features of the GitHub Action: - ๐Ÿ”„ Automatically creates or updates PRs from dev to default branch - ๐Ÿค– Generates PR descriptions using OpenAI API - ๐Ÿ‘ฅ Adds relevant reviewers to the PR - ๐Ÿ“… Sets PR title with the current date The action is configured to use OpenAI's API for generating descriptive PR content and includes steps for checking out the repository, setting up Git, determining the default branch, generating diffs, and managing pull requests. Next steps: - ๐Ÿ”‘ Set up OPENAI_API_KEY secret in repository settings - ๐Ÿงช Test the action in a real workflow - ๐Ÿ“š Update usage instructions with the correct GitHub username/organization --- .gitignore | 2 + LICENSE | 21 ++++++ README.md | 65 +++++++++++++++++ action.yml | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 298 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 action.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1590180 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +diff/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..99f9f9c --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 [Yuri V] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..74f2366 --- /dev/null +++ b/README.md @@ -0,0 +1,65 @@ +# Auto PR from Dev to Default Branch + +## Description + +This GitHub Action automatically creates or updates a Pull Request from a development branch to the default branch, generates descriptive PR content using OpenAI's API, and adds relevant reviewers. + +## Features + +- ๐Ÿ”„ Automatically creates or updates a PR from dev to the default branch +- ๐Ÿค– Generates PR descriptions using OpenAI API +- ๐Ÿ‘ฅ Automatically adds relevant reviewers +- ๐Ÿ“… Sets PR title with current date (e.g., "Release v2023.05.25") + +## Inputs + +| Name | Description | Required | Default | +|------|-------------|----------|---------| +| `openai_api_key` | OpenAI API Key | Yes | N/A | +| `github_token` | GitHub Personal Access Token with repo permissions | Yes | N/A | +| `dev_branch` | Name of the development branch | No | 'dev' | + +## Outputs + +| Name | Description | +|------|-------------| +| `pr_number` | The number of the pull request created or updated | + +## Usage + +To use this action in your workflow, add the following step: + +```yaml +- name: Auto PR from Dev to Default + uses: your-github-username/auto-pr-action@v1 + with: + openai_api_key: ${{ secrets.OPENAI_API_KEY }} + github_token: ${{ secrets.GITHUB_TOKEN }} + dev_branch: dev # Optional, defaults to 'dev' +``` + +Make sure to set up the `OPENAI_API_KEY` secret in your repository settings. + +## How it works + +1. Checks out the repository +2. Sets up Git configuration +3. Determines the default branch +4. Generates a diff between the dev and default branches +5. Uses OpenAI API to generate a descriptive PR content +6. Creates a new PR or updates an existing one +7. Adds relevant reviewers to the PR + +## License + +[MIT License](LICENSE) + +## Contributing + +Contributions are welcome! Please feel free to submit a Pull Request. + +This README.md provides an overview of your GitHub Action, including its features, inputs, outputs, and usage instructions. It also briefly explains how the action works and includes sections for licensing and contributions. + +You may want to adjust the "Usage" section to reflect the correct GitHub username or organization where this action will be published. Also, if you haven't already, you might want to add a LICENSE file to your repository. + +Feel free to modify this README to better fit your project's specific needs or to add any additional information you think would be helpful for users of your GitHub Action. diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..898b8d3 --- /dev/null +++ b/action.yml @@ -0,0 +1,210 @@ +# action.yml + +name: 'Auto PR from dev to default' +description: 'Creates or updates a PR from dev to the default branch, generates descriptions using OpenAI API, and adds reviewers.' +author: 'Your Name' +inputs: + openai_api_key: + description: 'OpenAI API Key' + required: true + github_token: + description: 'GitHub (PAT) token with repo permissions' + required: true + dev_branch: + description: 'Development branch name' + required: false + default: 'dev' +outputs: + pr_number: + description: 'The number of the pull request created or updated' +runs: + using: 'composite' + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ inputs.dev_branch }} + + - name: Set up Git + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + + - name: Get the default branch + id: get_default_branch + shell: bash + run: | + default_branch=$(git remote show origin | grep 'HEAD branch' | awk '{print $NF}') + echo "branch=${default_branch}" >> $GITHUB_OUTPUT + + - name: Get the diff using custom script + id: get_diff + shell: bash + run: | + set -e + branch_from="${{ steps.get_default_branch.outputs.branch }}" + branch_to="${{ inputs.dev_branch }}" + echo "Branch from: $branch_from" + echo "Branch to: $branch_to" + + git fetch --all + + mkdir -p diff + output_file="diff/${branch_from:-main}-${branch_to}_$(date +'%Y%m%d_%H%M').diff" + echo "Output file: $output_file" + + { + echo "Commits between $branch_from and $branch_to:" + echo "============================================" + git log origin/"$branch_from"..origin/"$branch_to" || echo "No commits found" + echo "--------------------------------------------" + echo "Git diff between $branch_from and $branch_to" + echo "============================================" + git diff origin/"$branch_from" origin/"$branch_to" || echo "No differences found" + } > "$output_file" + + if [ -s "$output_file" ]; then + echo "diff_output<> $GITHUB_OUTPUT + cat "$output_file" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + else + echo "diff_output=No changes detected between $branch_from and $branch_to" >> $GITHUB_OUTPUT + fi + + - name: Generate release description using OpenAI API + id: generate_release_notes + env: + OPENAI_API_KEY: ${{ inputs.openai_api_key }} + DIFF_OUTPUT: ${{ steps.get_diff.outputs.diff_output }} + shell: bash + run: | + prompt="**Instructions:**\n\nPlease generate a **Pull Request description** for the provided diff, following these guidelines:\n- Add appropriate emojis to the description.\n- Do **not** include the words \"Title\" and \"Description\" in your output.\n- Format your answer in **Markdown**." + + escaped_prompt=$(echo "$prompt" | jq -Rs .) + escaped_diff=$(echo "$DIFF_OUTPUT" | jq -Rs .) + + response=$(curl -s -X POST https://api.openai.com/v1/chat/completions \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $OPENAI_API_KEY" \ + -d "{ + \"model\": \"gpt-4o-mini\", + \"messages\": [ + { + \"role\": \"system\", + \"content\": ${escaped_prompt} + }, + { + \"role\": \"user\", + \"content\": ${escaped_diff} + } + ], + \"temperature\": 1, + \"max_tokens\": 2048, + \"top_p\": 1, + \"frequency_penalty\": 0, + \"presence_penalty\": 0 + }") + + description=$(echo "$response" | jq -r '.choices[0].message.content') + echo "description<> $GITHUB_OUTPUT + echo "$description" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + - name: Set Release Title + id: set_release_title + shell: bash + run: | + echo "title=Release v$(date +'%Y.%m.%d')" >> $GITHUB_OUTPUT + + - name: Create or Update Pull Request and Add Reviewers + id: create_pr + uses: actions/github-script@v6 + with: + github-token: ${{ inputs.github_token }} + script: | + const owner = context.repo.owner; + const repo = context.repo.repo; + const head = '${{ inputs.dev_branch }}'; + const base = '${{ steps.get_default_branch.outputs.branch }}'; + const title = '${{ steps.set_release_title.outputs.title }}'; + const body = `${{ steps.generate_release_notes.outputs.description }}`; + + // Check if PR from dev to default branch already exists + const { data: pulls } = await github.rest.pulls.list({ + owner: owner, + repo: repo, + head: `${owner}:${head}`, + base: base, + state: 'open', + }); + + let prNumber; + let prAuthor; + if (pulls.length > 0) { + prNumber = pulls[0].number; + prAuthor = pulls[0].user.login; + console.log(`Updating existing PR #${prNumber}`); + await github.rest.pulls.update({ + owner: owner, + repo: repo, + pull_number: prNumber, + title: title, + body: body, + }); + } else { + console.log('Creating new PR'); + const { data: pr } = await github.rest.pulls.create({ + owner: owner, + repo: repo, + head: head, + base: base, + title: title, + body: body, + }); + prNumber = pr.number; + prAuthor = pr.user.login; + } + + // Now, add reviewers + // First, get the list of committers to this PR + const { data: commits } = await github.rest.pulls.listCommits({ + owner: owner, + repo: repo, + pull_number: prNumber, + }); + + const committersSet = new Set(); + for (const commit of commits) { + if (commit.author && commit.author.login) { + committersSet.add(commit.author.login); + } + } + + // Add the repo owner + committersSet.add(owner); + + // Remove the PR author from reviewers + committersSet.delete(prAuthor); + + // Remove the bot user (if present) + const botUser = 'github-actions[bot]'; + committersSet.delete(botUser); + + // Convert set to array + const reviewers = Array.from(committersSet); + + console.log(`Adding reviewers: ${reviewers.join(', ')}`); + + if (reviewers.length > 0) { + // Add reviewers to the PR + await github.rest.pulls.requestReviewers({ + owner: owner, + repo: repo, + pull_number: prNumber, + reviewers: reviewers, + }); + } else { + console.log('No reviewers to add.'); + } + + core.setOutput('pr_number', prNumber);