Changes for issue #27 #48
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: gptme-bot | |
on: | |
issue_comment: | |
types: [created] | |
env: | |
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} | |
# Set permissions on GITHUB_TOKEN | |
# It seems we cannot set `workflows: write`, yet it's needed to allow modifying workflow files | |
#permissions: | |
# contents: write # push | |
# issues: write # comment | |
# pull-requests: write # create & comment | |
# actions: write # ? | |
# workflows: write # allow modifying workflow files | |
permissions: write-all | |
jobs: | |
check-comment: | |
runs-on: ubuntu-latest | |
outputs: | |
gptme_command: ${{ steps.detect_command.outputs.gptme_command }} | |
steps: | |
- name: Detect gptme command | |
id: detect_command | |
env: | |
COMMENT_BODY: ${{ github.event.comment.body }} | |
run: | | |
# Check if the comment starts with "@gptme" | |
if [[ "$COMMENT_BODY" == "@gptme "* ]]; then | |
# Extract the command | |
GPTME_COMMAND=${COMMENT_BODY#"@gptme "} | |
# Escape double quotes | |
# GPTME_COMMAND="${GPTME_COMMAND//\"/\\\"}" | |
# Set output | |
{ | |
echo "gptme_command<<EOFMAGIC" | |
echo $GPTME_COMMAND | |
echo "EOFMAGIC" | |
} >> $GITHUB_OUTPUT | |
fi | |
- name: Fail if author not on whitelist | |
if: steps.detect_command.outputs.gptme_command | |
run: | | |
WHITELIST=("ErikBjare") # Add your allowed usernames here | |
COMMENT_AUTHOR="${{ github.event.comment.user.login }}" | |
if [[ ! " ${WHITELIST[@]} " =~ " ${COMMENT_AUTHOR} " ]]; then | |
echo "Error: Author ${COMMENT_AUTHOR} is not on the whitelist." | |
exit 1 | |
else | |
echo "Author ${COMMENT_AUTHOR} is on the whitelist." | |
fi | |
- name: React to comment | |
env: | |
GITHUB_TOKEN: ${{ github.token }} | |
REPO_NAME: ${{ github.event.repository.name }} | |
USER_NAME: ${{ github.event.repository.owner.login }} | |
COMMENT_ID: ${{ github.event.comment.id }} | |
run: | | |
gh api /repos/$USER_NAME/$REPO_NAME/issues/comments/$COMMENT_ID/reactions -X POST -f content='+1' | |
execute-command: | |
needs: check-comment | |
if: needs.check-comment.outputs.gptme_command | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v3 | |
- name: Install ctags | |
run: sudo apt install universal-ctags | |
- name: Checkout PR branch if comment is on a PR | |
id: checkout_branch | |
env: | |
GITHUB_TOKEN: ${{ github.token }} | |
run: | | |
# Fetch details about the "issue" the comment is on | |
DATA=$(gh api /repos/${{ github.repository }}/issues/${{ github.event.issue.number }}) | |
# Extract whether this "issue" is a PR and | |
IS_PR=$(echo "$DATA" | jq -r .pull_request) | |
# If this is a PR, checkout its branch | |
if [[ "$IS_PR" != "null" ]]; then | |
# Fetch details about the PR the comment is on | |
DATA=$(gh api /repos/${{ github.repository }}/pulls/${{ github.event.issue.number }}) | |
# Get the PR's branch name | |
BRANCH_NAME=$(echo "$DATA" | jq -r .head.ref) | |
git fetch origin $BRANCH_NAME | |
git checkout $BRANCH_NAME | |
else | |
# Create a new branch and push changes | |
BRANCH_NAME="gptme-bot-changes-$(date +'%Y%m%d%H%M%S')" | |
git checkout -b $BRANCH_NAME | |
fi | |
echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT | |
- name: Install poetry | |
run: pipx install poetry | |
- name: Set up Python | |
uses: actions/setup-python@v4 | |
with: | |
python-version: '3.11' | |
cache: 'poetry' | |
- name: Install dependencies | |
run: | | |
make build | |
poetry install -E datascience | |
- name: Run gptme | |
env: | |
GITHUB_TOKEN: ${{ github.token }} | |
GPTME_COMMAND: ${{ needs.check-comment.outputs.gptme_command }} | |
ISSUE_NUMBER: ${{ github.event.issue.number }} | |
run: | | |
gh issue view $ISSUE_NUMBER > issue.md | |
gh issue view $ISSUE_NUMBER -c > comments.md | |
# install a shim that makes `git commit` a no-op (in case it would get that idea prematurely) | |
source scripts/git-shim.sh | |
# Run gptme with the extracted command and save logs | |
poetry run gptme --non-interactive "$GPTME_COMMAND" issue.md comments.md | |
# remove tmp files so that they do not get committed | |
rm issue.md comments.md | |
# stage changes | |
git add -A | |
- name: Read and format log | |
run: | | |
# Assuming the log file is located at ~/.local/share/gptme/logs/<conversation name>/conversation.jsonl | |
while IFS= read -r line; do | |
echo $(echo "$line" | jq -r '"\(.role): \(.content)"') | |
done < ~/.local/share/gptme/logs/*/conversation.jsonl > log.txt | |
- name: Generate commit message | |
run: | | |
# generate commit message | |
poetry run gptme --non-interactive "Run `git diff --staged`, then write a commit message for it to message.txt, following conventional commits. Don't commit." | |
- name: Commit, push, comment | |
env: | |
GITHUB_TOKEN: ${{ github.token }} | |
GPTME_COMMAND: ${{ needs.check-comment.outputs.gptme_command }} | |
ISSUE_NUMBER: ${{ github.event.issue.number }} | |
ISSUE_TYPE: ${{ github.event.issue.pull_request && 'pull_request' || 'issue' }} | |
REPO_NAME: ${{ github.event.repository.name }} | |
USER_NAME: ${{ github.event.repository.owner.login }} | |
BRANCH_NAME: ${{ steps.checkout_branch.outputs.branch_name }} | |
BRANCH_BASE: "master" | |
run: | | |
RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" | |
COMMENT_URL="https://github.com/${{ github.repository }}/issues/${{ github.event.issue.number }}#issuecomment-${{ github.event.comment.id }}" | |
COMMIT_MSG="\`gptme '$GPTME_COMMAND'\` | |
Triggered by: $COMMENT_URL | |
Run: $RUN_URL | |
<details> | |
<summary>Log</summary> | |
<pre>$(cat log.txt)</pre> | |
</details>" | |
git config user.name "gptme-bot" | |
git config user.email "[email protected]" | |
git commit -m "$COMMIT_MSG" | |
# Push changes to the PR branch | |
git push -u origin $BRANCH_NAME | |
if [[ $ISSUE_TYPE == "pull_request" ]]; then | |
# Comment on the PR | |
echo "Changes have been pushed to this pull request." | gh pr comment $ISSUE_NUMBER -R $USER_NAME/$REPO_NAME --body-file=- | |
else | |
# Some say this helps! https://github.com/cli/cli/issues/2691#issuecomment-1289521962 | |
sleep 1 | |
# Create a PR | |
PR_URL=$(gh pr create --title "Changes for issue #$ISSUE_NUMBER" --body "$COMMIT_MSG" --repo $USER_NAME/$REPO_NAME | grep -o 'https://github.com[^ ]*') | |
# These are redundant/implied: --base $BRANCH_BASE --head $USER_NAME:$BRANCH_NAME | |
# Comment on the issue with the PR link | |
echo "A pull request has been created for this issue: $PR_URL" | gh issue comment $ISSUE_NUMBER -R $USER_NAME/$REPO_NAME --body-file=- | |
fi | |
- name: Report error | |
if: failure() | |
env: | |
GITHUB_TOKEN: ${{ github.token }} | |
ISSUE_NUMBER: ${{ github.event.issue.number }} | |
REPO_NAME: ${{ github.event.repository.name }} | |
USER_NAME: ${{ github.event.repository.owner.login }} | |
run: | | |
# reply to the comment that we could not fulfill the request | |
RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" | |
MESSAGE="I'm sorry, I could not fulfill your request. Please check the [log of this run]($RUN_URL) for more information." | |
if [[ -f log.txt ]]; then | |
MESSAGE+=" | |
<details> | |
<summary>Conversation log</summary> | |
<pre>$(cat log.txt)</pre> | |
</details>" | |
fi | |
echo "$MESSAGE" | gh issue comment $ISSUE_NUMBER -R $USER_NAME/$REPO_NAME --body-file=- |