Nothing
#' Commit changes using an auto-generated commit message
#'
#' An R wrapper to automatically add, commit, and push changes
#' to a git repository using an auto-generated commit message. The commit
#' message is generated by an API call to the 'OpenAI' 'GPT-3.5 Turbo' model
#' using the git diff output as input.
#'
#' @param commit_message A custom commit message. If not provided, a message
#' will be generated automatically.
#' @param prepend A string to prepend to the commit message. Defaults to an
#' empty string. A convention may
#' be to prepend 'GPT: ' to the beginning of the commit message so you can
#' differentiate between those you wrote vs those GPT composed.
#' @return No return value, called for side effects.
#' @export
#' @examples
#' \dontrun{
#' # Simple command to git add, git commit, and git push with a commit
#' # message based on git diff of the working directory
#' commit()
#' }
#'
commit <- function(commit_message, prepend) { # alias commit_GPT() commit_message
# Work out which OS
os <- Sys.info()['sysname']
# Take git diff
git_diff_output <- generate_git_diff_output()
# Encode it
encoded_git_diff_output <- generate_encoded_git_diff_output(git_diff_output)
# Make commit message
encoded_git_diff_output <- substr(encoded_git_diff_output, 1, 4000)
if(missing(commit_message)) { commit_message <- generate_commit_message(encoded_git_diff_output) }
# Add, commit and push
# sink("/dev/null")
# on.exit(sink())
add_commit_push(commit_message)
# if(exists("output")) { output }
}
#' Generate git diff output
#'
#' Returns the git diff output for the current working directory, and lists
#' any new files found.
#' It checks the system's OS and executes the appropriate command to generate
#' the git diff.
#'
#' @return A character vector containing the git diff output.
#' @export
#' @examples
#' \dontrun{
#' # View with cat() for easier reading
#' cat(generate_git_diff_output())
#' }
generate_git_diff_output <- function() {
# See: https://r-pkgs.org/misc.html#sec-misc-inst
windows_script_path <- system.file("git_diff_and_new_files.bat", package = "gitGPT")
nix_script_path <- system.file("git_diff_and_new_files.sh", package = "gitGPT")
os <- Sys.info()['sysname']
if(os == "Windows") {
git_diff_output <- paste0(system2(windows_script_path, stdout = TRUE), collapse = "\n")
} else {
git_diff_and_new_files <- paste0(
readLines(nix_script_path),
collapse = "\n")
git_diff_output <- paste0(system(git_diff_and_new_files, intern = TRUE), collapse = "\n")
}
git_diff_output
}
#' Encode git diff output
#'
#' Takes the git diff output and encodes it for use in the API
#' call to the 'OpenAI' 'GPT-3.5 Turbo' model.
#'
#' @param git_diff_output A character vector containing the git diff output.
#' @return A character vector containing the URL-encoded git diff output.
#' @export
#' @examples
#' \dontrun{
#' git_diff_output <- generate_git_diff_output()
#' generate_encoded_git_diff_output(git_diff_output)
#' }
generate_encoded_git_diff_output <- function(git_diff_output) {
utils::URLencode(git_diff_output)
}
#' Generate commit message
#'
#' Generates a commit message by making an API call to the 'OpenAI'
#' 'GPT-3.5 Turbo' model using the
#' encoded git diff output as input.
#'
#' @param encoded_git_diff_output A character vector containing the URL-encoded
#' git diff output.
#' @return A character vector of length 1 containing the generated commit
#' message.
#' @export
#' @examples
#' \dontrun{
#' # Sends the encoded git diff to GPT and returns a
#' # character vector containing the commit message:
#' git_diff_output <- generate_git_diff_output()
#' edo <- generate_encoded_git_diff_output(git_diff_output)
#' enerate_commit_message(edo)
#' }
generate_commit_message <- function(encoded_git_diff_output) {
# See: https://github.com/curlconverter/curlconverter
# Also: https://curlconverter.com/r/
api_key_not_found_error_message <- '"OPENAI_API_KEY" environment variable not found.
Find it here:
https://help.openai.com/en/articles/4936850-where-do-i-find-my-secret-api-key
Set it in your R session with:
`Sys.setenv(OPENAI_API_KEY=\"sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\")`
Or add it to your .Renviron, .zshenv, .bashrc file.'
openai_api_key <- Sys.getenv("OPENAI_API_KEY")
if(openai_api_key == "") { stop(api_key_not_found_error_message)}
headers = c(
`Content-Type` = "application/json",
`Authorization` = paste("Bearer ", openai_api_key, sep = "")
)
data = paste('{\n "model": "gpt-3.5-turbo",\n "messages": [{"role": "user", "content": "Can you give a short commit message (under 50 words) that summarises the changes represented by this `git diff` output: ', encoded_git_diff_output, '"}],\n "temperature": 0.7\n }', sep = "")
response <- httr::POST(url = "https://api.openai.com/v1/chat/completions", httr::add_headers(.headers=headers), body = data)
commit_message <- jsonlite::fromJSON(readBin(response$content, "character"))$choices$message$content
commit_message
}
#' Add, commit, and push changes to a Git repository
#'
#' Aautomates the process of adding changes to a Git repository,
#' committing
#' those changes with a commit message, and pushing the changes to a remote
#' repository.
#'
#' @param commit_message A character string containing the commit message for
#' the changes.
#' @param prepend A character string to prepend to the commit message.
#' Defaults to an empty string.
#' @return No return value, called for side effects.
#' @export
#' @examples
#' \dontrun{
#' add_commit_push()
#' }
add_commit_push <- function(commit_message, prepend) {
if(missing(prepend)) {
if(is.null(options("git_prepend")[[1]])) {
prepend <- ""
} else {
prepend <- options("git_prepend")[[1]]
}
}
commit_message_with_prepend <-paste0(prepend, trimws(commit_message))
os <- Sys.info()['sysname']
if(os == "Windows") {
# Windows
escaped_commit_message_with_prepend <- gsub("([\"'!@#$%&*()[\\]\\{\\};:/\\\\?\\|])", "\\\\\\1", commit_message_with_prepend)
system2("git", c("add", "."), stdout=TRUE)
# Couldn't get git commit to work on windows unless -c (config) flag was provided
command <- paste0('git -c user.name="', Sys.getenv("GIT_AUTHOR_NAME"),
'" -c user.email="',
Sys.getenv("GIT_AUTHOR_EMAIL"), '" commit -m "',
escaped_commit_message_with_prepend,
'"')
git_commit_output <- system(command, intern=TRUE)
git_push_output <- system2("git", c("push"), stdout=TRUE)
output <- c(git_push_output, commit_message_with_prepend)
# output
} else {
# nix
# Not sure how this will handle single quotes, other chars may need escaping
command <- paste0(
"git add . \ngit commit -m '",
commit_message_with_prepend,
"'\ngit push")
# note: ignore.stderr = TRUE was necessary to prevent git push message
# appearing in R console even though it's not an error.
output <- system(command, intern = TRUE, ignore.stdout = TRUE, ignore.stderr = TRUE)
# message(output)
# system("git reset HEAD~ && git push -f")
}
}
#' Suggest a commit message based on the provided git diff
#'
#' Suggests a commit message by utilizing the 'OpenAI' 'GPT-3.5
#' Turbo' model.
#' It takes a git diff as input and returns a meaningful
#' commit message.
#'
#' @param diff An optional character vector containing the git diff. If not
#' provided, the function will automatically
#' generate the git diff output for the current working directory.
#' @return A character vector of length 1 with the suggested commit message
#' based on the provided git diff.
#' @export
#' @examples
#' \dontrun{
#' suggest_commit_message()
#' }
suggest_commit_message <- function(diff) {
if(missing(diff)) {
git_diff_output <- generate_git_diff_output()
diff <- generate_encoded_git_diff_output(git_diff_output)
}
encoded_diff <- utils::URLencode(diff)
commit_message <- generate_commit_message(diff)
cat(commit_message)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.