diff --git a/.Rbuildignore b/.Rbuildignore index 78eee8f..1eaa115 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -1,3 +1,8 @@ ^ojoutils\.Rproj$ ^\.Rproj\.user$ ^LICENSE\.md$ +^README\.Rmd$ +^_pkgdown\.yml$ +^docs$ +^pkgdown$ +^\.github$ diff --git a/.github/.gitignore b/.github/.gitignore new file mode 100644 index 0000000..2d19fc7 --- /dev/null +++ b/.github/.gitignore @@ -0,0 +1 @@ +*.html diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml new file mode 100644 index 0000000..4bbce75 --- /dev/null +++ b/.github/workflows/pkgdown.yaml @@ -0,0 +1,50 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + release: + types: [published] + workflow_dispatch: + +name: pkgdown.yaml + +permissions: read-all + +jobs: + pkgdown: + runs-on: ubuntu-latest + # Only restrict concurrency for non-PR jobs + concurrency: + group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-pandoc@v2 + + - uses: r-lib/actions/setup-r@v2 + with: + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::pkgdown, local::. + needs: website + + - name: Build site + run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) + shell: Rscript {0} + + - name: Deploy to GitHub pages 🚀 + if: github.event_name != 'pull_request' + uses: JamesIves/github-pages-deploy-action@v4.5.0 + with: + clean: false + branch: gh-pages + folder: docs diff --git a/.gitignore b/.gitignore index cd67eac..a433ae5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,9 @@ .Rproj.user +.Rhistory +.Rdata +.httr-oauth +.DS_Store +.quarto +local/ +secrets/ +docs diff --git a/DESCRIPTION b/DESCRIPTION index e9db20f..0d36486 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -8,16 +8,25 @@ Description: We find ourselves repeating the same simple tasks or running a seri License: GPL (>= 3) Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.2 Imports: cli, dbplyr, dplyr, fs, + gert, + gh, + heck, + readr, + renv, rlang, stringr, + usethis, withr Suggests: testthat (>= 3.0.0), tibble Config/testthat/edition: 3 +URL: https://github.com/openjusticeok/ojoutils, https://openjusticeok.github.io/ojoutils/ +BugReports: https://github.com/openjusticeok/ojoutils/issues +Config/testthat/parallel: true diff --git a/R/package.R b/R/package.R new file mode 100644 index 0000000..e7f4b2a --- /dev/null +++ b/R/package.R @@ -0,0 +1,131 @@ +#' Create Package +#' +ojo_create_package <- function( + name, + description, + dir = ".", + private = TRUE, + imports = NULL, + depends = NULL, + suggests = NULL, + authors = NULL, + rextendr = FALSE, + rstudio = TRUE +) { + # Get the initial working directory + init_wd <- fs::path_wd() + + # TODO: Default to using OJO_PATH env var for project location + + # Get full path of project directory + project_dir <- fs::path_abs(paste0(dir, "/", name)) + + # Get package name + package_name <- heck::to_lower_camel_case(name) + + # If name is NULL, first try to use interactive CLI, otherwise fail + if (is.null(name)) { + if (rlang::is_interactive()) { + # TODO: Get variable interactively + } else { + rlang::abort("No project name provided, and no support for interactive definition available in this environment.") + } + } + + # TODO: Check name matches conventions and isn't taken + # TODO: If interactive, offer to change + + # TODO: Check description format + # TODO: If description NULL offer to create + + # Create Github repo from package template + gh_resp <- gh::gh( + "POST /repos/openjusticeok/ojo-package-template/generate", + owner = "openjusticeok", + name = name, + description = description, + private = private + ) + + Sys.sleep(1) + + # Clone repo + gert::git_clone( + url = paste0("git@github.com:openjusticeok/", name, ".git"), + path = project_dir + ) + + usethis::create_package( + path = project_dir, + rstudio = rstudio, + roxygen = TRUE, + check_name = FALSE, + fields = list( + Package = package_name, + Description = description, + Version = "0.0.0.9000" + ), + open = FALSE + ) + + usethis::with_project( + path = project_dir, + code = { + usethis::use_readme_rmd() + usethis::use_github_links() + usethis::use_testthat(parallel = TRUE) + usethis::use_pkgdown_github_pages() + } + ) + + # # Prefill readme with title line + # readr::write_lines( + # x = c( + # paste0("# {", package_name, "}"), + # description + # ), + # sep = "\n\n", + # file = fs::path(project_dir, "README.md"), + # append = FALSE + # ) + + # TODO: Ask in cli if you want to edit the readme further + + # Init renv + renv::init( + project = project_dir, + bare = TRUE, + load = FALSE, + restart = FALSE + ) + + # Add pak + renv::install( + packages = c( + "pak", + "devtools", + "usethis" + ), + prompt = FALSE, + lock = TRUE, + project = project_dir + ) + + # Stage all changed files + gert::git_add( + files = c("*", ".*"), + repo = project_dir + ) + + # Commit changes + gert::git_commit( + message = "Scaffold package", + repo = project_dir + ) + + # Push changes to Github + gert::git_push(repo = project_dir) + + # Return the directory of the project invisibly + invisible(project_dir) +} diff --git a/R/project.R b/R/project.R new file mode 100644 index 0000000..feb127b --- /dev/null +++ b/R/project.R @@ -0,0 +1,99 @@ +#' @title Create Project +#' @description Creates a new R project with a standard directory structure +#' +ojo_create_project <- function(name = NULL, description = NULL, dir = ".", private = TRUE, packages = NULL) { + # Get the initial working directory + init_wd <- fs::path_wd() + + # TODO: Default to using OJO_PATH env var for project location + + # Get full path of project directory + project_dir <- fs::path_abs(paste0(dir, "/", name)) + + # If name is NULL, first try to use interactive CLI, otherwise fail + if (is.null(name)) { + if (rlang::is_interactive()) { + # TODO: Get variable interactively + } else { + rlang::abort("No project name provided, and no support for interactive definition available in this environment.") + } + } + + # TODO: Check name matches conventions and isn't taken + # TODO: If interactive, offer to change + + # TODO: Check description format + # TODO: If description NULL offer to create + + # TODO: Wrap API call and issue custom error message + # Create Github repo from project template + gh_resp <- gh::gh( + "POST /repos/openjusticeok/ojo-project-template/generate", + owner = "openjusticeok", + name = name, + description = description, + private = private + ) + + # Have to give github the time to transfer the repo + # TODO: Base this on an API call? + Sys.sleep(1) + + usethis::create_from_github( + repo_spec = glue::glue("git@github.com:openjusticeok/{name}.git"), + destdir = dir, + fork = FALSE, + rstudio = TRUE, + open = FALSE, + protocol = "ssh" + ) + + # Prefill readme with title line + readr::write_lines( + x = c( + paste0("# ", name), + description + ), + sep = "\n\n", + file = fs::path(project_dir, "README.md"), + append = FALSE + ) + + # TODO: Ask in cli if you want to edit the readme further + + # Init renv + renv::init( + project = project_dir, + bare = TRUE, + load = FALSE, + restart = FALSE + ) + + # Add pak + renv::install( + packages = c( + "pak" + ), + prompt = FALSE, + lock = TRUE, + project = project_dir + ) + + # Stage all changed files + gert::git_add( + files = c("*", ".*"), + repo = project_dir + ) + + # Commit changes + gert::git_commit( + message = "Scaffold project", + repo = project_dir + ) + + # Push changes to Github + gert::git_push(repo = project_dir) + + # Return the directory of the project invisibly + invisible(project_dir) +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..4a02d81 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# ojoutils diff --git a/_pkgdown.yml b/_pkgdown.yml new file mode 100644 index 0000000..846d616 --- /dev/null +++ b/_pkgdown.yml @@ -0,0 +1,4 @@ +url: https://openjusticeok.github.io/ojoutils/ +template: + bootstrap: 5 + diff --git a/man/ojo_create_project.Rd b/man/ojo_create_project.Rd new file mode 100644 index 0000000..e201b44 --- /dev/null +++ b/man/ojo_create_project.Rd @@ -0,0 +1,11 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/project.R +\name{ojo_create_project} +\alias{ojo_create_project} +\title{Create Project} +\usage{ +ojo_create_project(name = NULL, dir = ".", private = TRUE) +} +\description{ +Creates a new R project with a standard directory structure +} diff --git a/tests/testthat.R b/tests/testthat.R index 4b3c932..c5e7698 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -3,8 +3,8 @@ # # Where should you do additional test configuration? # Learn more about the roles of various files in: -# * https://r-pkgs.org/tests.html -# * https://testthat.r-lib.org/reference/test_package.html#special-files +# * https://r-pkgs.org/testing-design.html#sec-tests-files-overview +# * https://testthat.r-lib.org/articles/special-files.html library(testthat) library(ojoutils)