Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Template in RStudio's New Project Wizard #128

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed .github/.DS_Store
Binary file not shown.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Meta
doc
.Rproj.user
.Rhistory
.DS_Store
**/.DS_Store
.RData
.Ruserdata
inst/doc
Expand All @@ -12,4 +12,4 @@ run_test.R
/doc/
/Meta/
.secrets
inst/extdata/tmp/default*
inst/extdata/tmp/default*
80 changes: 80 additions & 0 deletions R/setup_project.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#' Template Function to Initiate a New Quarto-Based OTTR Course
#'
#' This function will be invoked by RStudio to create a new RStudio Project
#' containing boilerplates files required to start a new Quarto-based OTTR course.
#'
#' For more details, refer to the RStudio Project Templates link:
#' https://rstudio.github.io/rstudio-extensions/rstudio_project_templates.html
#'
#' @param path Path to newly created project
#' @param ... User inputs
#' @noRd
setup_project_quarto <- function(path, ...) {
# collect inputs
dots <- list(...)

# create directory
dir.create(path, recursive = TRUE, showWarnings = FALSE)
# create img folder within path
dir.create(file.path(path, "img"), recursive = TRUE, showWarnings = FALSE)
# create img/box-images folder within path
dir.create(file.path(path, "img", "box-images"), recursive = TRUE, showWarnings = FALSE)
# create .github folder within path
dir.create(file.path(path, ".github"), recursive = TRUE, showWarnings = FALSE)
# create .github/workflows folder within path
dir.create(file.path(path, ".github", "workflows"), recursive = TRUE, showWarnings = FALSE)

# Vector of filenames to be copied
boilerplate_file <- c("index.qmd", "intro.qmd", "404.qmd", "theme.scss",
"style.css", "references.bib", "_quarto.yml", "config_automation.yml")
# Apply the function to each file in the vector
lapply(boilerplate_file, copy_files, dots$style_set, path)

path_quarto_yml <- file.path(path, "_quarto.yml")

quarto_yml <- yaml::read_yaml(path_quarto_yml)
quarto_yml$book$title <- dots$title
quarto_yml$book$author <- dots$author
quarto_yml$book$`repo-url` <- dots$repo_url

# For Custom Style set, user provides logo
if (dots$style_set == "Custom") {
howardbaik marked this conversation as resolved.
Show resolved Hide resolved
file.copy(file.path(normalizePath(dirname(dots$logo)), "logo.png"), file.path(path, "img", "logo.png"))
}

write(yaml::as.yaml(quarto_yml, handlers = list(logical = yaml::verbatim_logical)),
path_quarto_yml)

# Vector of filenames to be copied (images)
boilerplate_file_img <- c("img/logo.png", "img/favicon.ico",
"img/box-images/note.png", "img/box-images/warning.png",
howardbaik marked this conversation as resolved.
Show resolved Hide resolved
"img/box-images/github.png", "img/box-images/dictionary.png",
"img/box-images/thinking_face.png", "img/box-images/under_construction.png")
# Apply the function to each file in the vector
lapply(boilerplate_file_img, copy_files, dots$style_set, path)

# Vector of filenames to be copied (Github Actions)
boilerplate_file_gha <- c(".github/workflows/pull_request.yml", ".github/workflows/delete-preview.yml",
".github/workflows/render-all.yml")
# Apply the function to each file in the vector
lapply(boilerplate_file_gha, copy_files, dots$style_set, path)
}

# Utility function to copy each file
copy_files <- function(file_name, style_set, project_path) {
if (style_set == "FHDaSL") {
style_set <- "fhdasl"
} else if (style_set == "ITN") {
style_set <- "itn"
} else if (style_set == "AnVIL") {
style_set <- "anvil"
} else if (style_set == "GDSCN") {
style_set <- "gdscn"
} else {
style_set <- "custom"
}

source_path <- system.file(file.path("style-sets", style_set, file_name), package = "ottrpal")
destination_path <- file.path(project_path, file_name)
file.copy(source_path, destination_path)
}
Binary file added inst/rstudio/templates/project/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions inst/rstudio/templates/project/rstudio_project_template.dcf
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Binding: setup_project_quarto
Title: Quarto-Based OTTR Course
Icon: logo.png

Parameter: style_set
Widget: SelectInput
Label: Style Set
Fields: FHDaSL, ITN, AnVIL, GDSCN, Custom

Parameter: title
Widget: TextInput
Label: Course Title
Position: right

Parameter: author
Widget: TextInput
Label: Course Author
Position: right

Parameter: logo
Widget: FileInput
Label: Logo (for Custom Style Set)

Parameter: repo_url
Widget: TextInput
Label: GitHub Repo URL
Position: right
25 changes: 25 additions & 0 deletions inst/style-sets/anvil/.github/workflows/delete-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Delete Preview
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is going to create a bit of a maintenance problem for when these files are updated in the main template.

There's two solutions I can think of to help.

  1. Have the function download the files directly from the main OTTR repo: https://github.com/jhudsl/OTTR_Template/
  2. We can have it so the sync file syncs to this R package.

The only reason I find 2 slightly less good of a solution is that this means in order for people to get the updates we would have to update to CRAN and the user would have to update to the most recent ottrpal package version.

Whereas alternatively 1 will make sure people have the latest no matter the ottrpal package version.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there will be many updates to the main template and even if we do make any updates, users can fetch the updates by downloading the development version of ottrpal from GitHub.

The main template is https://github.com/fhdsl/ottr. It is not https://github.com/jhudsl/OTTR_Template/, since this function setups up the Quarto-based OTTR template, not the Rmd-based OTTR Template.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There will definitely be more updates to OTTR in the future. We should also probably have this try to work for both Rmds and Quarto if possible (but I know that's another lift).

Some of the files you are having it download are GHA which will definitely change because people's GHA that we are using deprecate overtime. I think downloading the files directly will be a more stable move but we can definitely brainstorm on this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do one step at a time. (no need to worry about this in this PR) But we will want to make maintenance a tad easier. Happy to talk more at length.

To reiterate I am VERY excited about the work you are doing here -- was not something even on my radar. So you should definitely give yourself a pat on the back for this work!

But we will have to figure out some details like maintenance, but I'm happy to help with this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I'll setup a meeting with you to talk about this further.


on:
pull_request:
types: [closed]

jobs:
delete-preview:
runs-on: ubuntu-latest
steps:

# This is because if a PR is closed before a render finishes it won't find it.
- name: Sleep for 5 minutes
run: sleep 300s
shell: bash

# Check out current repository
- name: checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

# Delete the branch!
- name: Delete branch locally and remotely
run: git push origin --delete preview-${{ github.event.pull_request.number }} || echo "No branch to delete"
169 changes: 169 additions & 0 deletions inst/style-sets/anvil/.github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
name: Pull Request

on:
pull_request:
branches: [ main, staging ]

jobs:
yaml-check:
name: Load user automation choices
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

# Use the yaml-env-action action.
- name: Load environment from YAML
uses: doughepi/[email protected]
with:
files: config_automation.yml # Pass a space-separated list of configuration files. Rightmost files take precedence.

# Delete the branch if this has been run before
- name: Delete branch locally and remotely
run: git push origin --delete preview-${{ github.event.pull_request.number }} || echo "No branch to delete"

# Make the branch fresh
- name: Make the branch fresh
run: |
git config --global --add safe.directory $GITHUB_WORKSPACE
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'

branch_name='preview-${{ github.event.pull_request.number }}'
echo branch doesnt exist
git checkout -b $branch_name || echo branch exists
git push --set-upstream origin $branch_name
shell: bash

outputs:
public_repository: "${{ steps.public_repository.outputs.public }}"
toggle_spell_check: "${{ env.SPELL_CHECK }}"
toggle_url_check: "${{ env.URL_CHECKER }}"
toggle_render_preview: "${{ env.RENDER_PREVIEW }}"
rendering_docker_image: "${{ env.RENDERING_DOCKER_IMAGE }}"

########################## Make the error reports ##############################
spell-check:
name: Check spelling
needs: yaml-check
if: ${{needs.yaml-check.outputs.toggle_spell_check == 'yes'}}
uses: jhudsl/ottr-reports/.github/workflows/report-maker.yml@main
with:
check_type: spelling
error_min: 3
gh_pat: secrets.GH_PAT

url-check:
name: Check URLs
needs: yaml-check
if: ${{needs.yaml-check.outputs.toggle_url_check == 'yes'}}
uses: jhudsl/ottr-reports/.github/workflows/report-maker.yml@main
with:
check_type: urls
error_min: 0
gh_pat: secrets.GH_PAT

render-preview:
name: Render preview
needs: yaml-check
runs-on: ubuntu-latest
container:
image: ${{needs.yaml-check.outputs.rendering_docker_image}}
if: ${{needs.yaml-check.outputs.toggle_render_preview == 'yes'}}

steps:
- name: Checkout files
uses: actions/checkout@v4
with:
fetch-depth: 0

# Set up git checkout
- name: Set up git checkout
run: |
git config --global --add safe.directory $GITHUB_WORKSPACE
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'

branch_name='preview-${{ github.event.pull_request.number }}'
git fetch --all
git checkout $branch_name
git merge -s recursive --strategy-option=theirs origin/${{ github.head_ref }} --allow-unrelated-histories
shell: bash

# Now we want to render all the html files from the qmd files
- name: Run render html
id: site
run: quarto render

# This checks on the steps before it and makes sure that they completed.
# If the renders didn't complete we don't want to commit the file changes
- name: Check on render steps
if: steps.site.outcome != 'success'
run: |
echo site status ${{steps.site.outcome}}
exit 1

- name: Website preview for download
run: zip website-preview.zip docs/* -r

# Commit the rendered website files
- name: Commit rendered website files to preview branch
id: commit
run: |
branch_name='preview-${{ github.event.pull_request.number }}'
git diff origin/main -- '*.html' >/dev/null && changes=true || changes=false
echo "changes=$changes" >> $GITHUB_OUTPUT
git add . --force
git commit -m 'Render preview' || echo "No changes to commit"
git pull --set-upstream origin $branch_name --allow-unrelated-histories --strategy-option=ours
git push --force || echo "No changes to commit"
shell: bash

- name: Find Comment
uses: peter-evans/find-comment@v1
id: fc
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: 'github-actions[bot]'
body-includes: latest commit

- name: Build components of the comment
id: build-components
run: |
course_name=$(head -n 1 _website.yml | cut -d'"' -f 2| tr " " "-")
website_link=$(echo "https://htmlpreview.github.io/?https://raw.githubusercontent.com/$GITHUB_REPOSITORY/preview-${{ github.event.pull_request.number }}/docs/index.html")
docs_link=$(echo "https://github.com/$GITHUB_REPOSITORY/raw/preview-${{ github.event.pull_request.number }}/website-preview.zip")
echo "docs_link=$docs_link" >> $GITHUB_OUTPUT
echo "website_link=$website_link" >> $GITHUB_OUTPUT
echo "time=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
echo "commit_id=$GITHUB_SHA" >> $GITHUB_OUTPUT
echo ${{steps.commit.outputs.changes}}

- name: Create or update comment
if: steps.commit.outputs.changes == 'true'
uses: peter-evans/create-or-update-comment@v1
with:
comment-id: ${{ steps.fc.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body: |
:eyes: [Quick Preview of Website](${{ steps.build-components.outputs.website_link }}) - Click for a preview of recent changes.
:file_folder: [Download Full Website](${{ steps.build-components.outputs.docs_link }}) - Download complete Zip file of the website.

The Quick Preview may not display all HTML features accurately, but it provides a basic overview.

_Updated at ${{ steps.build-components.outputs.time }} with changes from the latest commit ${{ steps.build-components.outputs.commit_id }}_
edit-mode: replace

- name: No comment if no changes
if: steps.commit.outputs.changes == 'false'
uses: peter-evans/create-or-update-comment@v1
with:
comment-id: ${{ steps.fc.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body: |
The latest commit did not produce rendering changes.

_Updated at ${{ steps.build-components.outputs.time }} with changes from ${{ steps.build-components.outputs.commit_id }}_
edit-mode: replace
Loading
Loading