ci: started working on composite action for gptme-bot, generated basic docs #53
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 | |
if: steps.detect_command.outputs.gptme_command | |
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 | |
# strip long <details>...</details> from issue.md and comments.md | |
perl -0777 -i -pe 's/\n<details>.*?<\/details>//sg' issue.md | |
perl -0777 -i -pe 's/\n<details>.*?<\/details>//sg' 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: 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: | | |
# Read and format log | |
./scripts/format_log.sh ~/.local/share/gptme/logs/*/conversation.jsonl > log.txt | |
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 message & description | |
COMMIT_MSG="$(cat message.txt || echo 'no commit message')" | |
COMMIT_DESC="\`gptme '$GPTME_COMMAND'\` | |
Triggered by: $COMMENT_URL | |
Run: $RUN_URL" | |
# commit message with description | |
COMMIT_MSG_FULL="$COMMIT_MSG | |
$COMMIT_DESC" | |
# commit message with description and log | |
COMMIT_MSG_FULL_WITH_LOG="$COMMIT_MSG_FULL | |
<details> | |
<summary>Log</summary> | |
<pre>$(cat log.txt || echo 'could not get log')</pre> | |
</details>" | |
git config user.name "gptme-bot" | |
git config user.email "[email protected]" | |
git commit -m "$COMMIT_MSG_FULL" | |
# 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 "$COMMIT_MSG" --body "$COMMIT_MSG_FULL_WITH_LOG" --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=- |