From 9b37bb03ccb01d50d1c823e5227211f85c98dd20 Mon Sep 17 00:00:00 2001 From: Douglas Lowe <10961945+douglowe@users.noreply.github.com> Date: Fri, 2 Oct 2026 15:10:18 +0100 Subject: [PATCH 1/5] update to carpentry workflows from incubator example --- .github/workbench-docker-version.txt | 1 + .github/workflows/README.md | 366 ++++++++++++------- .github/workflows/docker_apply_cache.yaml | 187 ++++++++++ .github/workflows/docker_build_deploy.yaml | 150 ++++++++ .github/workflows/docker_pr_receive.yaml | 221 +++++++++++ .github/workflows/pr-close-signal.yaml | 2 +- .github/workflows/pr-comment.yaml | 112 ++++-- .github/workflows/pr-post-remove-branch.yaml | 4 +- .github/workflows/pr-preflight.yaml | 6 +- .github/workflows/pr-receive.yaml | 132 ------- .github/workflows/sandpaper-main.yaml | 64 ---- .github/workflows/sandpaper-version.txt | 1 - .github/workflows/update-cache.yaml | 151 +++++--- .github/workflows/update-workflows.yaml | 103 ++++-- .github/workflows/workflows-version.txt | 1 + 15 files changed, 1061 insertions(+), 440 deletions(-) create mode 100644 .github/workbench-docker-version.txt create mode 100644 .github/workflows/docker_apply_cache.yaml create mode 100644 .github/workflows/docker_build_deploy.yaml create mode 100644 .github/workflows/docker_pr_receive.yaml delete mode 100644 .github/workflows/pr-receive.yaml delete mode 100644 .github/workflows/sandpaper-main.yaml delete mode 100644 .github/workflows/sandpaper-version.txt create mode 100644 .github/workflows/workflows-version.txt diff --git a/.github/workbench-docker-version.txt b/.github/workbench-docker-version.txt new file mode 100644 index 0000000..d2db7db --- /dev/null +++ b/.github/workbench-docker-version.txt @@ -0,0 +1 @@ +v0.2.8 diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 7076ddd..4516bb1 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -1,198 +1,308 @@ -# Carpentries Workflows +# Workbench Workflows Documentation -This directory contains workflows to be used for Lessons using the {sandpaper} -lesson infrastructure. Two of these workflows require R (`sandpaper-main.yaml` -and `pr-receive.yaml`) and the rest are bots to handle pull request management. +These GitHub Actions workflows manage and maintain the build processes for lessons using the Carpentries Workbench on GitHub. -These workflows will likely change as {sandpaper} evolves, so it is important to -keep them up-to-date. To do this in your lesson you can do the following in your -R console: + +## Managing Workflow Updates + +By using prebuilt Docker containers that are managed by the Carpentries core Workbench maintainers, these workflows are designed to be rarely updated. + +However, is important to be able to keep them up-to-date when appropriate. +You can do this locally using your own R and Workbench installation, or via the "04 Maintain: Update Workflow Files" (`update-workflows.yaml`) GitHub Action. + +### Updating locally + +In a terminal/git bash, navigate to the lesson folder where you want to update the workflows, e.g.: + +```bash +cd ~/lessons/shell-novice +``` + +Then, start an R session and: ```r # Install/Update sandpaper -options(repos = c(carpentries = "https://carpentries.r-universe.dev/", - CRAN = "https://cloud.r-project.org")) +options(repos = c(carpentries = "https://carpentries.r-universe.dev/", CRAN = "https://cloud.r-project.org")) install.packages("sandpaper") # update the workflows in your lesson library("sandpaper") -update_github_workflows() +sandpaper::update_github_workflows() +quit() +``` + +And then in a bash prompt/git bash terminal: + +```bash +$ git add .github/workflows +$ git commit -m "Manual update to docker workflows" +$ git push origin main +``` + +> [!NOTE] +> For non-renv lessons, this is all the setup you need! +> +> For renv-enabled lessons: +> - Cancel any "01 Maintain: Build and Deploy Site" workflow currently running +> - Run the "02 Maintain: Check for Updated Packages" workflow and merge any PR opened to update the renv lockfile +> - This should automatically run the "03 Maintain: Apply Package Cache" workflow to install packages and build the cache +> - A successful cache build should then trigger the "01 Maintain: Build and Deploy Site" workflow + +#### Updating to a specific workflow release or branch + +To test new Workbench workflow features or branches, or to pin to a specific release, the `branch` option can be supplied to `update_github_workflows()`. + +For a given branch: + +```r +sandpaper::update_github_workflows(branch="develop") +``` + +Or for a given release version: +```r +sandpaper::update_github_workflows(branch="1.0.1") ``` -Inside this folder, you will find a file called `sandpaper-version.txt`, which -will contain a version number for sandpaper. This will be used in the future to -alert you if a workflow update is needed. +### Updating using GitHub -What follows are the descriptions of the workflow files: +#### Official lessons -## Deployment +"Official" lessons are those in the lesson program repositories, Incubator, or Lab. +They need no extra setup as this is all managed for you as part of the Carpentries GitHub organisations. -### 01 Build and Deploy (sandpaper-main.yaml) +To update the workflows, either: +- wait for the scheduled run of the "04 Maintain: Update Workflow Files" at approximately midnight every Tuesday +- go to the Actions tab on GitHub, click "04 Maintain: Update Workflow Files" on the left, then "Run Workflow" on the right -This is the main driver that will only act on the main branch of the repository. -This workflow does the following: +Once complete, this will raise a PR with any changes to the workflows that are needed. +If you are happy with the changes made, you can merge the PR into your lesson repository. - 1. checks out the lesson - 2. provisions the following resources - - R - - pandoc - - lesson infrastructure (stored in a cache) - - lesson dependencies if needed (stored in a cache) - 3. builds the lesson via `sandpaper:::ci_deploy()` +#### Your own lessons -#### Caching +This presumes you: + - already have a lesson repository available on GitHub + - have enabled workflows in the lesson repo + - have set up a SANDPAPER_WORKFLOW personal access token (PAT) in the lesson repo -This workflow has two caches; one cache is for the lesson infrastructure and -the other is for the the lesson dependencies if the lesson contains rendered -content. These caches are invalidated by new versions of the infrastructure and -the `renv.lock` file, respectively. If there is a problem with the cache, -manual invaliation is necessary. You will need maintain access to the repository -and you can either go to the actions tab and [click on the caches button to find -and invalidate the failing cache](https://github.blog/changelog/2022-10-20-manage-caches-in-your-actions-workflows-from-web-interface/) -or by setting the `CACHE_VERSION` secret to the current date (which will -invalidate all of the caches). +To go through these steps, please follow the [Forking a Workbench Lesson](https://docs.carpentries.org/resources/curriculum/lesson-forks.html#forking-a-workbench-lesson-repository) +documentation. -## Updates +Once set up, run the "04 Maintain: Update Workflow Files" (`update-workflows.yaml`) action. -### Setup Information +This will raise a PR with any changes to the workflows that are needed. +If you are happy with the changes made, you can merge the PR into your lesson repository. -These workflows run on a schedule and at the maintainer's request. Because they -create pull requests that update workflows/require the downstream actions to run, -they need a special repository/organization secret token called -`SANDPAPER_WORKFLOW` and it must have the `public_repo` and `workflow` scope. -This can be an individual user token, OR it can be a trusted bot account. If you -have a repository in one of the official Carpentries accounts, then you do not -need to worry about this token being present because the Carpentries Core Team -will take care of supplying this token. +## Dependency Images for RMarkdown Lessons -If you want to use your personal account: you can go to - -to create a token. Once you have created your token, you should copy it to your -clipboard and then go to your repository's settings > secrets > actions and -create or edit the `SANDPAPER_WORKFLOW` secret, pasting in the generated token. +Lessons that use R packages and RMarkdown are built on GitHub using Docker images within these workflows. +These images are based on the [workbench-docker](https://github.com/carpentries/workbench-docker) image. +This base image only contains the Workbench packages to build lessons and not any extra R packages your lesson might need. -If you do not specify your token correctly, the runs will not fail and they will -give you instructions to provide the token for your repository. +Therefore, there are two steps to perform to resolve the required R packages in a lesson, and then generate a Docker image layer comprising those packages. -### 02 Maintain: Update Workflow Files (update-workflow.yaml) +The "02 Maintain: Check for Updated Packages" workflow checks for any used R packages and their versions, and if successful, opens a Pull Request to update your lesson's renv lockfile (`renv.lock`). +Once the PR is merged, the "03 Maintain: Apply Package Cache" workflow builds the dependency image layer with `docker build` and publishes it in your user or organisation account Packages area. -The {sandpaper} repository was designed to do as much as possible to separate -the tools from the content. For local builds, this is absolutely true, but -there is a minor issue when it comes to workflow files: they must live inside -the repository. +> [!NOTE] +> Caching is only relevant for lessons that use Rmd files and renv to manage R packages. +> If you are building basic markdown documents, caching will not apply to you, and the only +> workflow that needs to be run is "01 Maintain: Build and Deploy Site". -This workflow ensures that the workflow files are up-to-date. The way it work is -to download the update-workflows.sh script from GitHub and run it. The script -will do the following: +### Publishing dependency images -1. check the recorded version of sandpaper against the current version on github -2. update the files if there is a difference in versions +The two dependency workflows are separated to ensure that once you have a successful build with a working renv environment, the resulting dependency image is stored and will be reused by the Workbench Docker container. +This means that lesson builds will be faster and more consistent once a dependency image is created and reused. This is doubly important if you need very specific versions of R packages, i.e. "pinning". -After the files are updated, if there are any changes, they are pushed to a -branch called `update/workflows` and a pull request is created. Maintainers are -encouraged to review the changes and accept the pull request if the outputs -are okay. +This setup means that this dependency image layer is available indefinitely: +- to build your lesson, improving robustness and reproducibility +- for others to use as a complete environment in their local builds, teaching environments, or Codespaces -This update is run weekly or on demand. +If and when you want to perform an update to the dependency image, you can re-run the "02 Maintain: Check for Updated Packages" workflow and verify that your lesson still builds with any new packages or changes. +The "03 Maintain: Apply Package Cache" workflow will publish a new repository- or organisation-local GHCR image for the lesson. -### 03 Maintain: Update Package Cache (update-cache.yaml) +As such, the dependency image is invalidated by new versions of the `renv.lock` file. +This happens: + - if you update your lockfile locally by using the `sandpaper::update_cache()` and `sandpaper::manage_deps()` functions, and then push it to the lesson repository + - when you run the "02 Maintain: Check for Updated Packages" and there are new packages to install -For lessons that have generated content, we use {renv} to ensure that the output -is stable. This is controlled by a single lockfile which documents the packages -needed for the lesson and the version numbers. This workflow is skipped in -lessons that do not have generated content. +More information on managing local renv-based lesson dependencies can be found in the [Sandpaper packages vignettes](https://carpentries.github.io/sandpaper/articles/building-with-renv.html). -Because the lessons need to remain current with the package ecosystem, it's a -good idea to make sure these packages can be updated periodically. The -update cache workflow will do this by checking for updates, applying them in a -branch called `updates/packages` and creating a pull request with _only the -lockfile changed_. +#### Using different dependency image versions + +There are times when you may want to go back to a previous dependency image: + - if you run "02 Maintain: Check for Updated Packages" and "03 Maintain: Apply Package Cache" and the cache generation fails for some reason + - if there is a new R package that produces incorrect or broken lesson output + - a new R version is released and downstream packages fail to build and install, and need updating by the package maintainer(s) + +Dependency images will have the following name format, where IMAGE is the workbench-docker image version, and HASHSUM is the `renv.lock` lockfile hash: + +``` +IMAGE HASHSUM +[ | ] [ | ] +v0.2.4_renv-2e499eb706112971b2cffceb49b55a6efe49f3ed75cd6579b10ff224489daca4 +``` + +Copy the hashsum part of the desired image tag you want to use, e.g. `2e499eb706112971b2cffceb49b55a6efe49f3ed75cd6579b10ff224489daca4`. + +Then either: + 1. Add a repository variable called CACHE_VERSION, and paste in the hash + 2. Run the "01 Maintain: Build and Deploy Site" manually, supplying the `Optional renv cache version override` input + +If you have no images listed, make sure to run the "02 Maintain: Check for Updated Packages" and "03 Maintain: Apply Package Cache" workflows to publish a new dependency image. + +> [!NOTE] +> If you are maintaining an official lesson, dependency images are saved to the Carpentries lesson program organisation, e.g. `datacarpentry`, GHCR package namespace. +> Once a successful dependency image has been published, the build workflows will use it automatically when the matching Docker version tag exists, e.g. 'latest' or a specific version. +> +> If you are developing a lesson in your own repository, the dependency images are stored in your repository's GHCR package namespace. +> You can see available images by going to your user or organisation's Packages tab, e.g. `https://github.com/?tab=packages`. + +#### Pruning dependency image layers + +Through the lifetime of a lesson, an increasing number of dependency images will be generated. +As the images are public, GitHub currently charges no storage, or network ingress or egress fees to upload or download them. + +The "03 Maintain: Apply Package Cache" workflow will automatically check the number of published dependency images and keep each version published plus one underlying untagged digest (if any) for each version. +This means it is possible to roll back easily to a previous version or digest, but not end up with a huge number of dependency images to manage. + +In any case, you can manually delete any versions you wish by: +- going to your user or organisation's Packages tab, e.g. `https://github.com/?tab=packages`. +- selecting the dependency image you want to manage, e.g. `-deps` +- selecting `Package settings` on the right hand side +- deleting any images + +> [!NOTE] +> Deleting these images manually may break your builds. +> Only perform this action if you are sure you want to delete the generated dependency images. +> +> If you mistakenly delete an image, you can rebuild it by rerunning the "03 Maintain: Apply Package Cache" workflow. + + +## User Settings + +Input level variables are documented in the `carpentries/actions` repository READMEs for each composite action. + +Specific repository level variables can be set that will force particular options across all workflow runs. + +### 01 Maintain: Build and Deploy Site (docker_build_deploy.yaml) + +Repository-level variables for this workflow are: +- WORKBENCH_TAG + - The workbench-docker release version to use for a given build + - This can be set to a specific version number to force all builds to use a given container version + - Default is unset or `latest` +- BUILD_RESET + - Force a reset of previously build markdown files + - Setting this variable value to `true` will force sandpaper to delete any previously build markdown files + - Default is unset or `false` +- AUTO_MERGE_WORKBENCH_VERSION_UPDATE + - Control merge behaviour of the workbench-docker version update PR + - When a new workbench Docker image version is detected, usually after a sandpaper, varnish, or pegboard update, its version number will be incremented + - If a newer version is available, a PR will be auto-generated that updates the `.github/workbench-docker-version.txt` file, and this PR will be auto-merged + - To not auto-merge this PR and to choose when to update the Docker version used, set this to `false`. + - Default is unset or `true` +- LANG_CODE + - Two-letter language code that triggers the use of Joel Nitta's {dovetail} package for lesson translation + - This is used in the internationalisation repos of the main Carpentry lesson programs + - Default is unset or `''` + +### 02 Maintain: Check for Updated Packages (update-cache.yaml) + +Repository-level variables for this workflow are: +- LOCKFILE_CACHE_GEN + - Passed to the `generate-cache` input of the [update-lockfile](https://github.com/carpentries/actions/tree/main/update-lockfile) action + - A temporary renv cache is generated when this workflow runs + - If this option is set to `false`, no temporary cache will be generated + - Default is `true` +- FORCE_RENV_INIT + - Passed to the `force-renv-init` input of the [update-lockfile](https://github.com/carpentries/actions/tree/main/update-lockfile) action + - renv initialises a cache based on a given lockfile + - If this lockfile is particularly old or packages have broken/unresolvable dependencies, then builds will fail + - If this option is set to `true`, a full renv reinitialisation will occur, "wiping the slate clean" + - This option is useful if you're using Bioconductor packages which often break when new Bioconductor releases happen + - Default is `false` +- UPDATE_PACKAGES + - Passed to the `update` input of the [update-lockfile](https://github.com/carpentries/actions/tree/main/update-lockfile) action + - If set to `false` only package hydration will happen and no package update checks will occur + - Default is `true` + +### 03 Maintain: Apply Package Cache (docker_apply_cache.yaml) + +Repository-level variables for this workflow are: +- WORKBENCH_TAG + - The workbench-docker release version to use for a given build + - This can be set to a specific version number to force all builds to use a given container version + - Default is unset or `latest` + +### 04 Maintain: Update Workflow Files (update-workflows.yaml) + +There are no repository variables for this workflow. -From here, the markdown documents will be rebuilt and you can inspect what has -changed based on how the packages have updated. ## Pull Request and Review Management -Because our lessons execute code, pull requests are a secruity risk for any -lesson and thus have security measures associted with them. **Do not merge any -pull requests that do not pass checks and do not have bots commented on them.** +Because our lessons execute code, pull requests are a security risk for any lesson and thus have security measures associated with them. +**Do not merge any pull requests that do not pass checks and do not have bots commented on them.** -This series of workflows all go together and are described in the following -diagram and the below sections: +This series of workflows all go together and are described in the following diagram and the below sections: ![Graph representation of a pull request](https://carpentries.github.io/sandpaper/articles/img/pr-flow.dot.svg) ### Pre Flight Pull Request Validation (pr-preflight.yaml) -This workflow runs every time a pull request is created and its purpose is to -validate that the pull request is okay to run. This means the following things: +This workflow runs every time a pull request is created and its purpose is to validate that the pull request is okay to run. +This means the following things: 1. The pull request does not contain modified workflow files -2. If the pull request contains modified workflow files, it does not contain - modified content files (such as a situation where @carpentries-bot will - make an automated pull request) -3. The pull request does not contain an invalid commit hash (e.g. from a fork - that was made before a lesson was transitioned from styles to use the - workbench). +2. If the pull request contains modified workflow files, it does not contain modified content files + (such as a situation where @carpentries-bot will make an automated pull request) +3. The pull request does not contain an invalid commit hash + (e.g. from a fork that was made before a lesson was transitioned from styles to use the Workbench). -Once the checks are finished, a comment is issued to the pull request, which -will allow maintainers to determine if it is safe to run the -"Receive Pull Request" workflow from new contributors. +Once the checks are finished, a comment is issued to the pull request, which will allow maintainers to determine if it is safe to run the "Receive Pull Request" workflow from new contributors. -### Receive Pull Request (pr-receive.yaml) +### Receive Pull Request (docker_pr_receive.yaml) -**Note of caution:** This workflow runs arbitrary code by anyone who creates a -pull request. GitHub has safeguarded the token used in this workflow to have no -priviledges in the repository, but we have taken precautions to protect against -spoofing. +**Note of caution:** This workflow runs arbitrary code by anyone who creates a pull request. +GitHub has safeguarded the token used in this workflow to have no privileges in the repository, but we have taken precautions to protect against spoofing. -This workflow is triggered with every push to a pull request. If this workflow -is already running and a new push is sent to the pull request, the workflow -running from the previous push will be cancelled and a new workflow run will be -started. +This workflow is triggered with every push to a pull request. +If this workflow is already running and a new push is sent to the pull request, the workflow running from the previous push will be cancelled and a new workflow run will be started. -The first step of this workflow is to check if it is valid (e.g. that no -workflow files have been modified). If there are workflow files that have been -modified, a comment is made that indicates that the workflow is not run. If -both a workflow file and lesson content is modified, an error will occurr. +The first step of this workflow is to check if it is valid (e.g. that no workflow files have been modified): +- If there are workflow files that have been modified, a comment is made that indicates that the workflow will not continue. +- If both a workflow file and lesson content is modified, an error will occur and the workflow will not continue. -The second step (if valid) is to build the generated content from the pull -request. This builds the content and uploads three artifacts: +The second step (if valid) is to build the generated content from the pull request. +This builds the content and uploads three artifacts: 1. The pull request number (pr) 2. A summary of changes after the rendering process (diff) 3. The rendered files (build) -Because this workflow builds generated content, it follows the same general -process as the `sandpaper-main` workflow with the same caching mechanisms. - -The artifacts produced are used by the next workflow. +The artifacts produced are used by the "Comment on Pull Request" workflow. ### Comment on Pull Request (pr-comment.yaml) -This workflow is triggered if the `pr-receive.yaml` workflow is successful. +This workflow is triggered if the `docker_pr_receive.yaml` workflow is successful. The steps in this workflow are: -1. Test if the workflow is valid and comment the validity of the workflow to the - pull request. -2. If it is valid: create an orphan branch with two commits: the current state - of the repository and the proposed changes. +1. Test if the workflow is valid and comment the validity of the workflow to the pull request. +2. If it is valid: create an orphan branch with two commits: the current state of the repository and the proposed changes. 3. If it is valid: update the pull request comment with the summary of changes -Importantly: if the pull request is invalid, the branch is not created so any -malicious code is not published. +Importantly: if the pull request is invalid, the branch is not created so any malicious code is not published. -From here, the maintainer can request changes from the author and eventually -either merge or reject the PR. When this happens, if the PR was valid, the -preview branch needs to be deleted. +From here, the maintainer can request changes from the author and eventually either merge or reject the PR. +When this happens, if the PR was valid, the preview branch needs to be deleted. ### Send Close PR Signal (pr-close-signal.yaml) -Triggered any time a pull request is closed. This emits an artifact that is the -pull request number for the next action +Triggered any time a pull request is closed. +This emits an artifact that is the pull request number for the next action. ### Remove Pull Request Branch (pr-post-remove-branch.yaml) -Tiggered by `pr-close-signal.yaml`. This removes the temporary branch associated with -the pull request (if it was created). +Triggered by `pr-close-signal.yaml`. +This removes the temporary branch associated with the pull request (if it was created). diff --git a/.github/workflows/docker_apply_cache.yaml b/.github/workflows/docker_apply_cache.yaml new file mode 100644 index 0000000..dcebb3b --- /dev/null +++ b/.github/workflows/docker_apply_cache.yaml @@ -0,0 +1,187 @@ +name: "03 Maintain: Apply Package Cache" +description: "Build and publish the lesson dependency image after a pull request has been merged or via manual trigger" +on: + workflow_dispatch: + inputs: + name: + description: 'Who triggered this build?' + required: true + default: 'Maintainer (via GitHub)' + force-dependency-image-rebuild: + description: 'Rebuild the dependency image layer even if one already exists?' + required: false + default: false + type: boolean + prune-keep-count: + description: 'How many existing dependency image layers to keep?' + required: false + default: 1 + type: number + pull_request: + types: + - closed + branches: + - main + +# queue cache runs +concurrency: + group: docker-apply-cache + cancel-in-progress: false + +jobs: + preflight: + name: "Preflight: PR or Manual Trigger?" + runs-on: ubuntu-latest + outputs: + do-apply: ${{ steps.check.outputs.merged_or_manual }} + steps: + - name: "Should we run cache application?" + id: check + run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" || + ("${{ github.ref }}" == "refs/heads/main" && "${{ github.event.action }}" == "closed" && "${{ github.event.pull_request.merged }}" == "true") ]]; then + echo "merged_or_manual=true" >> $GITHUB_OUTPUT + else + echo "This was not a manual trigger and no PR was merged. No action taken." + echo "merged_or_manual=false" >> $GITHUB_OUTPUT + fi + shell: bash + + check-renv: + name: "Check If We Need {renv}" + runs-on: ubuntu-latest + needs: preflight + if: needs.preflight.outputs.do-apply == 'true' + outputs: + renv-needed: ${{ steps.check-for-renv.outputs.renv-needed }} + renv-cache-hashsum: ${{ steps.check-for-renv.outputs.renv-cache-hashsum }} + steps: + - name: "Check for renv" + id: check-for-renv + uses: carpentries/actions/renv-checks@v1 + with: + WORKBENCH_TAG: ${{ vars.WORKBENCH_TAG || 'latest' }} + skip-cache-check: true + + no-renv-cache-used: + name: "No renv package dependency image needed" + runs-on: ubuntu-latest + needs: check-renv + if: needs.check-renv.outputs.renv-needed != 'true' + steps: + - name: "No dependency image needed" + run: echo "No renv dependency image needed for this lesson" + + update-renv-cache: + name: "Publish renv package dependency image" + runs-on: ubuntu-latest + needs: check-renv + if: needs.check-renv.outputs.renv-needed == 'true' + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v6 + + - name: "Get Container Version Used" + id: wb-vers + uses: carpentries/actions/container-version@v1 + with: + WORKBENCH_TAG: ${{ vars.WORKBENCH_TAG }} + renv-needed: ${{ needs.check-renv.outputs.renv-needed }} + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Log in to GHCR + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set dependency image tags + id: image + env: + IMAGE_OWNER: ${{ github.repository_owner }} + IMAGE_NAME: ${{ github.event.repository.name }} + WB_VERSION: ${{ steps.wb-vers.outputs.container-version }} + RENV_HASH: ${{ needs.check-renv.outputs.renv-cache-hashsum }} + run: | + set -euo pipefail + exact_image="ghcr.io/${IMAGE_OWNER}/${IMAGE_NAME}-deps:${WB_VERSION}_renv-${RENV_HASH}" + latest_image="ghcr.io/${IMAGE_OWNER}/${IMAGE_NAME}-deps:latest" + + # lowercaseify + echo "exact_image=${exact_image,,}" >> "$GITHUB_OUTPUT" + echo "latest_image=${latest_image,,}" >> "$GITHUB_OUTPUT" + shell: bash + + - name: Check for existing dependency image tag + id: image-exists + env: + EXACT_IMAGE: ${{ steps.image.outputs.exact_image }} + run: | + set -euo pipefail + if docker manifest inspect "${EXACT_IMAGE}" >/dev/null 2>&1; then + echo "exists=true" >> "$GITHUB_OUTPUT" + echo "## ⚠️ Dependency image already exists" >> $GITHUB_STEP_SUMMARY + echo "Dependency image already exists for this renv hash: ${EXACT_IMAGE}" >> $GITHUB_STEP_SUMMARY + echo "Dependency image already exists for this renv hash: ${EXACT_IMAGE}" + else + echo "exists=false" >> "$GITHUB_OUTPUT" + echo "No existing dependency image found for this renv hash: ${EXACT_IMAGE}" + fi + shell: bash + + - name: Build and push dependency image layer + id: build-push-deps-layer + if: | + steps.image-exists.outputs.exists != 'true' || + ( + github.event_name == 'workflow_dispatch' && + github.event.inputs.force-dependency-image-rebuild == 'true' + ) + uses: carpentries/actions/build-dependency-image@v1 + with: + workbench-tag: ${{ vars.WORKBENCH_TAG || 'latest' }} + github-token: ${{ secrets.GITHUB_TOKEN }} + github-repository: ${{ github.repository }} + github-sha: ${{ github.sha }} + exact-image: ${{ steps.image.outputs.exact_image }} + latest-image: ${{ steps.image.outputs.latest_image }} + build-context: ${{ github.workspace }} + + prune-dependency-images: + name: "Prune Dependency Images" + runs-on: ubuntu-latest + needs: check-renv + steps: + - name: Prune any old dependency image layers + uses: carpentries/actions/prune-dependency-images@v1 + if: needs.check-renv.outputs.renv-needed == 'true' + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + owner: ${{ github.repository_owner }} + owner-type: ${{ github.event.repository.owner.type }} + repository: ${{ github.event.repository.name }} + package-name: ${{ github.event.repository.name }}-deps + keep-count: ${{ github.event.inputs.prune-keep-count }} + continue-on-error: true + + record-cache-result: + name: "Record Caching Status" + runs-on: ubuntu-latest + needs: [check-renv, update-renv-cache] + if: always() + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - name: "Record cache result" + run: | + echo "${{ needs.check-renv.outputs.renv-needed != 'true' || needs.update-renv-cache.result == 'success' }}" > ${{ github.workspace }}/apply-cache-result + shell: bash + + - name: "Upload cache result" + uses: actions/upload-artifact@v7 + with: + name: apply-cache-result + path: ${{ github.workspace }}/apply-cache-result diff --git a/.github/workflows/docker_build_deploy.yaml b/.github/workflows/docker_build_deploy.yaml new file mode 100644 index 0000000..bb0d0fd --- /dev/null +++ b/.github/workflows/docker_build_deploy.yaml @@ -0,0 +1,150 @@ +name: "01 Maintain: Build and Deploy Site" +description: "Build and deploy the lesson site using the carpentries/workbench-docker container" +on: + push: + branches: + - 'main' + - 'l10n_main' + paths-ignore: + - '.github/workflows/**.yaml' + - '.github/workbench-docker-version.txt' + schedule: + - cron: '0 0 * * 2' + workflow_run: + workflows: ["03 Maintain: Apply Package Cache"] + types: + - completed + workflow_dispatch: + inputs: + name: + description: 'Who triggered this build?' + required: true + default: 'Maintainer (via GitHub)' + CACHE_VERSION: + description: 'Optional renv cache version override' + required: false + default: '' + reset: + description: 'Reset cached markdown files' + required: true + default: false + type: boolean + force-skip-manage-deps: + description: 'Skip build-time dependency management' + required: true + default: false + type: boolean + +# only one build/deploy at a time +concurrency: + group: docker-build-deploy + cancel-in-progress: true + +jobs: + preflight: + name: "Preflight: Schedule, Push, or PR?" + runs-on: ubuntu-latest + outputs: + do-build: ${{ steps.build-check.outputs.do-build }} + renv-needed: ${{ steps.build-check.outputs.renv-needed }} + renv-cache-hashsum: ${{ steps.build-check.outputs.renv-cache-hashsum }} + dependency-image-ref: ${{ steps.build-check.outputs.dependency-image-ref }} + workbench-container-file-exists: ${{ steps.wb-vers.outputs.workbench-container-file-exists }} + wb-vers: ${{ steps.wb-vers.outputs.container-version }} + last-wb-vers: ${{ steps.wb-vers.outputs.last-container-version }} + workbench-update: ${{ steps.wb-vers.outputs.workbench-update }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - name: "Should we run build and deploy?" + id: build-check + uses: carpentries/actions/build-preflight@v1 + + - name: "Checkout Lesson" + if: steps.build-check.outputs.do-build == 'true' + uses: actions/checkout@v6 + + - name: "Get container version info" + id: wb-vers + if: steps.build-check.outputs.do-build == 'true' + uses: carpentries/actions/container-version@v1 + with: + WORKBENCH_TAG: ${{ vars.WORKBENCH_TAG }} + renv-needed: ${{ steps.build-check.outputs.renv-needed }} + token: ${{ secrets.GITHUB_TOKEN }} + + full-build: + name: "Build Full Site" + runs-on: ubuntu-latest + needs: preflight + if: | + needs.preflight.outputs.do-build == 'true' && + needs.preflight.outputs.workbench-update != 'true' + env: + RENV_EXISTS: ${{ needs.preflight.outputs.renv-needed }} + RENV_HASH: ${{ needs.preflight.outputs.renv-cache-hashsum }} + permissions: + checks: write + contents: write + pages: write + container: + image: ${{ needs.preflight.outputs.dependency-image-ref }} + env: + WORKBENCH_PROFILE: "ci" + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + RENV_PATHS_ROOT: /home/rstudio/lesson/renv + RENV_PROFILE: "lesson-requirements" + RENV_CONFIG_EXTERNAL_LIBRARIES: "/usr/local/lib/R/site-library" + volumes: + - ${{ github.workspace }}:/home/rstudio/lesson + options: --cpus 1 + steps: + - uses: actions/checkout@v6 + + - name: "Debugging Info" + run: | + cd /home/rstudio/lesson + echo "Current Directory: $(pwd)" + echo "RENV_HASH is $RENV_HASH" + ls -lah /home/rstudio/.workbench + ls -lah $(pwd) + Rscript -e 'sessionInfo()' + shell: bash + + - name: "Mark Repository as Safe" + run: | + git config --global --add safe.directory $(pwd) + shell: bash + + - name: "Run Container and Build Site" + id: build-and-deploy + uses: carpentries/actions/build-and-deploy@v1 + with: + reset: ${{ vars.BUILD_RESET || github.event.inputs.reset || 'false' }} + skip-manage-deps: ${{ github.event.inputs.force-skip-manage-deps == 'true' || contains(needs.preflight.outputs.dependency-image-ref, '-deps:') }} + lang-code: ${{ vars.LANG_CODE || '' }} + + update-container-version: + name: "Update container version used" + runs-on: ubuntu-latest + needs: [preflight] + permissions: + actions: write + contents: write + pull-requests: write + id-token: write + if: | + needs.preflight.outputs.do-build == 'true' && + ( + needs.preflight.outputs.workbench-container-file-exists == 'false' || + needs.preflight.outputs.workbench-update == 'true' + ) + steps: + - name: "Record container version used" + uses: carpentries/actions/record-container-version@v1 + with: + CONTAINER_VER: ${{ needs.preflight.outputs.wb-vers }} + AUTO_MERGE: ${{ vars.AUTO_MERGE_CONTAINER_VERSION_UPDATE || 'true' }} + token: ${{ secrets.GITHUB_TOKEN }} + role-to-assume: ${{ secrets.AWS_GH_OIDC_ARN }} + aws-region: ${{ secrets.AWS_GH_OIDC_REGION }} diff --git a/.github/workflows/docker_pr_receive.yaml b/.github/workflows/docker_pr_receive.yaml new file mode 100644 index 0000000..9ed11c9 --- /dev/null +++ b/.github/workflows/docker_pr_receive.yaml @@ -0,0 +1,221 @@ +name: "Bot: Receive Pull Request" +description: "Receive a pull request and build the markdown source files" +on: + pull_request: + types: + [opened, synchronize, reopened] + workflow_dispatch: + inputs: + pr_number: + type: number + required: true + +concurrency: + group: ${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + pull-requests: write + +jobs: + preflight: + name: "Preflight: md-outputs exists?" + runs-on: ubuntu-latest + outputs: + branch-exists: ${{ steps.check.outputs.exists }} + steps: + - name: "Checkout Lesson" + uses: actions/checkout@v6 + + - name: "Check if md-outputs branch exists" + id: check + run: | + # 💡 Checking for md-outputs branch # + if [[ -n $(git ls-remote --exit-code --heads origin md-outputs) ]]; then + echo "exists=true" >> $GITHUB_OUTPUT + else + echo "exists=false" >> $GITHUB_OUTPUT + echo "::error::md-outputs branch required but does not exist." + echo "::error::Please merge any open package update PRs to trigger the '03 Maintain: Apply Package Cache' and '01: Maintain: Build and Deploy Site' workflows." + + echo "## ❌ ERROR: md-outputs branch required" >> $GITHUB_STEP_SUMMARY + echo "Please merge any open package update PRs to trigger the '03 Maintain: Apply Package Cache' and '01: Maintain: Build and Deploy Site' workflows." >> $GITHUB_STEP_SUMMARY + + exit 1 + fi + shell: bash + + test-pr: + name: "Record PR number" + if: | + github.event.action != 'closed' && + needs.preflight.outputs.branch-exists == 'true' + runs-on: ubuntu-latest + needs: preflight + outputs: + is_valid: ${{ steps.check-pr.outputs.VALID }} + pr_number: ${{ env.NR }} + pr_branch: ${{ env.PR_BRANCH }} + steps: + - name: "Grab PR" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + if [[ "${{ github.event_name }}" == "pull_request" ]] ; then + PR_NUMBER=${{ github.event.number }} + elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]] ; then + PR_NUMBER=${{ inputs.pr_number }} + fi + + echo $PR_NUMBER > ${{ github.workspace }}/NR + echo "NR=$PR_NUMBER" >> $GITHUB_ENV + echo "PR_BRANCH=$(gh -R ${{ github.repository }} pr view $PR_NUMBER --json headRefName --jq '.headRefName')" >> $GITHUB_ENV + shell: bash + + - name: "Upload PR number" + id: upload + if: always() + uses: actions/upload-artifact@v7 + with: + name: pr + path: ${{ github.workspace }}/NR + + - name: "Get Invalid Hashes File" + id: hash + run: | + echo "json<> $GITHUB_OUTPUT + shell: bash + + - name: "Debug Hashes Output" + run: | + echo "${{ steps.hash.outputs.json }}" + shell: bash + + - name: "Check PR" + id: check-pr + uses: carpentries/actions/check-valid-pr@v1 + with: + pr: ${{ env.NR }} + invalid: ${{ fromJSON(steps.hash.outputs.json)[github.repository] }} + + check-renv: + name: "Check If We Need {renv}" + runs-on: ubuntu-latest + outputs: + renv-needed: ${{ steps.renv-check.outputs.renv-needed }} + renv-cache-hashsum: ${{ steps.renv-check.outputs.renv-cache-hashsum }} + dependency-image-ref: ${{ steps.renv-check.outputs.dependency-image-ref }} + steps: + - name: "Checkout Lesson" + uses: actions/checkout@v6 + + - name: "Is renv required?" + id: renv-check + uses: carpentries/actions/renv-checks@v1 + with: + CACHE_VERSION: ${{ inputs.CACHE_VERSION || '' }} + skip-cache-check: true + + build-md-source: + name: "Build markdown source files if valid" + needs: + - test-pr + - check-renv + runs-on: ubuntu-latest + if: needs.test-pr.outputs.is_valid == 'true' + env: + CHIVE: ${{ github.workspace }}/site/chive + PR: ${{ github.workspace }}/site/pr + GHWMD: ${{ github.workspace }}/site/built + PR_BRANCH: ${{ needs.test-pr.outputs.pr_branch }} + PR_NUMBER: ${{ needs.test-pr.outputs.pr_number }} + permissions: + contents: read + container: + image: ${{ needs.check-renv.outputs.dependency-image-ref }} + env: + WORKBENCH_PROFILE: "ci" + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RENV_PATHS_ROOT: /home/rstudio/lesson/renv + RENV_PROFILE: "lesson-requirements" + RENV_CONFIG_EXTERNAL_LIBRARIES: "/usr/local/lib/R/site-library" + volumes: + - ${{ github.workspace }}:/home/rstudio/lesson + options: --cpus 2 + outputs: + build-site: ${{ steps.build-site.outcome }} + steps: + - uses: actions/checkout@v6 + + - name: "Check Out Staging Branch" + uses: actions/checkout@v6 + with: + ref: md-outputs + path: ${{ env.GHWMD }} + + - name: Mark Repository as Safe + run: | + git config --global --add safe.directory $(pwd) + git config --global --add safe.directory /home/rstudio/lesson + shell: bash + + - name: "Ensure sandpaper is loadable" + run: | + .libPaths() + library(sandpaper) + shell: Rscript {0} + + - name: Setup Lesson Dependencies + run: | + Rscript /home/rstudio/.workbench/setup_lesson_deps.R + shell: bash + + - name: "Validate and Build Markdown" + id: build-site + run: | + sandpaper::package_cache_trigger(TRUE) + sandpaper::validate_lesson(path = '/home/rstudio/lesson') + sandpaper:::build_markdown(path = '/home/rstudio/lesson', quiet = FALSE) + shell: Rscript {0} + + - name: "Generate Artifacts" + id: generate-artifacts + run: | + sandpaper:::ci_bundle_pr_artifacts( + repo = '${{ github.repository }}', + pr_number = '${{ env.PR_NUMBER }}', + path_md = '/home/rstudio/lesson/site/built', + path_pr = '/home/rstudio/lesson/site/pr', + path_archive = '/home/rstudio/lesson/site/chive', + branch = 'md-outputs' + ) + shell: Rscript {0} + + - name: "Upload PR" + uses: actions/upload-artifact@v7 + with: + name: pr + path: ${{ env.PR }} + overwrite: true + + - name: "Upload Diff" + uses: actions/upload-artifact@v7 + with: + name: diff + path: ${{ env.CHIVE }} + retention-days: 1 + + - name: "Upload Build" + uses: actions/upload-artifact@v7 + with: + name: built + path: ${{ env.GHWMD }} + retention-days: 1 + + - name: "Teardown" + run: sandpaper::reset_site() + shell: Rscript {0} diff --git a/.github/workflows/pr-close-signal.yaml b/.github/workflows/pr-close-signal.yaml index b1303c2..de1f254 100644 --- a/.github/workflows/pr-close-signal.yaml +++ b/.github/workflows/pr-close-signal.yaml @@ -16,7 +16,7 @@ jobs: mkdir -p ./pr printf ${{ github.event.number }} > ./pr/NUM - name: Upload Diff - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: pr path: ./pr diff --git a/.github/workflows/pr-comment.yaml b/.github/workflows/pr-comment.yaml index f80d9d0..c292851 100644 --- a/.github/workflows/pr-comment.yaml +++ b/.github/workflows/pr-comment.yaml @@ -1,38 +1,28 @@ name: "Bot: Comment on the Pull Request" - -# read-write repo token -# access to secrets +description: "Comment on the pull request with the results of the markdown generation" on: workflow_run: - workflows: ["Receive Pull Request"] + workflows: ["Bot: Receive Pull Request"] types: - completed -concurrency: - group: pr-${{ github.event.workflow_run.pull_requests[0].number }} - cancel-in-progress: true - - jobs: # Pull requests are valid if: # - they match the sha of the workflow run head commit # - they are open - # - no .github files were committed + # - no .github files were committed, except for .github/workbench-docker-version.txt test-pr: name: "Test if pull request is valid" - runs-on: ubuntu-22.04 - if: > - github.event.workflow_run.event == 'pull_request' && - github.event.workflow_run.conclusion == 'success' + runs-on: ubuntu-latest outputs: is_valid: ${{ steps.check-pr.outputs.VALID }} payload: ${{ steps.check-pr.outputs.payload }} number: ${{ steps.get-pr.outputs.NUM }} msg: ${{ steps.check-pr.outputs.MSG }} steps: - - name: 'Download PR artifact' + - name: "Download PR artifact" id: dl - uses: carpentries/actions/download-workflow-artifact@main + uses: carpentries/actions/download-workflow-artifact@v1 with: run: ${{ github.event.workflow_run.id }} name: 'pr' @@ -50,16 +40,48 @@ jobs: run: | echo '::error::A pull request number was not recorded. The pull request that triggered this workflow is likely malicious.' exit 1 + + - name: "Checkout Lesson" + uses: actions/checkout@v6 + + - name: "Verify committed files" + id: changed-files + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + ## Get list of changed files in the PR ## + ONLY_VERSION=$(gh pr view ${{ steps.get-pr.outputs.NUM }} --json files --jq ' + .files | + length == 1 and + .[0].path == ".github/workbench-docker-version.txt" + ') + + if [[ "$ONLY_VERSION" == "true" ]]; then + echo "only_version_file=true" >> $GITHUB_OUTPUT + else + echo "only_version_file=false" >> $GITHUB_OUTPUT + fi + shell: bash + + - name: "Skip checks for Workbench version file updates" + if: steps.changed-files.outputs.only_version_file == 'true' + run: | + echo "# 🔧 Wait for Next Cache Update #" + echo "Only workbench-docker-version.txt changed." + exit 0 + shell: bash + - name: "Get Invalid Hashes File" id: hash run: | echo "json<> $GITHUB_OUTPUT + - name: "Check PR" id: check-pr if: ${{ steps.dl.outputs.success == 'true' }} - uses: carpentries/actions/check-valid-pr@main + uses: carpentries/actions/check-valid-pr@v1 with: pr: ${{ steps.get-pr.outputs.NUM }} sha: ${{ github.event.workflow_run.head_sha }} @@ -67,6 +89,14 @@ jobs: invalid: ${{ fromJSON(steps.hash.outputs.json)[github.repository] }} fail_on_error: true + - name: "Comment result of validation" + id: comment-diff + if: always() + uses: carpentries/actions/comment-diff@v1 + with: + pr: ${{ steps.get-pr.outputs.NUM }} + body: ${{ steps.check-pr.outputs.MSG }} + # Create an orphan branch on this repository with two commits # - the current HEAD of the md-outputs branch # - the output from running the current HEAD of the pull request through @@ -74,32 +104,32 @@ jobs: create-branch: name: "Create Git Branch" needs: test-pr - runs-on: ubuntu-22.04 - if: ${{ needs.test-pr.outputs.is_valid == 'true' }} + runs-on: ubuntu-latest + if: needs.test-pr.outputs.is_valid == 'true' env: NR: ${{ needs.test-pr.outputs.number }} permissions: contents: write steps: - - name: 'Checkout md outputs' - uses: actions/checkout@v4 + - name: "Checkout md outputs" + uses: actions/checkout@v6 with: ref: md-outputs path: built fetch-depth: 1 - - name: 'Download built markdown' + - name: "Download built markdown" id: dl - uses: carpentries/actions/download-workflow-artifact@main + uses: carpentries/actions/download-workflow-artifact@v1 with: run: ${{ github.event.workflow_run.id }} name: 'built' - - if: ${{ steps.dl.outputs.success == 'true' }} + - if: steps.dl.outputs.success == 'true' run: unzip built.zip - name: "Create orphan and push" - if: ${{ steps.dl.outputs.success == 'true' }} + if: steps.dl.outputs.success == 'true' run: | cd built/ git config --local user.email "actions@github.com" @@ -120,27 +150,27 @@ jobs: comment-pr: name: "Comment on Pull Request" needs: [test-pr, create-branch] - runs-on: ubuntu-22.04 - if: ${{ needs.test-pr.outputs.is_valid == 'true' }} + runs-on: ubuntu-latest + if: needs.test-pr.outputs.is_valid == 'true' env: NR: ${{ needs.test-pr.outputs.number }} permissions: pull-requests: write steps: - - name: 'Download comment artifact' + - name: "Download comment artifact" id: dl - uses: carpentries/actions/download-workflow-artifact@main + uses: carpentries/actions/download-workflow-artifact@v1 with: run: ${{ github.event.workflow_run.id }} name: 'diff' - - if: ${{ steps.dl.outputs.success == 'true' }} + - if: steps.dl.outputs.success == 'true' run: unzip ${{ github.workspace }}/diff.zip - name: "Comment on PR" id: comment-diff - if: ${{ steps.dl.outputs.success == 'true' }} - uses: carpentries/actions/comment-diff@main + if: steps.dl.outputs.success == 'true' + uses: carpentries/actions/comment-diff@v1 with: pr: ${{ env.NR }} path: ${{ github.workspace }}/diff.md @@ -150,24 +180,26 @@ jobs: comment-changed-workflow: name: "Comment if workflow files have changed" needs: test-pr - runs-on: ubuntu-22.04 - if: ${{ always() && needs.test-pr.outputs.is_valid == 'false' }} + runs-on: ubuntu-latest + if: | + always() && + needs.test-pr.outputs.is_valid == 'false' env: - NR: ${{ github.event.workflow_run.pull_requests[0].number }} + NR: ${{ needs.test-pr.outputs.number }} body: ${{ needs.test-pr.outputs.msg }} permissions: pull-requests: write steps: - - name: 'Check for spoofing' + - name: "Check for spoofing" id: dl - uses: carpentries/actions/download-workflow-artifact@main + uses: carpentries/actions/download-workflow-artifact@v1 with: run: ${{ github.event.workflow_run.id }} name: 'built' - - name: 'Alert if spoofed' + - name: "Alert if spoofed" id: spoof - if: ${{ steps.dl.outputs.success == 'true' }} + if: steps.dl.outputs.success == 'true' run: | echo 'body<> $GITHUB_ENV echo '' >> $GITHUB_ENV @@ -178,7 +210,7 @@ jobs: - name: "Comment on PR" id: comment-diff - uses: carpentries/actions/comment-diff@main + uses: carpentries/actions/comment-diff@v1 with: pr: ${{ env.NR }} body: ${{ env.body }} diff --git a/.github/workflows/pr-post-remove-branch.yaml b/.github/workflows/pr-post-remove-branch.yaml index 9419e2b..ebbe22d 100644 --- a/.github/workflows/pr-post-remove-branch.yaml +++ b/.github/workflows/pr-post-remove-branch.yaml @@ -17,7 +17,7 @@ jobs: contents: write steps: - name: 'Download artifact' - uses: carpentries/actions/download-workflow-artifact@main + uses: carpentries/actions/download-workflow-artifact@v1 with: run: ${{ github.event.workflow_run.id }} name: pr @@ -27,6 +27,6 @@ jobs: unzip pr.zip echo "NUM=$(<./NUM)" >> $GITHUB_OUTPUT - name: 'Remove branch' - uses: carpentries/actions/remove-branch@main + uses: carpentries/actions/remove-branch@v1 with: pr: ${{ steps.get-pr.outputs.NUM }} diff --git a/.github/workflows/pr-preflight.yaml b/.github/workflows/pr-preflight.yaml index 34ad7ae..d292d91 100644 --- a/.github/workflows/pr-preflight.yaml +++ b/.github/workflows/pr-preflight.yaml @@ -11,7 +11,7 @@ jobs: test-pr: name: "Test if pull request is valid" if: ${{ github.event.action != 'closed' }} - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest outputs: is_valid: ${{ steps.check-pr.outputs.VALID }} permissions: @@ -25,7 +25,7 @@ jobs: EOF" >> $GITHUB_OUTPUT - name: "Check PR" id: check-pr - uses: carpentries/actions/check-valid-pr@main + uses: carpentries/actions/check-valid-pr@v1 with: pr: ${{ github.event.number }} invalid: ${{ fromJSON(steps.hash.outputs.json)[github.repository] }} @@ -33,7 +33,7 @@ jobs: - name: "Comment result of validation" id: comment-diff if: ${{ always() }} - uses: carpentries/actions/comment-diff@main + uses: carpentries/actions/comment-diff@v1 with: pr: ${{ github.event.number }} body: ${{ steps.check-pr.outputs.MSG }} diff --git a/.github/workflows/pr-receive.yaml b/.github/workflows/pr-receive.yaml deleted file mode 100644 index 7fbff6c..0000000 --- a/.github/workflows/pr-receive.yaml +++ /dev/null @@ -1,132 +0,0 @@ -name: "Receive Pull Request" - -on: - pull_request: - types: - [opened, synchronize, reopened] - -concurrency: - group: ${{ github.ref }} - cancel-in-progress: true - -jobs: - test-pr: - name: "Record PR number" - if: ${{ github.event.action != 'closed' }} - runs-on: ubuntu-22.04 - outputs: - is_valid: ${{ steps.check-pr.outputs.VALID }} - steps: - - name: "Record PR number" - id: record - if: ${{ always() }} - run: | - echo ${{ github.event.number }} > ${{ github.workspace }}/NR # 2022-03-02: artifact name fixed to be NR - - name: "Upload PR number" - id: upload - if: ${{ always() }} - uses: actions/upload-artifact@v4 - with: - name: pr - path: ${{ github.workspace }}/NR - - name: "Get Invalid Hashes File" - id: hash - run: | - echo "json<> $GITHUB_OUTPUT - - name: "echo output" - run: | - echo "${{ steps.hash.outputs.json }}" - - name: "Check PR" - id: check-pr - uses: carpentries/actions/check-valid-pr@main - with: - pr: ${{ github.event.number }} - invalid: ${{ fromJSON(steps.hash.outputs.json)[github.repository] }} - - build-md-source: - name: "Build markdown source files if valid" - needs: test-pr - runs-on: ubuntu-22.04 - if: ${{ needs.test-pr.outputs.is_valid == 'true' }} - env: - GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - RENV_PATHS_ROOT: ~/.local/share/renv/ - CHIVE: ${{ github.workspace }}/site/chive - PR: ${{ github.workspace }}/site/pr - MD: ${{ github.workspace }}/site/built - steps: - - name: "Check Out Main Branch" - uses: actions/checkout@v4 - - - name: "Check Out Staging Branch" - uses: actions/checkout@v4 - with: - ref: md-outputs - path: ${{ env.MD }} - - - name: "Set up R" - uses: r-lib/actions/setup-r@v2 - with: - use-public-rspm: true - install-r: false - - - name: "Set up Pandoc" - uses: r-lib/actions/setup-pandoc@v2 - - - name: "Setup Lesson Engine" - uses: carpentries/actions/setup-sandpaper@main - with: - cache-version: ${{ secrets.CACHE_VERSION }} - - - name: "Setup Package Cache" - uses: carpentries/actions/setup-lesson-deps@main - with: - cache-version: ${{ secrets.CACHE_VERSION }} - - - name: "Validate and Build Markdown" - id: build-site - run: | - sandpaper::package_cache_trigger(TRUE) - sandpaper::validate_lesson(path = '${{ github.workspace }}') - sandpaper:::build_markdown(path = '${{ github.workspace }}', quiet = FALSE) - shell: Rscript {0} - - - name: "Generate Artifacts" - id: generate-artifacts - run: | - sandpaper:::ci_bundle_pr_artifacts( - repo = '${{ github.repository }}', - pr_number = '${{ github.event.number }}', - path_md = '${{ env.MD }}', - path_pr = '${{ env.PR }}', - path_archive = '${{ env.CHIVE }}', - branch = 'md-outputs' - ) - shell: Rscript {0} - - - name: "Upload PR" - uses: actions/upload-artifact@v4 - with: - name: pr - path: ${{ env.PR }} - overwrite: true - - - name: "Upload Diff" - uses: actions/upload-artifact@v4 - with: - name: diff - path: ${{ env.CHIVE }} - retention-days: 1 - - - name: "Upload Build" - uses: actions/upload-artifact@v4 - with: - name: built - path: ${{ env.MD }} - retention-days: 1 - - - name: "Teardown" - run: sandpaper::reset_site() - shell: Rscript {0} diff --git a/.github/workflows/sandpaper-main.yaml b/.github/workflows/sandpaper-main.yaml deleted file mode 100644 index b3d1de8..0000000 --- a/.github/workflows/sandpaper-main.yaml +++ /dev/null @@ -1,64 +0,0 @@ -name: "01 Build and Deploy Site" - -on: - push: - branches: - - main - - master - schedule: - - cron: '0 0 * * 2' - workflow_dispatch: - inputs: - name: - description: 'Who triggered this build?' - required: true - default: 'Maintainer (via GitHub)' - reset: - description: 'Reset cached markdown files' - required: false - default: false - type: boolean -jobs: - full-build: - name: "Build Full Site" - - # 2024-10-01: ubuntu-latest is now 24.04 and R is not installed by default in the runner image - # pin to 22.04 for now - runs-on: ubuntu-22.04 - permissions: - checks: write - contents: write - pages: write - env: - GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - RENV_PATHS_ROOT: ~/.local/share/renv/ - steps: - - - name: "Checkout Lesson" - uses: actions/checkout@v4 - - - name: "Set up R" - uses: r-lib/actions/setup-r@v2 - with: - use-public-rspm: true - install-r: false - - - name: "Set up Pandoc" - uses: r-lib/actions/setup-pandoc@v2 - - - name: "Setup Lesson Engine" - uses: carpentries/actions/setup-sandpaper@main - with: - cache-version: ${{ secrets.CACHE_VERSION }} - - - name: "Setup Package Cache" - uses: carpentries/actions/setup-lesson-deps@main - with: - cache-version: ${{ secrets.CACHE_VERSION }} - - - name: "Deploy Site" - run: | - reset <- "${{ github.event.inputs.reset }}" == "true" - sandpaper::package_cache_trigger(TRUE) - sandpaper:::ci_deploy(reset = reset) - shell: Rscript {0} diff --git a/.github/workflows/sandpaper-version.txt b/.github/workflows/sandpaper-version.txt deleted file mode 100644 index f2f6c13..0000000 --- a/.github/workflows/sandpaper-version.txt +++ /dev/null @@ -1 +0,0 @@ -0.16.11 diff --git a/.github/workflows/update-cache.yaml b/.github/workflows/update-cache.yaml index a011c0c..b711f2d 100644 --- a/.github/workflows/update-cache.yaml +++ b/.github/workflows/update-cache.yaml @@ -1,26 +1,45 @@ -name: "03 Maintain: Update Package Cache" - +name: "02 Maintain: Check for Updated Packages" +description: "Check for updated R packages and create a pull request to update the lesson's renv lockfile and package cache" on: + schedule: + - cron: '0 0 * * 2' # every Tuesday at midnight UTC workflow_dispatch: inputs: name: - description: 'Who triggered this build (enter github username to tag yourself)?' + description: 'Who triggered this build?' required: true - default: 'monthly run' - schedule: - # Run every tuesday - - cron: '0 0 * * 2' + default: 'Maintainer (via GitHub)' + force-renv-init: + description: 'Force full lockfile update?' + required: false + default: false + type: boolean + update-packages: + description: 'Install any package updates?' + required: false + default: true + type: boolean + generate-cache: + description: 'Generate separate package cache?' + required: false + default: false + type: boolean + +env: + LOCKFILE_CACHE_GEN: ${{ vars.LOCKFILE_CACHE_GEN || github.event.inputs.generate-cache || 'false' }} + FORCE_RENV_INIT: ${{ vars.FORCE_RENV_INIT || github.event.inputs.force-renv-init || 'false' }} + UPDATE_PACKAGES: ${{ vars.UPDATE_PACKAGES || github.event.inputs.update-packages || 'true' }} jobs: preflight: - name: "Preflight Check" - runs-on: ubuntu-22.04 + name: "Preflight: Manual or Scheduled Trigger?" + runs-on: ubuntu-latest outputs: ok: ${{ steps.check.outputs.ok }} steps: - id: check run: | - if [[ ${{ github.event_name }} == 'workflow_dispatch' ]]; then + if [[ "${{ github.event_name }}" == 'workflow_dispatch' ]]; then echo "ok=true" >> $GITHUB_OUTPUT echo "Running on request" # using single brackets here to avoid 08 being interpreted as octal @@ -33,50 +52,44 @@ jobs: echo "ok=false" >> $GITHUB_OUTPUT echo "Not Running Today" fi + shell: bash - check_renv: - name: "Check if We Need {renv}" - runs-on: ubuntu-22.04 + check-renv: + name: "Check If We Need {renv}" + runs-on: ubuntu-latest needs: preflight - if: ${{ needs.preflight.outputs.ok == 'true'}} + if: ${{ needs.preflight.outputs.ok == 'true' }} outputs: - needed: ${{ steps.renv.outputs.exists }} + renv-needed: ${{ steps.renv-check.outputs.renv-needed }} steps: - name: "Checkout Lesson" - uses: actions/checkout@v4 - - id: renv - run: | - if [[ -d renv ]]; then - echo "exists=true" >> $GITHUB_OUTPUT - fi + uses: actions/checkout@v6 - check_token: - name: "Check SANDPAPER_WORKFLOW token" - runs-on: ubuntu-22.04 - needs: check_renv - if: ${{ needs.check_renv.outputs.needed == 'true' }} - outputs: - workflow: ${{ steps.validate.outputs.wf }} - repo: ${{ steps.validate.outputs.repo }} - steps: - - name: "validate token" - id: validate - uses: carpentries/actions/check-valid-credentials@main + - name: "Is renv required?" + id: renv-check + uses: carpentries/actions/renv-checks@v1 with: - token: ${{ secrets.SANDPAPER_WORKFLOW }} + CACHE_VERSION: ${{ inputs.CACHE_VERSION || '' }} + skip-cache-check: true update_cache: - name: "Update Package Cache" - needs: check_token - if: ${{ needs.check_token.outputs.repo== 'true' }} + name: "Create Package Update Pull Request" runs-on: ubuntu-22.04 + needs: check-renv + permissions: + contents: write + pull-requests: write + actions: write + issues: write + id-token: write + if: needs.check-renv.outputs.renv-needed == 'true' env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} RENV_PATHS_ROOT: ~/.local/share/renv/ steps: - - name: "Checkout Lesson" - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: "Set up R" uses: r-lib/actions/setup-r@v2 @@ -86,16 +99,62 @@ jobs: - name: "Update {renv} deps and determine if a PR is needed" id: update - uses: carpentries/actions/update-lockfile@main + uses: carpentries/actions/update-lockfile@v1 with: + update: ${{ env.UPDATE_PACKAGES }} + force-renv-init: ${{ env.FORCE_RENV_INIT }} + generate-cache: ${{ env.LOCKFILE_CACHE_GEN }} cache-version: ${{ secrets.CACHE_VERSION }} - - name: Create Pull Request + - name: "Validate Current Org and Workflow" + id: validate-org-workflow + uses: carpentries/actions/validate-org-workflow@v1 + with: + repo: ${{ github.repository }} + workflow: ${{ github.workflow }} + + - name: "Configure AWS credentials via OIDC" + env: + role-to-assume: ${{ secrets.AWS_GH_OIDC_ARN }} + aws-region: ${{ secrets.AWS_GH_OIDC_REGION }} + if: | + steps.validate-org-workflow.outputs.is_valid == 'true' && + env.role-to-assume != '' && + env.aws-region != '' + uses: aws-actions/configure-aws-credentials@v6 + with: + role-to-assume: ${{ env.role-to-assume }} + aws-region: ${{ env.aws-region }} + + - name: "Set PAT from AWS Secrets Manager" + env: + role-to-assume: ${{ secrets.AWS_GH_OIDC_ARN }} + aws-region: ${{ secrets.AWS_GH_OIDC_REGION }} + if: | + steps.validate-org-workflow.outputs.is_valid == 'true' && + env.role-to-assume != '' && + env.aws-region != '' + id: set-pat + run: | + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id carpentries-bot/github-pat \ + --query SecretString --output text) + PAT=$(echo "$SECRET" | jq -r .[]) + echo "::add-mask::$PAT" + echo "pat=$PAT" >> "$GITHUB_OUTPUT" + shell: bash + + # Create the PR with the following roles in order of preference: + # - Carpentries Bot classic PAT fetched from AWS (will only work in official Carpentries repos) + # - repo-scoped SANDPAPER_WORKFLOW classic PAT (will work in all scenarios) + # - default GITHUB_TOKEN (will work suitably, but workflows need to be triggered) + - name: "Create Pull Request" id: cpr - if: ${{ steps.update.outputs.n > 0 }} + if: | + steps.update.outputs.n > 0 uses: carpentries/create-pull-request@main with: - token: ${{ secrets.SANDPAPER_WORKFLOW }} + token: ${{ steps.set-pat.outputs.pat || secrets.SANDPAPER_WORKFLOW }} delete-branch: true branch: "update/packages" commit-message: "[actions] update ${{ steps.update.outputs.n }} packages" @@ -123,3 +182,9 @@ jobs: [1]: https://github.com/carpentries/create-pull-request/tree/main labels: "type: package cache" draft: false + + - name: "Skip PR creation" + if: steps.update.outputs.n == 0 + run: | + echo "No updates needed, skipping PR creation" + shell: bash diff --git a/.github/workflows/update-workflows.yaml b/.github/workflows/update-workflows.yaml index 6414cf2..6d63a32 100644 --- a/.github/workflows/update-workflows.yaml +++ b/.github/workflows/update-workflows.yaml @@ -1,55 +1,106 @@ -name: "02 Maintain: Update Workflow Files" +name: "04 Maintain: Update Workflow Files" +description: "Update workflow files from the carpentries/sandpaper repository" on: + schedule: + - cron: '0 0 * * 2' workflow_dispatch: inputs: name: description: 'Who triggered this build (enter github username to tag yourself)?' required: true default: 'weekly run' + version: + description: 'Workflows version number (e.g. 0.0.1), branch name (e.g. main), or "latest"' + required: false + default: 'latest' clean: description: 'Workflow files/file extensions to clean (no wildcards, enter "" for none)' required: false default: '.yaml' - schedule: - # Run every Tuesday - - cron: '0 0 * * 2' jobs: - check_token: - name: "Check SANDPAPER_WORKFLOW token" - runs-on: ubuntu-22.04 - outputs: - workflow: ${{ steps.validate.outputs.wf }} - repo: ${{ steps.validate.outputs.repo }} - steps: - - name: "validate token" - id: validate - uses: carpentries/actions/check-valid-credentials@main - with: - token: ${{ secrets.SANDPAPER_WORKFLOW }} - update_workflow: name: "Update Workflow" - runs-on: ubuntu-22.04 - needs: check_token - if: ${{ needs.check_token.outputs.workflow == 'true' }} + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + id-token: write steps: - name: "Checkout Repository" - uses: actions/checkout@v4 + uses: actions/checkout@v6 + + - name: "Validate Current Org and Workflow" + id: validate-org-workflow + uses: carpentries/actions/validate-org-workflow@v1 + with: + repo: ${{ github.repository }} + workflow: ${{ github.workflow }} + + - name: Configure AWS credentials via OIDC + env: + role-to-assume: ${{ secrets.AWS_GH_OIDC_ARN }} + aws-region: ${{ secrets.AWS_GH_OIDC_REGION }} + if: | + steps.validate-org-workflow.outputs.is_valid == 'true' && + env.role-to-assume != '' && + env.aws-region != '' + uses: aws-actions/configure-aws-credentials@v6 + with: + role-to-assume: ${{ env.role-to-assume }} + aws-region: ${{ env.aws-region }} + + - name: Set PAT from AWS Secrets Manager + id: set-pat + env: + role-to-assume: ${{ secrets.AWS_GH_OIDC_ARN }} + aws-region: ${{ secrets.AWS_GH_OIDC_REGION }} + if: | + steps.validate-org-workflow.outputs.is_valid == 'true' && + env.role-to-assume != '' && + env.aws-region != '' + run: | + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id carpentries-bot/github-pat \ + --query SecretString --output text) + PAT=$(echo "$SECRET" | jq -r .[]) + echo "::add-mask::$PAT" + echo "pat=$PAT" >> "$GITHUB_OUTPUT" + shell: bash + + - name: "Validate token" + id: validate-token + uses: carpentries/actions/check-valid-credentials@v1 + with: + token: ${{ steps.set-pat.outputs.pat || secrets.SANDPAPER_WORKFLOW }} + + - name: "No Token Found: Skipping Workflow Update" + if: ${{ steps.validate-token.outputs.wf == 'false' }} + run: | + echo "❗No valid SANDPAPER_WORKFLOW token or PAT from AWS found, cannot update workflows." + + echo "## ❌ Workflow Update Failed" >> $GITHUB_STEP_SUMMARY + echo "No valid SANDPAPER_WORKFLOW token or PAT from AWS found, cannot update workflows." >> $GITHUB_STEP_SUMMARY + shell: bash - name: Update Workflows id: update - uses: carpentries/actions/update-workflows@main + if: ${{ steps.validate-token.outputs.wf == 'true' }} + uses: carpentries/actions/update-workflows@v1 with: - clean: ${{ github.event.inputs.clean }} + version: ${{ github.event.inputs.version || 'latest' }} + clean: ${{ github.event.inputs.clean || '.yaml' }} + token: ${{ steps.set-pat.outputs.pat || secrets.SANDPAPER_WORKFLOW }} - name: Create Pull Request id: cpr - if: "${{ steps.update.outputs.new }}" + if: | + steps.update.outputs.new && + steps.validate-token.outputs.wf == 'true' uses: carpentries/create-pull-request@main with: - token: ${{ secrets.SANDPAPER_WORKFLOW }} + token: ${{ steps.set-pat.outputs.pat || secrets.SANDPAPER_WORKFLOW }} delete-branch: true branch: "update/workflows" commit-message: "[actions] update sandpaper workflow to version ${{ steps.update.outputs.new }}" @@ -62,5 +113,5 @@ jobs: - Auto-generated by [create-pull-request][1] on ${{ steps.update.outputs.date }} [1]: https://github.com/carpentries/create-pull-request/tree/main - labels: "type: template and tools" + labels: "type: workflows" draft: false diff --git a/.github/workflows/workflows-version.txt b/.github/workflows/workflows-version.txt new file mode 100644 index 0000000..570c796 --- /dev/null +++ b/.github/workflows/workflows-version.txt @@ -0,0 +1 @@ +v1.0.2 From 8d1cd9a4ceddc869a99d8d9448aec0692cd2bc94 Mon Sep 17 00:00:00 2001 From: Douglas Lowe <10961945+douglowe@users.noreply.github.com> Date: Fri, 2 Oct 2026 16:01:22 +0100 Subject: [PATCH 2/5] remove carpentries specific workflow update workflow --- .github/workflows/update-workflows.yaml | 117 ------------------------ 1 file changed, 117 deletions(-) delete mode 100644 .github/workflows/update-workflows.yaml diff --git a/.github/workflows/update-workflows.yaml b/.github/workflows/update-workflows.yaml deleted file mode 100644 index 6d63a32..0000000 --- a/.github/workflows/update-workflows.yaml +++ /dev/null @@ -1,117 +0,0 @@ -name: "04 Maintain: Update Workflow Files" -description: "Update workflow files from the carpentries/sandpaper repository" - -on: - schedule: - - cron: '0 0 * * 2' - workflow_dispatch: - inputs: - name: - description: 'Who triggered this build (enter github username to tag yourself)?' - required: true - default: 'weekly run' - version: - description: 'Workflows version number (e.g. 0.0.1), branch name (e.g. main), or "latest"' - required: false - default: 'latest' - clean: - description: 'Workflow files/file extensions to clean (no wildcards, enter "" for none)' - required: false - default: '.yaml' - -jobs: - update_workflow: - name: "Update Workflow" - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - id-token: write - steps: - - name: "Checkout Repository" - uses: actions/checkout@v6 - - - name: "Validate Current Org and Workflow" - id: validate-org-workflow - uses: carpentries/actions/validate-org-workflow@v1 - with: - repo: ${{ github.repository }} - workflow: ${{ github.workflow }} - - - name: Configure AWS credentials via OIDC - env: - role-to-assume: ${{ secrets.AWS_GH_OIDC_ARN }} - aws-region: ${{ secrets.AWS_GH_OIDC_REGION }} - if: | - steps.validate-org-workflow.outputs.is_valid == 'true' && - env.role-to-assume != '' && - env.aws-region != '' - uses: aws-actions/configure-aws-credentials@v6 - with: - role-to-assume: ${{ env.role-to-assume }} - aws-region: ${{ env.aws-region }} - - - name: Set PAT from AWS Secrets Manager - id: set-pat - env: - role-to-assume: ${{ secrets.AWS_GH_OIDC_ARN }} - aws-region: ${{ secrets.AWS_GH_OIDC_REGION }} - if: | - steps.validate-org-workflow.outputs.is_valid == 'true' && - env.role-to-assume != '' && - env.aws-region != '' - run: | - SECRET=$(aws secretsmanager get-secret-value \ - --secret-id carpentries-bot/github-pat \ - --query SecretString --output text) - PAT=$(echo "$SECRET" | jq -r .[]) - echo "::add-mask::$PAT" - echo "pat=$PAT" >> "$GITHUB_OUTPUT" - shell: bash - - - name: "Validate token" - id: validate-token - uses: carpentries/actions/check-valid-credentials@v1 - with: - token: ${{ steps.set-pat.outputs.pat || secrets.SANDPAPER_WORKFLOW }} - - - name: "No Token Found: Skipping Workflow Update" - if: ${{ steps.validate-token.outputs.wf == 'false' }} - run: | - echo "❗No valid SANDPAPER_WORKFLOW token or PAT from AWS found, cannot update workflows." - - echo "## ❌ Workflow Update Failed" >> $GITHUB_STEP_SUMMARY - echo "No valid SANDPAPER_WORKFLOW token or PAT from AWS found, cannot update workflows." >> $GITHUB_STEP_SUMMARY - shell: bash - - - name: Update Workflows - id: update - if: ${{ steps.validate-token.outputs.wf == 'true' }} - uses: carpentries/actions/update-workflows@v1 - with: - version: ${{ github.event.inputs.version || 'latest' }} - clean: ${{ github.event.inputs.clean || '.yaml' }} - token: ${{ steps.set-pat.outputs.pat || secrets.SANDPAPER_WORKFLOW }} - - - name: Create Pull Request - id: cpr - if: | - steps.update.outputs.new && - steps.validate-token.outputs.wf == 'true' - uses: carpentries/create-pull-request@main - with: - token: ${{ steps.set-pat.outputs.pat || secrets.SANDPAPER_WORKFLOW }} - delete-branch: true - branch: "update/workflows" - commit-message: "[actions] update sandpaper workflow to version ${{ steps.update.outputs.new }}" - title: "Update Workflows to Version ${{ steps.update.outputs.new }}" - body: | - :robot: This is an automated build - - Update Workflows from sandpaper version ${{ steps.update.outputs.old }} -> ${{ steps.update.outputs.new }} - - - Auto-generated by [create-pull-request][1] on ${{ steps.update.outputs.date }} - - [1]: https://github.com/carpentries/create-pull-request/tree/main - labels: "type: workflows" - draft: false From 0b91fc4dce849ce36186454a537f155cc8fbe6fb Mon Sep 17 00:00:00 2001 From: Douglas Lowe <10961945+douglowe@users.noreply.github.com> Date: Fri, 2 Oct 2026 16:41:38 +0100 Subject: [PATCH 3/5] remove R markdown file and environment --- episodes/introduction.Rmd | 111 -- renv/activate.R | 1313 ----------------- renv/profile | 1 - renv/profiles/lesson-requirements/renv.lock | 996 ------------- .../lesson-requirements/renv/.gitignore | 7 - .../lesson-requirements/renv/settings.json | 19 - 6 files changed, 2447 deletions(-) delete mode 100644 episodes/introduction.Rmd delete mode 100644 renv/activate.R delete mode 100644 renv/profile delete mode 100644 renv/profiles/lesson-requirements/renv.lock delete mode 100644 renv/profiles/lesson-requirements/renv/.gitignore delete mode 100644 renv/profiles/lesson-requirements/renv/settings.json diff --git a/episodes/introduction.Rmd b/episodes/introduction.Rmd deleted file mode 100644 index 77edfd7..0000000 --- a/episodes/introduction.Rmd +++ /dev/null @@ -1,111 +0,0 @@ ---- -title: 'introduction' -teaching: 10 -exercises: 2 ---- - -:::::::::::::::::::::::::::::::::::::: questions - -- How do you write a lesson using R Markdown and `{sandpaper}`? - -:::::::::::::::::::::::::::::::::::::::::::::::: - -::::::::::::::::::::::::::::::::::::: objectives - -- Explain how to use markdown with the new lesson template -- Demonstrate how to include pieces of code, figures, and nested challenge blocks - -:::::::::::::::::::::::::::::::::::::::::::::::: - -## Introduction - -This is a lesson created via The Carpentries Workbench. It is written in -[Pandoc-flavored Markdown][pandoc] for static files (with extension `.md`) and -[R Markdown][r-markdown] for dynamic files that can render code into output -(with extension `.Rmd`). Please refer to the [Introduction to The Carpentries -Workbench][carpentries-workbench] for full documentation. - -What you need to know is that there are three sections required for a valid -Carpentries lesson template: - - 1. `questions` are displayed at the beginning of the episode to prime the - learner for the content. - 2. `objectives` are the learning objectives for an episode displayed with - the questions. - 3. `keypoints` are displayed at the end of the episode to reinforce the - objectives. - -:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: instructor - -Inline instructor notes can help inform instructors of timing challenges -associated with the lessons. They appear in the "Instructor View" - -:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - -::::::::::::::::::::::::::::::::::::: challenge - -## Challenge 1: Can you do it? - -What is the output of this command? - -```r -paste("This", "new", "lesson", "looks", "good") -``` - -:::::::::::::::::::::::: solution - -## Output - -```output -[1] "This new lesson looks good" -``` - -::::::::::::::::::::::::::::::::: - - -## Challenge 2: how do you nest solutions within challenge blocks? - -:::::::::::::::::::::::: solution - -You can add a line with at least three colons and a `solution` tag. - -::::::::::::::::::::::::::::::::: -:::::::::::::::::::::::::::::::::::::::::::::::: - -## Figures - -You can include figures generated from R Markdown: - -```{r pyramid, fig.alt = "pie chart illusion of a pyramid", fig.cap = "Sun arise each and every morning"} -pie( - c(Sky = 78, "Sunny side of pyramid" = 17, "Shady side of pyramid" = 5), - init.angle = 315, - col = c("deepskyblue", "yellow", "yellow3"), - border = FALSE -) -``` -Or you can use pandoc markdown for static figures with the following syntax: - -`![optional caption that appears below the figure](figure url){alt='alt text for -accessibility purposes'}` - -![You belong in The Carpentries!](https://raw.githubusercontent.com/carpentries/logo/master/Badge_Carpentries.svg){alt='Blue Carpentries hex person logo with no text.'} - -## Math - -One of our episodes contains $\LaTeX$ equations when describing how to create -dynamic reports with {knitr}, so we now use mathjax to describe this: - -`$\alpha = \dfrac{1}{(1 - \beta)^2}$` becomes: $\alpha = \dfrac{1}{(1 - \beta)^2}$ - -Cool, right? - -::::::::::::::::::::::::::::::::::::: keypoints - -- Use `.md` files for episodes when you want static content -- Use `.Rmd` files for episodes when you need to generate output -- Run `sandpaper::check_lesson()` to identify any issues with your lesson -- Run `sandpaper::build_lesson()` to preview your lesson locally - -:::::::::::::::::::::::::::::::::::::::::::::::: - diff --git a/renv/activate.R b/renv/activate.R deleted file mode 100644 index c9f5942..0000000 --- a/renv/activate.R +++ /dev/null @@ -1,1313 +0,0 @@ - -local({ - - # the requested version of renv - version <- "1.1.2" - attr(version, "sha") <- NULL - - # the project directory - project <- Sys.getenv("RENV_PROJECT") - if (!nzchar(project)) - project <- getwd() - - # use start-up diagnostics if enabled - diagnostics <- Sys.getenv("RENV_STARTUP_DIAGNOSTICS", unset = "FALSE") - if (diagnostics) { - start <- Sys.time() - profile <- tempfile("renv-startup-", fileext = ".Rprof") - utils::Rprof(profile) - on.exit({ - utils::Rprof(NULL) - elapsed <- signif(difftime(Sys.time(), start, units = "auto"), digits = 2L) - writeLines(sprintf("- renv took %s to run the autoloader.", format(elapsed))) - writeLines(sprintf("- Profile: %s", profile)) - print(utils::summaryRprof(profile)) - }, add = TRUE) - } - - # figure out whether the autoloader is enabled - enabled <- local({ - - # first, check config option - override <- getOption("renv.config.autoloader.enabled") - if (!is.null(override)) - return(override) - - # if we're being run in a context where R_LIBS is already set, - # don't load -- presumably we're being run as a sub-process and - # the parent process has already set up library paths for us - rcmd <- Sys.getenv("R_CMD", unset = NA) - rlibs <- Sys.getenv("R_LIBS", unset = NA) - if (!is.na(rlibs) && !is.na(rcmd)) - return(FALSE) - - # next, check environment variables - # prefer using the configuration one in the future - envvars <- c( - "RENV_CONFIG_AUTOLOADER_ENABLED", - "RENV_AUTOLOADER_ENABLED", - "RENV_ACTIVATE_PROJECT" - ) - - for (envvar in envvars) { - envval <- Sys.getenv(envvar, unset = NA) - if (!is.na(envval)) - return(tolower(envval) %in% c("true", "t", "1")) - } - - # enable by default - TRUE - - }) - - # bail if we're not enabled - if (!enabled) { - - # if we're not enabled, we might still need to manually load - # the user profile here - profile <- Sys.getenv("R_PROFILE_USER", unset = "~/.Rprofile") - if (file.exists(profile)) { - cfg <- Sys.getenv("RENV_CONFIG_USER_PROFILE", unset = "TRUE") - if (tolower(cfg) %in% c("true", "t", "1")) - sys.source(profile, envir = globalenv()) - } - - return(FALSE) - - } - - # avoid recursion - if (identical(getOption("renv.autoloader.running"), TRUE)) { - warning("ignoring recursive attempt to run renv autoloader") - return(invisible(TRUE)) - } - - # signal that we're loading renv during R startup - options(renv.autoloader.running = TRUE) - on.exit(options(renv.autoloader.running = NULL), add = TRUE) - - # signal that we've consented to use renv - options(renv.consent = TRUE) - - # load the 'utils' package eagerly -- this ensures that renv shims, which - # mask 'utils' packages, will come first on the search path - library(utils, lib.loc = .Library) - - # unload renv if it's already been loaded - if ("renv" %in% loadedNamespaces()) - unloadNamespace("renv") - - # load bootstrap tools - ansify <- function(text) { - if (renv_ansify_enabled()) - renv_ansify_enhanced(text) - else - renv_ansify_default(text) - } - - renv_ansify_enabled <- function() { - - override <- Sys.getenv("RENV_ANSIFY_ENABLED", unset = NA) - if (!is.na(override)) - return(as.logical(override)) - - pane <- Sys.getenv("RSTUDIO_CHILD_PROCESS_PANE", unset = NA) - if (identical(pane, "build")) - return(FALSE) - - testthat <- Sys.getenv("TESTTHAT", unset = "false") - if (tolower(testthat) %in% "true") - return(FALSE) - - iderun <- Sys.getenv("R_CLI_HAS_HYPERLINK_IDE_RUN", unset = "false") - if (tolower(iderun) %in% "false") - return(FALSE) - - TRUE - - } - - renv_ansify_default <- function(text) { - text - } - - renv_ansify_enhanced <- function(text) { - - # R help links - pattern <- "`\\?(renv::(?:[^`])+)`" - replacement <- "`\033]8;;x-r-help:\\1\a?\\1\033]8;;\a`" - text <- gsub(pattern, replacement, text, perl = TRUE) - - # runnable code - pattern <- "`(renv::(?:[^`])+)`" - replacement <- "`\033]8;;x-r-run:\\1\a\\1\033]8;;\a`" - text <- gsub(pattern, replacement, text, perl = TRUE) - - # return ansified text - text - - } - - renv_ansify_init <- function() { - - envir <- renv_envir_self() - if (renv_ansify_enabled()) - assign("ansify", renv_ansify_enhanced, envir = envir) - else - assign("ansify", renv_ansify_default, envir = envir) - - } - - `%||%` <- function(x, y) { - if (is.null(x)) y else x - } - - catf <- function(fmt, ..., appendLF = TRUE) { - - quiet <- getOption("renv.bootstrap.quiet", default = FALSE) - if (quiet) - return(invisible()) - - msg <- sprintf(fmt, ...) - cat(msg, file = stdout(), sep = if (appendLF) "\n" else "") - - invisible(msg) - - } - - header <- function(label, - ..., - prefix = "#", - suffix = "-", - n = min(getOption("width"), 78)) - { - label <- sprintf(label, ...) - n <- max(n - nchar(label) - nchar(prefix) - 2L, 8L) - if (n <= 0) - return(paste(prefix, label)) - - tail <- paste(rep.int(suffix, n), collapse = "") - paste0(prefix, " ", label, " ", tail) - - } - - heredoc <- function(text, leave = 0) { - - # remove leading, trailing whitespace - trimmed <- gsub("^\\s*\\n|\\n\\s*$", "", text) - - # split into lines - lines <- strsplit(trimmed, "\n", fixed = TRUE)[[1L]] - - # compute common indent - indent <- regexpr("[^[:space:]]", lines) - common <- min(setdiff(indent, -1L)) - leave - text <- paste(substring(lines, common), collapse = "\n") - - # substitute in ANSI links for executable renv code - ansify(text) - - } - - bootstrap <- function(version, library) { - - friendly <- renv_bootstrap_version_friendly(version) - section <- header(sprintf("Bootstrapping renv %s", friendly)) - catf(section) - - # attempt to download renv - catf("- Downloading renv ... ", appendLF = FALSE) - withCallingHandlers( - tarball <- renv_bootstrap_download(version), - error = function(err) { - catf("FAILED") - stop("failed to download:\n", conditionMessage(err)) - } - ) - catf("OK") - on.exit(unlink(tarball), add = TRUE) - - # now attempt to install - catf("- Installing renv ... ", appendLF = FALSE) - withCallingHandlers( - status <- renv_bootstrap_install(version, tarball, library), - error = function(err) { - catf("FAILED") - stop("failed to install:\n", conditionMessage(err)) - } - ) - catf("OK") - - # add empty line to break up bootstrapping from normal output - catf("") - - return(invisible()) - } - - renv_bootstrap_tests_running <- function() { - getOption("renv.tests.running", default = FALSE) - } - - renv_bootstrap_repos <- function() { - - # get CRAN repository - cran <- getOption("renv.repos.cran", "https://cloud.r-project.org") - - # check for repos override - repos <- Sys.getenv("RENV_CONFIG_REPOS_OVERRIDE", unset = NA) - if (!is.na(repos)) { - - # check for RSPM; if set, use a fallback repository for renv - rspm <- Sys.getenv("RSPM", unset = NA) - if (identical(rspm, repos)) - repos <- c(RSPM = rspm, CRAN = cran) - - return(repos) - - } - - # check for lockfile repositories - repos <- tryCatch(renv_bootstrap_repos_lockfile(), error = identity) - if (!inherits(repos, "error") && length(repos)) - return(repos) - - # retrieve current repos - repos <- getOption("repos") - - # ensure @CRAN@ entries are resolved - repos[repos == "@CRAN@"] <- cran - - # add in renv.bootstrap.repos if set - default <- c(FALLBACK = "https://cloud.r-project.org") - extra <- getOption("renv.bootstrap.repos", default = default) - repos <- c(repos, extra) - - # remove duplicates that might've snuck in - dupes <- duplicated(repos) | duplicated(names(repos)) - repos[!dupes] - - } - - renv_bootstrap_repos_lockfile <- function() { - - lockpath <- Sys.getenv("RENV_PATHS_LOCKFILE", unset = "renv.lock") - if (!file.exists(lockpath)) - return(NULL) - - lockfile <- tryCatch(renv_json_read(lockpath), error = identity) - if (inherits(lockfile, "error")) { - warning(lockfile) - return(NULL) - } - - repos <- lockfile$R$Repositories - if (length(repos) == 0) - return(NULL) - - keys <- vapply(repos, `[[`, "Name", FUN.VALUE = character(1)) - vals <- vapply(repos, `[[`, "URL", FUN.VALUE = character(1)) - names(vals) <- keys - - return(vals) - - } - - renv_bootstrap_download <- function(version) { - - sha <- attr(version, "sha", exact = TRUE) - - methods <- if (!is.null(sha)) { - - # attempting to bootstrap a development version of renv - c( - function() renv_bootstrap_download_tarball(sha), - function() renv_bootstrap_download_github(sha) - ) - - } else { - - # attempting to bootstrap a release version of renv - c( - function() renv_bootstrap_download_tarball(version), - function() renv_bootstrap_download_cran_latest(version), - function() renv_bootstrap_download_cran_archive(version) - ) - - } - - for (method in methods) { - path <- tryCatch(method(), error = identity) - if (is.character(path) && file.exists(path)) - return(path) - } - - stop("All download methods failed") - - } - - renv_bootstrap_download_impl <- function(url, destfile) { - - mode <- "wb" - - # https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17715 - fixup <- - Sys.info()[["sysname"]] == "Windows" && - substring(url, 1L, 5L) == "file:" - - if (fixup) - mode <- "w+b" - - args <- list( - url = url, - destfile = destfile, - mode = mode, - quiet = TRUE - ) - - if ("headers" %in% names(formals(utils::download.file))) { - headers <- renv_bootstrap_download_custom_headers(url) - if (length(headers) && is.character(headers)) - args$headers <- headers - } - - do.call(utils::download.file, args) - - } - - renv_bootstrap_download_custom_headers <- function(url) { - - headers <- getOption("renv.download.headers") - if (is.null(headers)) - return(character()) - - if (!is.function(headers)) - stopf("'renv.download.headers' is not a function") - - headers <- headers(url) - if (length(headers) == 0L) - return(character()) - - if (is.list(headers)) - headers <- unlist(headers, recursive = FALSE, use.names = TRUE) - - ok <- - is.character(headers) && - is.character(names(headers)) && - all(nzchar(names(headers))) - - if (!ok) - stop("invocation of 'renv.download.headers' did not return a named character vector") - - headers - - } - - renv_bootstrap_download_cran_latest <- function(version) { - - spec <- renv_bootstrap_download_cran_latest_find(version) - type <- spec$type - repos <- spec$repos - - baseurl <- utils::contrib.url(repos = repos, type = type) - ext <- if (identical(type, "source")) - ".tar.gz" - else if (Sys.info()[["sysname"]] == "Windows") - ".zip" - else - ".tgz" - name <- sprintf("renv_%s%s", version, ext) - url <- paste(baseurl, name, sep = "/") - - destfile <- file.path(tempdir(), name) - status <- tryCatch( - renv_bootstrap_download_impl(url, destfile), - condition = identity - ) - - if (inherits(status, "condition")) - return(FALSE) - - # report success and return - destfile - - } - - renv_bootstrap_download_cran_latest_find <- function(version) { - - # check whether binaries are supported on this system - binary <- - getOption("renv.bootstrap.binary", default = TRUE) && - !identical(.Platform$pkgType, "source") && - !identical(getOption("pkgType"), "source") && - Sys.info()[["sysname"]] %in% c("Darwin", "Windows") - - types <- c(if (binary) "binary", "source") - - # iterate over types + repositories - for (type in types) { - for (repos in renv_bootstrap_repos()) { - - # build arguments for utils::available.packages() call - args <- list(type = type, repos = repos) - - # add custom headers if available -- note that - # utils::available.packages() will pass this to download.file() - if ("headers" %in% names(formals(utils::download.file))) { - headers <- renv_bootstrap_download_custom_headers(repos) - if (length(headers) && is.character(headers)) - args$headers <- headers - } - - # retrieve package database - db <- tryCatch( - as.data.frame( - do.call(utils::available.packages, args), - stringsAsFactors = FALSE - ), - error = identity - ) - - if (inherits(db, "error")) - next - - # check for compatible entry - entry <- db[db$Package %in% "renv" & db$Version %in% version, ] - if (nrow(entry) == 0) - next - - # found it; return spec to caller - spec <- list(entry = entry, type = type, repos = repos) - return(spec) - - } - } - - # if we got here, we failed to find renv - fmt <- "renv %s is not available from your declared package repositories" - stop(sprintf(fmt, version)) - - } - - renv_bootstrap_download_cran_archive <- function(version) { - - name <- sprintf("renv_%s.tar.gz", version) - repos <- renv_bootstrap_repos() - urls <- file.path(repos, "src/contrib/Archive/renv", name) - destfile <- file.path(tempdir(), name) - - for (url in urls) { - - status <- tryCatch( - renv_bootstrap_download_impl(url, destfile), - condition = identity - ) - - if (identical(status, 0L)) - return(destfile) - - } - - return(FALSE) - - } - - renv_bootstrap_download_tarball <- function(version) { - - # if the user has provided the path to a tarball via - # an environment variable, then use it - tarball <- Sys.getenv("RENV_BOOTSTRAP_TARBALL", unset = NA) - if (is.na(tarball)) - return() - - # allow directories - if (dir.exists(tarball)) { - name <- sprintf("renv_%s.tar.gz", version) - tarball <- file.path(tarball, name) - } - - # bail if it doesn't exist - if (!file.exists(tarball)) { - - # let the user know we weren't able to honour their request - fmt <- "- RENV_BOOTSTRAP_TARBALL is set (%s) but does not exist." - msg <- sprintf(fmt, tarball) - warning(msg) - - # bail - return() - - } - - catf("- Using local tarball '%s'.", tarball) - tarball - - } - - renv_bootstrap_github_token <- function() { - for (envvar in c("GITHUB_TOKEN", "GITHUB_PAT", "GH_TOKEN")) { - envval <- Sys.getenv(envvar, unset = NA) - if (!is.na(envval)) - return(envval) - } - } - - renv_bootstrap_download_github <- function(version) { - - enabled <- Sys.getenv("RENV_BOOTSTRAP_FROM_GITHUB", unset = "TRUE") - if (!identical(enabled, "TRUE")) - return(FALSE) - - # prepare download options - token <- renv_bootstrap_github_token() - if (is.null(token)) - token <- "" - - if (nzchar(Sys.which("curl")) && nzchar(token)) { - fmt <- "--location --fail --header \"Authorization: token %s\"" - extra <- sprintf(fmt, token) - saved <- options("download.file.method", "download.file.extra") - options(download.file.method = "curl", download.file.extra = extra) - on.exit(do.call(base::options, saved), add = TRUE) - } else if (nzchar(Sys.which("wget")) && nzchar(token)) { - fmt <- "--header=\"Authorization: token %s\"" - extra <- sprintf(fmt, token) - saved <- options("download.file.method", "download.file.extra") - options(download.file.method = "wget", download.file.extra = extra) - on.exit(do.call(base::options, saved), add = TRUE) - } - - url <- file.path("https://api.github.com/repos/rstudio/renv/tarball", version) - name <- sprintf("renv_%s.tar.gz", version) - destfile <- file.path(tempdir(), name) - - status <- tryCatch( - renv_bootstrap_download_impl(url, destfile), - condition = identity - ) - - if (!identical(status, 0L)) - return(FALSE) - - renv_bootstrap_download_augment(destfile) - - return(destfile) - - } - - # Add Sha to DESCRIPTION. This is stop gap until #890, after which we - # can use renv::install() to fully capture metadata. - renv_bootstrap_download_augment <- function(destfile) { - sha <- renv_bootstrap_git_extract_sha1_tar(destfile) - if (is.null(sha)) { - return() - } - - # Untar - tempdir <- tempfile("renv-github-") - on.exit(unlink(tempdir, recursive = TRUE), add = TRUE) - untar(destfile, exdir = tempdir) - pkgdir <- dir(tempdir, full.names = TRUE)[[1]] - - # Modify description - desc_path <- file.path(pkgdir, "DESCRIPTION") - desc_lines <- readLines(desc_path) - remotes_fields <- c( - "RemoteType: github", - "RemoteHost: api.github.com", - "RemoteRepo: renv", - "RemoteUsername: rstudio", - "RemotePkgRef: rstudio/renv", - paste("RemoteRef: ", sha), - paste("RemoteSha: ", sha) - ) - writeLines(c(desc_lines[desc_lines != ""], remotes_fields), con = desc_path) - - # Re-tar - local({ - old <- setwd(tempdir) - on.exit(setwd(old), add = TRUE) - - tar(destfile, compression = "gzip") - }) - invisible() - } - - # Extract the commit hash from a git archive. Git archives include the SHA1 - # hash as the comment field of the tarball pax extended header - # (see https://www.kernel.org/pub/software/scm/git/docs/git-archive.html) - # For GitHub archives this should be the first header after the default one - # (512 byte) header. - renv_bootstrap_git_extract_sha1_tar <- function(bundle) { - - # open the bundle for reading - # We use gzcon for everything because (from ?gzcon) - # > Reading from a connection which does not supply a 'gzip' magic - # > header is equivalent to reading from the original connection - conn <- gzcon(file(bundle, open = "rb", raw = TRUE)) - on.exit(close(conn)) - - # The default pax header is 512 bytes long and the first pax extended header - # with the comment should be 51 bytes long - # `52 comment=` (11 chars) + 40 byte SHA1 hash - len <- 0x200 + 0x33 - res <- rawToChar(readBin(conn, "raw", n = len)[0x201:len]) - - if (grepl("^52 comment=", res)) { - sub("52 comment=", "", res) - } else { - NULL - } - } - - renv_bootstrap_install <- function(version, tarball, library) { - - # attempt to install it into project library - dir.create(library, showWarnings = FALSE, recursive = TRUE) - output <- renv_bootstrap_install_impl(library, tarball) - - # check for successful install - status <- attr(output, "status") - if (is.null(status) || identical(status, 0L)) - return(status) - - # an error occurred; report it - header <- "installation of renv failed" - lines <- paste(rep.int("=", nchar(header)), collapse = "") - text <- paste(c(header, lines, output), collapse = "\n") - stop(text) - - } - - renv_bootstrap_install_impl <- function(library, tarball) { - - # invoke using system2 so we can capture and report output - bin <- R.home("bin") - exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R" - R <- file.path(bin, exe) - - args <- c( - "--vanilla", "CMD", "INSTALL", "--no-multiarch", - "-l", shQuote(path.expand(library)), - shQuote(path.expand(tarball)) - ) - - system2(R, args, stdout = TRUE, stderr = TRUE) - - } - - renv_bootstrap_platform_prefix <- function() { - - # construct version prefix - version <- paste(R.version$major, R.version$minor, sep = ".") - prefix <- paste("R", numeric_version(version)[1, 1:2], sep = "-") - - # include SVN revision for development versions of R - # (to avoid sharing platform-specific artefacts with released versions of R) - devel <- - identical(R.version[["status"]], "Under development (unstable)") || - identical(R.version[["nickname"]], "Unsuffered Consequences") - - if (devel) - prefix <- paste(prefix, R.version[["svn rev"]], sep = "-r") - - # build list of path components - components <- c(prefix, R.version$platform) - - # include prefix if provided by user - prefix <- renv_bootstrap_platform_prefix_impl() - if (!is.na(prefix) && nzchar(prefix)) - components <- c(prefix, components) - - # build prefix - paste(components, collapse = "/") - - } - - renv_bootstrap_platform_prefix_impl <- function() { - - # if an explicit prefix has been supplied, use it - prefix <- Sys.getenv("RENV_PATHS_PREFIX", unset = NA) - if (!is.na(prefix)) - return(prefix) - - # if the user has requested an automatic prefix, generate it - auto <- Sys.getenv("RENV_PATHS_PREFIX_AUTO", unset = NA) - if (is.na(auto) && getRversion() >= "4.4.0") - auto <- "TRUE" - - if (auto %in% c("TRUE", "True", "true", "1")) - return(renv_bootstrap_platform_prefix_auto()) - - # empty string on failure - "" - - } - - renv_bootstrap_platform_prefix_auto <- function() { - - prefix <- tryCatch(renv_bootstrap_platform_os(), error = identity) - if (inherits(prefix, "error") || prefix %in% "unknown") { - - msg <- paste( - "failed to infer current operating system", - "please file a bug report at https://github.com/rstudio/renv/issues", - sep = "; " - ) - - warning(msg) - - } - - prefix - - } - - renv_bootstrap_platform_os <- function() { - - sysinfo <- Sys.info() - sysname <- sysinfo[["sysname"]] - - # handle Windows + macOS up front - if (sysname == "Windows") - return("windows") - else if (sysname == "Darwin") - return("macos") - - # check for os-release files - for (file in c("/etc/os-release", "/usr/lib/os-release")) - if (file.exists(file)) - return(renv_bootstrap_platform_os_via_os_release(file, sysinfo)) - - # check for redhat-release files - if (file.exists("/etc/redhat-release")) - return(renv_bootstrap_platform_os_via_redhat_release()) - - "unknown" - - } - - renv_bootstrap_platform_os_via_os_release <- function(file, sysinfo) { - - # read /etc/os-release - release <- utils::read.table( - file = file, - sep = "=", - quote = c("\"", "'"), - col.names = c("Key", "Value"), - comment.char = "#", - stringsAsFactors = FALSE - ) - - vars <- as.list(release$Value) - names(vars) <- release$Key - - # get os name - os <- tolower(sysinfo[["sysname"]]) - - # read id - id <- "unknown" - for (field in c("ID", "ID_LIKE")) { - if (field %in% names(vars) && nzchar(vars[[field]])) { - id <- vars[[field]] - break - } - } - - # read version - version <- "unknown" - for (field in c("UBUNTU_CODENAME", "VERSION_CODENAME", "VERSION_ID", "BUILD_ID")) { - if (field %in% names(vars) && nzchar(vars[[field]])) { - version <- vars[[field]] - break - } - } - - # join together - paste(c(os, id, version), collapse = "-") - - } - - renv_bootstrap_platform_os_via_redhat_release <- function() { - - # read /etc/redhat-release - contents <- readLines("/etc/redhat-release", warn = FALSE) - - # infer id - id <- if (grepl("centos", contents, ignore.case = TRUE)) - "centos" - else if (grepl("redhat", contents, ignore.case = TRUE)) - "redhat" - else - "unknown" - - # try to find a version component (very hacky) - version <- "unknown" - - parts <- strsplit(contents, "[[:space:]]")[[1L]] - for (part in parts) { - - nv <- tryCatch(numeric_version(part), error = identity) - if (inherits(nv, "error")) - next - - version <- nv[1, 1] - break - - } - - paste(c("linux", id, version), collapse = "-") - - } - - renv_bootstrap_library_root_name <- function(project) { - - # use project name as-is if requested - asis <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT_ASIS", unset = "FALSE") - if (asis) - return(basename(project)) - - # otherwise, disambiguate based on project's path - id <- substring(renv_bootstrap_hash_text(project), 1L, 8L) - paste(basename(project), id, sep = "-") - - } - - renv_bootstrap_library_root <- function(project) { - - prefix <- renv_bootstrap_profile_prefix() - - path <- Sys.getenv("RENV_PATHS_LIBRARY", unset = NA) - if (!is.na(path)) - return(paste(c(path, prefix), collapse = "/")) - - path <- renv_bootstrap_library_root_impl(project) - if (!is.null(path)) { - name <- renv_bootstrap_library_root_name(project) - return(paste(c(path, prefix, name), collapse = "/")) - } - - renv_bootstrap_paths_renv("library", project = project) - - } - - renv_bootstrap_library_root_impl <- function(project) { - - root <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT", unset = NA) - if (!is.na(root)) - return(root) - - type <- renv_bootstrap_project_type(project) - if (identical(type, "package")) { - userdir <- renv_bootstrap_user_dir() - return(file.path(userdir, "library")) - } - - } - - renv_bootstrap_validate_version <- function(version, description = NULL) { - - # resolve description file - # - # avoid passing lib.loc to `packageDescription()` below, since R will - # use the loaded version of the package by default anyhow. note that - # this function should only be called after 'renv' is loaded - # https://github.com/rstudio/renv/issues/1625 - description <- description %||% packageDescription("renv") - - # check whether requested version 'version' matches loaded version of renv - sha <- attr(version, "sha", exact = TRUE) - valid <- if (!is.null(sha)) - renv_bootstrap_validate_version_dev(sha, description) - else - renv_bootstrap_validate_version_release(version, description) - - if (valid) - return(TRUE) - - # the loaded version of renv doesn't match the requested version; - # give the user instructions on how to proceed - dev <- identical(description[["RemoteType"]], "github") - remote <- if (dev) - paste("rstudio/renv", description[["RemoteSha"]], sep = "@") - else - paste("renv", description[["Version"]], sep = "@") - - # display both loaded version + sha if available - friendly <- renv_bootstrap_version_friendly( - version = description[["Version"]], - sha = if (dev) description[["RemoteSha"]] - ) - - fmt <- heredoc(" - renv %1$s was loaded from project library, but this project is configured to use renv %2$s. - - Use `renv::record(\"%3$s\")` to record renv %1$s in the lockfile. - - Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library. - ") - catf(fmt, friendly, renv_bootstrap_version_friendly(version), remote) - - FALSE - - } - - renv_bootstrap_validate_version_dev <- function(version, description) { - - expected <- description[["RemoteSha"]] - if (!is.character(expected)) - return(FALSE) - - pattern <- sprintf("^\\Q%s\\E", version) - grepl(pattern, expected, perl = TRUE) - - } - - renv_bootstrap_validate_version_release <- function(version, description) { - expected <- description[["Version"]] - is.character(expected) && identical(expected, version) - } - - renv_bootstrap_hash_text <- function(text) { - - hashfile <- tempfile("renv-hash-") - on.exit(unlink(hashfile), add = TRUE) - - writeLines(text, con = hashfile) - tools::md5sum(hashfile) - - } - - renv_bootstrap_load <- function(project, libpath, version) { - - # try to load renv from the project library - if (!requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) - return(FALSE) - - # warn if the version of renv loaded does not match - renv_bootstrap_validate_version(version) - - # execute renv load hooks, if any - hooks <- getHook("renv::autoload") - for (hook in hooks) - if (is.function(hook)) - tryCatch(hook(), error = warnify) - - # load the project - renv::load(project) - - TRUE - - } - - renv_bootstrap_profile_load <- function(project) { - - # if RENV_PROFILE is already set, just use that - profile <- Sys.getenv("RENV_PROFILE", unset = NA) - if (!is.na(profile) && nzchar(profile)) - return(profile) - - # check for a profile file (nothing to do if it doesn't exist) - path <- renv_bootstrap_paths_renv("profile", profile = FALSE, project = project) - if (!file.exists(path)) - return(NULL) - - # read the profile, and set it if it exists - contents <- readLines(path, warn = FALSE) - if (length(contents) == 0L) - return(NULL) - - # set RENV_PROFILE - profile <- contents[[1L]] - if (!profile %in% c("", "default")) - Sys.setenv(RENV_PROFILE = profile) - - profile - - } - - renv_bootstrap_profile_prefix <- function() { - profile <- renv_bootstrap_profile_get() - if (!is.null(profile)) - return(file.path("profiles", profile, "renv")) - } - - renv_bootstrap_profile_get <- function() { - profile <- Sys.getenv("RENV_PROFILE", unset = "") - renv_bootstrap_profile_normalize(profile) - } - - renv_bootstrap_profile_set <- function(profile) { - profile <- renv_bootstrap_profile_normalize(profile) - if (is.null(profile)) - Sys.unsetenv("RENV_PROFILE") - else - Sys.setenv(RENV_PROFILE = profile) - } - - renv_bootstrap_profile_normalize <- function(profile) { - - if (is.null(profile) || profile %in% c("", "default")) - return(NULL) - - profile - - } - - renv_bootstrap_path_absolute <- function(path) { - - substr(path, 1L, 1L) %in% c("~", "/", "\\") || ( - substr(path, 1L, 1L) %in% c(letters, LETTERS) && - substr(path, 2L, 3L) %in% c(":/", ":\\") - ) - - } - - renv_bootstrap_paths_renv <- function(..., profile = TRUE, project = NULL) { - renv <- Sys.getenv("RENV_PATHS_RENV", unset = "renv") - root <- if (renv_bootstrap_path_absolute(renv)) NULL else project - prefix <- if (profile) renv_bootstrap_profile_prefix() - components <- c(root, renv, prefix, ...) - paste(components, collapse = "/") - } - - renv_bootstrap_project_type <- function(path) { - - descpath <- file.path(path, "DESCRIPTION") - if (!file.exists(descpath)) - return("unknown") - - desc <- tryCatch( - read.dcf(descpath, all = TRUE), - error = identity - ) - - if (inherits(desc, "error")) - return("unknown") - - type <- desc$Type - if (!is.null(type)) - return(tolower(type)) - - package <- desc$Package - if (!is.null(package)) - return("package") - - "unknown" - - } - - renv_bootstrap_user_dir <- function() { - dir <- renv_bootstrap_user_dir_impl() - path.expand(chartr("\\", "/", dir)) - } - - renv_bootstrap_user_dir_impl <- function() { - - # use local override if set - override <- getOption("renv.userdir.override") - if (!is.null(override)) - return(override) - - # use R_user_dir if available - tools <- asNamespace("tools") - if (is.function(tools$R_user_dir)) - return(tools$R_user_dir("renv", "cache")) - - # try using our own backfill for older versions of R - envvars <- c("R_USER_CACHE_DIR", "XDG_CACHE_HOME") - for (envvar in envvars) { - root <- Sys.getenv(envvar, unset = NA) - if (!is.na(root)) - return(file.path(root, "R/renv")) - } - - # use platform-specific default fallbacks - if (Sys.info()[["sysname"]] == "Windows") - file.path(Sys.getenv("LOCALAPPDATA"), "R/cache/R/renv") - else if (Sys.info()[["sysname"]] == "Darwin") - "~/Library/Caches/org.R-project.R/R/renv" - else - "~/.cache/R/renv" - - } - - renv_bootstrap_version_friendly <- function(version, shafmt = NULL, sha = NULL) { - sha <- sha %||% attr(version, "sha", exact = TRUE) - parts <- c(version, sprintf(shafmt %||% " [sha: %s]", substring(sha, 1L, 7L))) - paste(parts, collapse = "") - } - - renv_bootstrap_exec <- function(project, libpath, version) { - if (!renv_bootstrap_load(project, libpath, version)) - renv_bootstrap_run(project, libpath, version) - } - - renv_bootstrap_run <- function(project, libpath, version) { - - # perform bootstrap - bootstrap(version, libpath) - - # exit early if we're just testing bootstrap - if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA))) - return(TRUE) - - # try again to load - if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) { - return(renv::load(project = project)) - } - - # failed to download or load renv; warn the user - msg <- c( - "Failed to find an renv installation: the project will not be loaded.", - "Use `renv::activate()` to re-initialize the project." - ) - - warning(paste(msg, collapse = "\n"), call. = FALSE) - - } - - renv_json_read <- function(file = NULL, text = NULL) { - - jlerr <- NULL - - # if jsonlite is loaded, use that instead - if ("jsonlite" %in% loadedNamespaces()) { - - json <- tryCatch(renv_json_read_jsonlite(file, text), error = identity) - if (!inherits(json, "error")) - return(json) - - jlerr <- json - - } - - # otherwise, fall back to the default JSON reader - json <- tryCatch(renv_json_read_default(file, text), error = identity) - if (!inherits(json, "error")) - return(json) - - # report an error - if (!is.null(jlerr)) - stop(jlerr) - else - stop(json) - - } - - renv_json_read_jsonlite <- function(file = NULL, text = NULL) { - text <- paste(text %||% readLines(file, warn = FALSE), collapse = "\n") - jsonlite::fromJSON(txt = text, simplifyVector = FALSE) - } - - renv_json_read_patterns <- function() { - - list( - - # objects - list("{", "\t\n\tobject(\t\n\t"), - list("}", "\t\n\t)\t\n\t"), - - # arrays - list("[", "\t\n\tarray(\t\n\t"), - list("]", "\n\t\n)\n\t\n"), - - # maps - list(":", "\t\n\t=\t\n\t") - - ) - - } - - renv_json_read_envir <- function() { - - envir <- new.env(parent = emptyenv()) - - envir[["+"]] <- `+` - envir[["-"]] <- `-` - - envir[["object"]] <- function(...) { - result <- list(...) - names(result) <- as.character(names(result)) - result - } - - envir[["array"]] <- list - - envir[["true"]] <- TRUE - envir[["false"]] <- FALSE - envir[["null"]] <- NULL - - envir - - } - - renv_json_read_remap <- function(object, patterns) { - - # repair names if necessary - if (!is.null(names(object))) { - - nms <- names(object) - for (pattern in patterns) - nms <- gsub(pattern[[2L]], pattern[[1L]], nms, fixed = TRUE) - names(object) <- nms - - } - - # repair strings if necessary - if (is.character(object)) { - for (pattern in patterns) - object <- gsub(pattern[[2L]], pattern[[1L]], object, fixed = TRUE) - } - - # recurse for other objects - if (is.recursive(object)) - for (i in seq_along(object)) - object[i] <- list(renv_json_read_remap(object[[i]], patterns)) - - # return remapped object - object - - } - - renv_json_read_default <- function(file = NULL, text = NULL) { - - # read json text - text <- paste(text %||% readLines(file, warn = FALSE), collapse = "\n") - - # convert into something the R parser will understand - patterns <- renv_json_read_patterns() - transformed <- text - for (pattern in patterns) - transformed <- gsub(pattern[[1L]], pattern[[2L]], transformed, fixed = TRUE) - - # parse it - rfile <- tempfile("renv-json-", fileext = ".R") - on.exit(unlink(rfile), add = TRUE) - writeLines(transformed, con = rfile) - json <- parse(rfile, keep.source = FALSE, srcfile = NULL)[[1L]] - - # evaluate in safe environment - result <- eval(json, envir = renv_json_read_envir()) - - # fix up strings if necessary - renv_json_read_remap(result, patterns) - - } - - - # load the renv profile, if any - renv_bootstrap_profile_load(project) - - # construct path to library root - root <- renv_bootstrap_library_root(project) - - # construct library prefix for platform - prefix <- renv_bootstrap_platform_prefix() - - # construct full libpath - libpath <- file.path(root, prefix) - - # run bootstrap code - renv_bootstrap_exec(project, libpath, version) - - invisible() - -}) diff --git a/renv/profile b/renv/profile deleted file mode 100644 index 6d4023b..0000000 --- a/renv/profile +++ /dev/null @@ -1 +0,0 @@ -lesson-requirements diff --git a/renv/profiles/lesson-requirements/renv.lock b/renv/profiles/lesson-requirements/renv.lock deleted file mode 100644 index fbd452e..0000000 --- a/renv/profiles/lesson-requirements/renv.lock +++ /dev/null @@ -1,996 +0,0 @@ -{ - "R": { - "Version": "4.4.3", - "Repositories": [ - { - "Name": "carpentries", - "URL": "https://carpentries.r-universe.dev" - }, - { - "Name": "carpentries_archive", - "URL": "https://carpentries.github.io/drat" - }, - { - "Name": "CRAN", - "URL": "https://cran.rstudio.com" - } - ] - }, - "Packages": { - "R6": { - "Package": "R6", - "Version": "2.6.1", - "Source": "Repository", - "Title": "Encapsulated Classes with Reference Semantics", - "Authors@R": "c( person(\"Winston\", \"Chang\", , \"winston@posit.co\", role = c(\"aut\", \"cre\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )", - "Description": "Creates classes with reference semantics, similar to R's built-in reference classes. Compared to reference classes, R6 classes are simpler and lighter-weight, and they are not built on S4 classes so they do not require the methods package. These classes allow public and private members, and they support inheritance, even when the classes are defined in different packages.", - "License": "MIT + file LICENSE", - "URL": "https://r6.r-lib.org, https://github.com/r-lib/R6", - "BugReports": "https://github.com/r-lib/R6/issues", - "Depends": [ - "R (>= 3.6)" - ], - "Suggests": [ - "lobstr", - "testthat (>= 3.0.0)" - ], - "Config/Needs/website": "tidyverse/tidytemplate, ggplot2, microbenchmark, scales", - "Config/testthat/edition": "3", - "Encoding": "UTF-8", - "RoxygenNote": "7.3.2", - "NeedsCompilation": "no", - "Author": "Winston Chang [aut, cre], Posit Software, PBC [cph, fnd]", - "Maintainer": "Winston Chang ", - "Repository": "CRAN" - }, - "base64enc": { - "Package": "base64enc", - "Version": "0.1-3", - "Source": "Repository", - "Title": "Tools for base64 encoding", - "Author": "Simon Urbanek ", - "Maintainer": "Simon Urbanek ", - "Depends": [ - "R (>= 2.9.0)" - ], - "Enhances": [ - "png" - ], - "Description": "This package provides tools for handling base64 encoding. It is more flexible than the orphaned base64 package.", - "License": "GPL-2 | GPL-3", - "URL": "http://www.rforge.net/base64enc", - "NeedsCompilation": "yes", - "Repository": "CRAN" - }, - "bslib": { - "Package": "bslib", - "Version": "0.9.0", - "Source": "Repository", - "Title": "Custom 'Bootstrap' 'Sass' Themes for 'shiny' and 'rmarkdown'", - "Authors@R": "c( person(\"Carson\", \"Sievert\", , \"carson@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-4958-2844\")), person(\"Joe\", \"Cheng\", , \"joe@posit.co\", role = \"aut\"), person(\"Garrick\", \"Aden-Buie\", , \"garrick@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0002-7111-0077\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")), person(, \"Bootstrap contributors\", role = \"ctb\", comment = \"Bootstrap library\"), person(, \"Twitter, Inc\", role = \"cph\", comment = \"Bootstrap library\"), person(\"Javi\", \"Aguilar\", role = c(\"ctb\", \"cph\"), comment = \"Bootstrap colorpicker library\"), person(\"Thomas\", \"Park\", role = c(\"ctb\", \"cph\"), comment = \"Bootswatch library\"), person(, \"PayPal\", role = c(\"ctb\", \"cph\"), comment = \"Bootstrap accessibility plugin\") )", - "Description": "Simplifies custom 'CSS' styling of both 'shiny' and 'rmarkdown' via 'Bootstrap' 'Sass'. Supports 'Bootstrap' 3, 4 and 5 as well as their various 'Bootswatch' themes. An interactive widget is also provided for previewing themes in real time.", - "License": "MIT + file LICENSE", - "URL": "https://rstudio.github.io/bslib/, https://github.com/rstudio/bslib", - "BugReports": "https://github.com/rstudio/bslib/issues", - "Depends": [ - "R (>= 2.10)" - ], - "Imports": [ - "base64enc", - "cachem", - "fastmap (>= 1.1.1)", - "grDevices", - "htmltools (>= 0.5.8)", - "jquerylib (>= 0.1.3)", - "jsonlite", - "lifecycle", - "memoise (>= 2.0.1)", - "mime", - "rlang", - "sass (>= 0.4.9)" - ], - "Suggests": [ - "bsicons", - "curl", - "fontawesome", - "future", - "ggplot2", - "knitr", - "magrittr", - "rappdirs", - "rmarkdown (>= 2.7)", - "shiny (> 1.8.1)", - "testthat", - "thematic", - "tools", - "utils", - "withr", - "yaml" - ], - "Config/Needs/deploy": "BH, chiflights22, colourpicker, commonmark, cpp11, cpsievert/chiflights22, cpsievert/histoslider, dplyr, DT, ggplot2, ggridges, gt, hexbin, histoslider, htmlwidgets, lattice, leaflet, lubridate, markdown, modelr, plotly, reactable, reshape2, rprojroot, rsconnect, rstudio/shiny, scales, styler, tibble", - "Config/Needs/routine": "chromote, desc, renv", - "Config/Needs/website": "brio, crosstalk, dplyr, DT, ggplot2, glue, htmlwidgets, leaflet, lorem, palmerpenguins, plotly, purrr, rprojroot, rstudio/htmltools, scales, stringr, tidyr, webshot2", - "Config/testthat/edition": "3", - "Config/testthat/parallel": "true", - "Config/testthat/start-first": "zzzz-bs-sass, fonts, zzz-precompile, theme-*, rmd-*", - "Encoding": "UTF-8", - "RoxygenNote": "7.3.2", - "Collate": "'accordion.R' 'breakpoints.R' 'bs-current-theme.R' 'bs-dependencies.R' 'bs-global.R' 'bs-remove.R' 'bs-theme-layers.R' 'bs-theme-preset-bootswatch.R' 'bs-theme-preset-brand.R' 'bs-theme-preset-builtin.R' 'bs-theme-preset.R' 'utils.R' 'bs-theme-preview.R' 'bs-theme-update.R' 'bs-theme.R' 'bslib-package.R' 'buttons.R' 'card.R' 'deprecated.R' 'files.R' 'fill.R' 'imports.R' 'input-dark-mode.R' 'input-switch.R' 'layout.R' 'nav-items.R' 'nav-update.R' 'navbar_options.R' 'navs-legacy.R' 'navs.R' 'onLoad.R' 'page.R' 'popover.R' 'precompiled.R' 'print.R' 'shiny-devmode.R' 'sidebar.R' 'staticimports.R' 'tooltip.R' 'utils-deps.R' 'utils-shiny.R' 'utils-tags.R' 'value-box.R' 'version-default.R' 'versions.R'", - "NeedsCompilation": "no", - "Author": "Carson Sievert [aut, cre] (), Joe Cheng [aut], Garrick Aden-Buie [aut] (), Posit Software, PBC [cph, fnd], Bootstrap contributors [ctb] (Bootstrap library), Twitter, Inc [cph] (Bootstrap library), Javi Aguilar [ctb, cph] (Bootstrap colorpicker library), Thomas Park [ctb, cph] (Bootswatch library), PayPal [ctb, cph] (Bootstrap accessibility plugin)", - "Maintainer": "Carson Sievert ", - "Repository": "CRAN" - }, - "cachem": { - "Package": "cachem", - "Version": "1.1.0", - "Source": "Repository", - "Title": "Cache R Objects with Automatic Pruning", - "Description": "Key-value stores with automatic pruning. Caches can limit either their total size or the age of the oldest object (or both), automatically pruning objects to maintain the constraints.", - "Authors@R": "c( person(\"Winston\", \"Chang\", , \"winston@posit.co\", c(\"aut\", \"cre\")), person(family = \"Posit Software, PBC\", role = c(\"cph\", \"fnd\")))", - "License": "MIT + file LICENSE", - "Encoding": "UTF-8", - "ByteCompile": "true", - "URL": "https://cachem.r-lib.org/, https://github.com/r-lib/cachem", - "Imports": [ - "rlang", - "fastmap (>= 1.2.0)" - ], - "Suggests": [ - "testthat" - ], - "RoxygenNote": "7.2.3", - "Config/Needs/routine": "lobstr", - "Config/Needs/website": "pkgdown", - "NeedsCompilation": "yes", - "Author": "Winston Chang [aut, cre], Posit Software, PBC [cph, fnd]", - "Maintainer": "Winston Chang ", - "Repository": "CRAN" - }, - "cli": { - "Package": "cli", - "Version": "3.6.4", - "Source": "Repository", - "Title": "Helpers for Developing Command Line Interfaces", - "Authors@R": "c( person(\"Gábor\", \"Csárdi\", , \"gabor@posit.co\", role = c(\"aut\", \"cre\")), person(\"Hadley\", \"Wickham\", role = \"ctb\"), person(\"Kirill\", \"Müller\", role = \"ctb\"), person(\"Salim\", \"Brüggemann\", , \"salim-b@pm.me\", role = \"ctb\", comment = c(ORCID = \"0000-0002-5329-5987\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )", - "Description": "A suite of tools to build attractive command line interfaces ('CLIs'), from semantic elements: headings, lists, alerts, paragraphs, etc. Supports custom themes via a 'CSS'-like language. It also contains a number of lower level 'CLI' elements: rules, boxes, trees, and 'Unicode' symbols with 'ASCII' alternatives. It support ANSI colors and text styles as well.", - "License": "MIT + file LICENSE", - "URL": "https://cli.r-lib.org, https://github.com/r-lib/cli", - "BugReports": "https://github.com/r-lib/cli/issues", - "Depends": [ - "R (>= 3.4)" - ], - "Imports": [ - "utils" - ], - "Suggests": [ - "callr", - "covr", - "crayon", - "digest", - "glue (>= 1.6.0)", - "grDevices", - "htmltools", - "htmlwidgets", - "knitr", - "methods", - "processx", - "ps (>= 1.3.4.9000)", - "rlang (>= 1.0.2.9003)", - "rmarkdown", - "rprojroot", - "rstudioapi", - "testthat (>= 3.2.0)", - "tibble", - "whoami", - "withr" - ], - "Config/Needs/website": "r-lib/asciicast, bench, brio, cpp11, decor, desc, fansi, prettyunits, sessioninfo, tidyverse/tidytemplate, usethis, vctrs", - "Config/testthat/edition": "3", - "Encoding": "UTF-8", - "RoxygenNote": "7.3.2", - "NeedsCompilation": "yes", - "Author": "Gábor Csárdi [aut, cre], Hadley Wickham [ctb], Kirill Müller [ctb], Salim Brüggemann [ctb] (), Posit Software, PBC [cph, fnd]", - "Maintainer": "Gábor Csárdi ", - "Repository": "CRAN" - }, - "digest": { - "Package": "digest", - "Version": "0.6.37", - "Source": "Repository", - "Authors@R": "c(person(\"Dirk\", \"Eddelbuettel\", role = c(\"aut\", \"cre\"), email = \"edd@debian.org\", comment = c(ORCID = \"0000-0001-6419-907X\")), person(\"Antoine\", \"Lucas\", role=\"ctb\"), person(\"Jarek\", \"Tuszynski\", role=\"ctb\"), person(\"Henrik\", \"Bengtsson\", role=\"ctb\", comment = c(ORCID = \"0000-0002-7579-5165\")), person(\"Simon\", \"Urbanek\", role=\"ctb\", comment = c(ORCID = \"0000-0003-2297-1732\")), person(\"Mario\", \"Frasca\", role=\"ctb\"), person(\"Bryan\", \"Lewis\", role=\"ctb\"), person(\"Murray\", \"Stokely\", role=\"ctb\"), person(\"Hannes\", \"Muehleisen\", role=\"ctb\"), person(\"Duncan\", \"Murdoch\", role=\"ctb\"), person(\"Jim\", \"Hester\", role=\"ctb\"), person(\"Wush\", \"Wu\", role=\"ctb\", comment = c(ORCID = \"0000-0001-5180-0567\")), person(\"Qiang\", \"Kou\", role=\"ctb\", comment = c(ORCID = \"0000-0001-6786-5453\")), person(\"Thierry\", \"Onkelinx\", role=\"ctb\", comment = c(ORCID = \"0000-0001-8804-4216\")), person(\"Michel\", \"Lang\", role=\"ctb\", comment = c(ORCID = \"0000-0001-9754-0393\")), person(\"Viliam\", \"Simko\", role=\"ctb\"), person(\"Kurt\", \"Hornik\", role=\"ctb\", comment = c(ORCID = \"0000-0003-4198-9911\")), person(\"Radford\", \"Neal\", role=\"ctb\", comment = c(ORCID = \"0000-0002-2473-3407\")), person(\"Kendon\", \"Bell\", role=\"ctb\", comment = c(ORCID = \"0000-0002-9093-8312\")), person(\"Matthew\", \"de Queljoe\", role=\"ctb\"), person(\"Dmitry\", \"Selivanov\", role=\"ctb\"), person(\"Ion\", \"Suruceanu\", role=\"ctb\"), person(\"Bill\", \"Denney\", role=\"ctb\"), person(\"Dirk\", \"Schumacher\", role=\"ctb\"), person(\"András\", \"Svraka\", role=\"ctb\"), person(\"Sergey\", \"Fedorov\", role=\"ctb\"), person(\"Will\", \"Landau\", role=\"ctb\", comment = c(ORCID = \"0000-0003-1878-3253\")), person(\"Floris\", \"Vanderhaeghe\", role=\"ctb\", comment = c(ORCID = \"0000-0002-6378-6229\")), person(\"Kevin\", \"Tappe\", role=\"ctb\"), person(\"Harris\", \"McGehee\", role=\"ctb\"), person(\"Tim\", \"Mastny\", role=\"ctb\"), person(\"Aaron\", \"Peikert\", role=\"ctb\", comment = c(ORCID = \"0000-0001-7813-818X\")), person(\"Mark\", \"van der Loo\", role=\"ctb\", comment = c(ORCID = \"0000-0002-9807-4686\")), person(\"Chris\", \"Muir\", role=\"ctb\", comment = c(ORCID = \"0000-0003-2555-3878\")), person(\"Moritz\", \"Beller\", role=\"ctb\", comment = c(ORCID = \"0000-0003-4852-0526\")), person(\"Sebastian\", \"Campbell\", role=\"ctb\"), person(\"Winston\", \"Chang\", role=\"ctb\", comment = c(ORCID = \"0000-0002-1576-2126\")), person(\"Dean\", \"Attali\", role=\"ctb\", comment = c(ORCID = \"0000-0002-5645-3493\")), person(\"Michael\", \"Chirico\", role=\"ctb\", comment = c(ORCID = \"0000-0003-0787-087X\")), person(\"Kevin\", \"Ushey\", role=\"ctb\"))", - "Date": "2024-08-19", - "Title": "Create Compact Hash Digests of R Objects", - "Description": "Implementation of a function 'digest()' for the creation of hash digests of arbitrary R objects (using the 'md5', 'sha-1', 'sha-256', 'crc32', 'xxhash', 'murmurhash', 'spookyhash', 'blake3', 'crc32c', 'xxh3_64', and 'xxh3_128' algorithms) permitting easy comparison of R language objects, as well as functions such as'hmac()' to create hash-based message authentication code. Please note that this package is not meant to be deployed for cryptographic purposes for which more comprehensive (and widely tested) libraries such as 'OpenSSL' should be used.", - "URL": "https://github.com/eddelbuettel/digest, https://dirk.eddelbuettel.com/code/digest.html", - "BugReports": "https://github.com/eddelbuettel/digest/issues", - "Depends": [ - "R (>= 3.3.0)" - ], - "Imports": [ - "utils" - ], - "License": "GPL (>= 2)", - "Suggests": [ - "tinytest", - "simplermarkdown" - ], - "VignetteBuilder": "simplermarkdown", - "Encoding": "UTF-8", - "NeedsCompilation": "yes", - "Author": "Dirk Eddelbuettel [aut, cre] (), Antoine Lucas [ctb], Jarek Tuszynski [ctb], Henrik Bengtsson [ctb] (), Simon Urbanek [ctb] (), Mario Frasca [ctb], Bryan Lewis [ctb], Murray Stokely [ctb], Hannes Muehleisen [ctb], Duncan Murdoch [ctb], Jim Hester [ctb], Wush Wu [ctb] (), Qiang Kou [ctb] (), Thierry Onkelinx [ctb] (), Michel Lang [ctb] (), Viliam Simko [ctb], Kurt Hornik [ctb] (), Radford Neal [ctb] (), Kendon Bell [ctb] (), Matthew de Queljoe [ctb], Dmitry Selivanov [ctb], Ion Suruceanu [ctb], Bill Denney [ctb], Dirk Schumacher [ctb], András Svraka [ctb], Sergey Fedorov [ctb], Will Landau [ctb] (), Floris Vanderhaeghe [ctb] (), Kevin Tappe [ctb], Harris McGehee [ctb], Tim Mastny [ctb], Aaron Peikert [ctb] (), Mark van der Loo [ctb] (), Chris Muir [ctb] (), Moritz Beller [ctb] (), Sebastian Campbell [ctb], Winston Chang [ctb] (), Dean Attali [ctb] (), Michael Chirico [ctb] (), Kevin Ushey [ctb]", - "Maintainer": "Dirk Eddelbuettel ", - "Repository": "CRAN" - }, - "evaluate": { - "Package": "evaluate", - "Version": "1.0.3", - "Source": "Repository", - "Type": "Package", - "Title": "Parsing and Evaluation Tools that Provide More Details than the Default", - "Authors@R": "c( person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = c(\"aut\", \"cre\")), person(\"Yihui\", \"Xie\", role = \"aut\", comment = c(ORCID = \"0000-0003-0645-5666\")), person(\"Michael\", \"Lawrence\", role = \"ctb\"), person(\"Thomas\", \"Kluyver\", role = \"ctb\"), person(\"Jeroen\", \"Ooms\", role = \"ctb\"), person(\"Barret\", \"Schloerke\", role = \"ctb\"), person(\"Adam\", \"Ryczkowski\", role = \"ctb\"), person(\"Hiroaki\", \"Yutani\", role = \"ctb\"), person(\"Michel\", \"Lang\", role = \"ctb\"), person(\"Karolis\", \"Koncevičius\", role = \"ctb\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )", - "Description": "Parsing and evaluation tools that make it easy to recreate the command line behaviour of R.", - "License": "MIT + file LICENSE", - "URL": "https://evaluate.r-lib.org/, https://github.com/r-lib/evaluate", - "BugReports": "https://github.com/r-lib/evaluate/issues", - "Depends": [ - "R (>= 3.6.0)" - ], - "Suggests": [ - "callr", - "covr", - "ggplot2 (>= 3.3.6)", - "lattice", - "methods", - "pkgload", - "rlang", - "knitr", - "testthat (>= 3.0.0)", - "withr" - ], - "Config/Needs/website": "tidyverse/tidytemplate", - "Config/testthat/edition": "3", - "Encoding": "UTF-8", - "RoxygenNote": "7.3.2", - "NeedsCompilation": "no", - "Author": "Hadley Wickham [aut, cre], Yihui Xie [aut] (), Michael Lawrence [ctb], Thomas Kluyver [ctb], Jeroen Ooms [ctb], Barret Schloerke [ctb], Adam Ryczkowski [ctb], Hiroaki Yutani [ctb], Michel Lang [ctb], Karolis Koncevičius [ctb], Posit Software, PBC [cph, fnd]", - "Maintainer": "Hadley Wickham ", - "Repository": "CRAN" - }, - "fastmap": { - "Package": "fastmap", - "Version": "1.2.0", - "Source": "Repository", - "Title": "Fast Data Structures", - "Authors@R": "c( person(\"Winston\", \"Chang\", email = \"winston@posit.co\", role = c(\"aut\", \"cre\")), person(given = \"Posit Software, PBC\", role = c(\"cph\", \"fnd\")), person(given = \"Tessil\", role = \"cph\", comment = \"hopscotch_map library\") )", - "Description": "Fast implementation of data structures, including a key-value store, stack, and queue. Environments are commonly used as key-value stores in R, but every time a new key is used, it is added to R's global symbol table, causing a small amount of memory leakage. This can be problematic in cases where many different keys are used. Fastmap avoids this memory leak issue by implementing the map using data structures in C++.", - "License": "MIT + file LICENSE", - "Encoding": "UTF-8", - "RoxygenNote": "7.2.3", - "Suggests": [ - "testthat (>= 2.1.1)" - ], - "URL": "https://r-lib.github.io/fastmap/, https://github.com/r-lib/fastmap", - "BugReports": "https://github.com/r-lib/fastmap/issues", - "NeedsCompilation": "yes", - "Author": "Winston Chang [aut, cre], Posit Software, PBC [cph, fnd], Tessil [cph] (hopscotch_map library)", - "Maintainer": "Winston Chang ", - "Repository": "CRAN" - }, - "fontawesome": { - "Package": "fontawesome", - "Version": "0.5.3", - "Source": "Repository", - "Type": "Package", - "Title": "Easily Work with 'Font Awesome' Icons", - "Description": "Easily and flexibly insert 'Font Awesome' icons into 'R Markdown' documents and 'Shiny' apps. These icons can be inserted into HTML content through inline 'SVG' tags or 'i' tags. There is also a utility function for exporting 'Font Awesome' icons as 'PNG' images for those situations where raster graphics are needed.", - "Authors@R": "c( person(\"Richard\", \"Iannone\", , \"rich@posit.co\", c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0003-3925-190X\")), person(\"Christophe\", \"Dervieux\", , \"cderv@posit.co\", role = \"ctb\", comment = c(ORCID = \"0000-0003-4474-2498\")), person(\"Winston\", \"Chang\", , \"winston@posit.co\", role = \"ctb\"), person(\"Dave\", \"Gandy\", role = c(\"ctb\", \"cph\"), comment = \"Font-Awesome font\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )", - "License": "MIT + file LICENSE", - "URL": "https://github.com/rstudio/fontawesome, https://rstudio.github.io/fontawesome/", - "BugReports": "https://github.com/rstudio/fontawesome/issues", - "Encoding": "UTF-8", - "ByteCompile": "true", - "RoxygenNote": "7.3.2", - "Depends": [ - "R (>= 3.3.0)" - ], - "Imports": [ - "rlang (>= 1.0.6)", - "htmltools (>= 0.5.1.1)" - ], - "Suggests": [ - "covr", - "dplyr (>= 1.0.8)", - "gt (>= 0.9.0)", - "knitr (>= 1.31)", - "testthat (>= 3.0.0)", - "rsvg" - ], - "Config/testthat/edition": "3", - "NeedsCompilation": "no", - "Author": "Richard Iannone [aut, cre] (), Christophe Dervieux [ctb] (), Winston Chang [ctb], Dave Gandy [ctb, cph] (Font-Awesome font), Posit Software, PBC [cph, fnd]", - "Maintainer": "Richard Iannone ", - "Repository": "CRAN" - }, - "fs": { - "Package": "fs", - "Version": "1.6.5", - "Source": "Repository", - "Title": "Cross-Platform File System Operations Based on 'libuv'", - "Authors@R": "c( person(\"Jim\", \"Hester\", role = \"aut\"), person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = \"aut\"), person(\"Gábor\", \"Csárdi\", , \"csardi.gabor@gmail.com\", role = c(\"aut\", \"cre\")), person(\"libuv project contributors\", role = \"cph\", comment = \"libuv library\"), person(\"Joyent, Inc. and other Node contributors\", role = \"cph\", comment = \"libuv library\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )", - "Description": "A cross-platform interface to file system operations, built on top of the 'libuv' C library.", - "License": "MIT + file LICENSE", - "URL": "https://fs.r-lib.org, https://github.com/r-lib/fs", - "BugReports": "https://github.com/r-lib/fs/issues", - "Depends": [ - "R (>= 3.6)" - ], - "Imports": [ - "methods" - ], - "Suggests": [ - "covr", - "crayon", - "knitr", - "pillar (>= 1.0.0)", - "rmarkdown", - "spelling", - "testthat (>= 3.0.0)", - "tibble (>= 1.1.0)", - "vctrs (>= 0.3.0)", - "withr" - ], - "VignetteBuilder": "knitr", - "ByteCompile": "true", - "Config/Needs/website": "tidyverse/tidytemplate", - "Config/testthat/edition": "3", - "Copyright": "file COPYRIGHTS", - "Encoding": "UTF-8", - "Language": "en-US", - "RoxygenNote": "7.2.3", - "SystemRequirements": "GNU make", - "NeedsCompilation": "yes", - "Author": "Jim Hester [aut], Hadley Wickham [aut], Gábor Csárdi [aut, cre], libuv project contributors [cph] (libuv library), Joyent, Inc. and other Node contributors [cph] (libuv library), Posit Software, PBC [cph, fnd]", - "Maintainer": "Gábor Csárdi ", - "Repository": "CRAN" - }, - "glue": { - "Package": "glue", - "Version": "1.8.0", - "Source": "Repository", - "Title": "Interpreted String Literals", - "Authors@R": "c( person(\"Jim\", \"Hester\", role = \"aut\", comment = c(ORCID = \"0000-0002-2739-7082\")), person(\"Jennifer\", \"Bryan\", , \"jenny@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-6983-2759\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )", - "Description": "An implementation of interpreted string literals, inspired by Python's Literal String Interpolation and Docstrings and Julia's Triple-Quoted String Literals .", - "License": "MIT + file LICENSE", - "URL": "https://glue.tidyverse.org/, https://github.com/tidyverse/glue", - "BugReports": "https://github.com/tidyverse/glue/issues", - "Depends": [ - "R (>= 3.6)" - ], - "Imports": [ - "methods" - ], - "Suggests": [ - "crayon", - "DBI (>= 1.2.0)", - "dplyr", - "knitr", - "magrittr", - "rlang", - "rmarkdown", - "RSQLite", - "testthat (>= 3.2.0)", - "vctrs (>= 0.3.0)", - "waldo (>= 0.5.3)", - "withr" - ], - "VignetteBuilder": "knitr", - "ByteCompile": "true", - "Config/Needs/website": "bench, forcats, ggbeeswarm, ggplot2, R.utils, rprintf, tidyr, tidyverse/tidytemplate", - "Config/testthat/edition": "3", - "Encoding": "UTF-8", - "RoxygenNote": "7.3.2", - "NeedsCompilation": "yes", - "Author": "Jim Hester [aut] (), Jennifer Bryan [aut, cre] (), Posit Software, PBC [cph, fnd]", - "Maintainer": "Jennifer Bryan ", - "Repository": "CRAN" - }, - "highr": { - "Package": "highr", - "Version": "0.11", - "Source": "Repository", - "Type": "Package", - "Title": "Syntax Highlighting for R Source Code", - "Authors@R": "c( person(\"Yihui\", \"Xie\", role = c(\"aut\", \"cre\"), email = \"xie@yihui.name\", comment = c(ORCID = \"0000-0003-0645-5666\")), person(\"Yixuan\", \"Qiu\", role = \"aut\"), person(\"Christopher\", \"Gandrud\", role = \"ctb\"), person(\"Qiang\", \"Li\", role = \"ctb\") )", - "Description": "Provides syntax highlighting for R source code. Currently it supports LaTeX and HTML output. Source code of other languages is supported via Andre Simon's highlight package ().", - "Depends": [ - "R (>= 3.3.0)" - ], - "Imports": [ - "xfun (>= 0.18)" - ], - "Suggests": [ - "knitr", - "markdown", - "testit" - ], - "License": "GPL", - "URL": "https://github.com/yihui/highr", - "BugReports": "https://github.com/yihui/highr/issues", - "VignetteBuilder": "knitr", - "Encoding": "UTF-8", - "RoxygenNote": "7.3.1", - "NeedsCompilation": "no", - "Author": "Yihui Xie [aut, cre] (), Yixuan Qiu [aut], Christopher Gandrud [ctb], Qiang Li [ctb]", - "Maintainer": "Yihui Xie ", - "Repository": "CRAN" - }, - "htmltools": { - "Package": "htmltools", - "Version": "0.5.8.1", - "Source": "Repository", - "Type": "Package", - "Title": "Tools for HTML", - "Authors@R": "c( person(\"Joe\", \"Cheng\", , \"joe@posit.co\", role = \"aut\"), person(\"Carson\", \"Sievert\", , \"carson@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-4958-2844\")), person(\"Barret\", \"Schloerke\", , \"barret@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0001-9986-114X\")), person(\"Winston\", \"Chang\", , \"winston@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0002-1576-2126\")), person(\"Yihui\", \"Xie\", , \"yihui@posit.co\", role = \"aut\"), person(\"Jeff\", \"Allen\", role = \"aut\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )", - "Description": "Tools for HTML generation and output.", - "License": "GPL (>= 2)", - "URL": "https://github.com/rstudio/htmltools, https://rstudio.github.io/htmltools/", - "BugReports": "https://github.com/rstudio/htmltools/issues", - "Depends": [ - "R (>= 2.14.1)" - ], - "Imports": [ - "base64enc", - "digest", - "fastmap (>= 1.1.0)", - "grDevices", - "rlang (>= 1.0.0)", - "utils" - ], - "Suggests": [ - "Cairo", - "markdown", - "ragg", - "shiny", - "testthat", - "withr" - ], - "Enhances": [ - "knitr" - ], - "Config/Needs/check": "knitr", - "Config/Needs/website": "rstudio/quillt, bench", - "Encoding": "UTF-8", - "RoxygenNote": "7.3.1", - "Collate": "'colors.R' 'fill.R' 'html_dependency.R' 'html_escape.R' 'html_print.R' 'htmltools-package.R' 'images.R' 'known_tags.R' 'selector.R' 'staticimports.R' 'tag_query.R' 'utils.R' 'tags.R' 'template.R'", - "NeedsCompilation": "yes", - "Author": "Joe Cheng [aut], Carson Sievert [aut, cre] (), Barret Schloerke [aut] (), Winston Chang [aut] (), Yihui Xie [aut], Jeff Allen [aut], Posit Software, PBC [cph, fnd]", - "Maintainer": "Carson Sievert ", - "Repository": "CRAN" - }, - "jquerylib": { - "Package": "jquerylib", - "Version": "0.1.4", - "Source": "Repository", - "Title": "Obtain 'jQuery' as an HTML Dependency Object", - "Authors@R": "c( person(\"Carson\", \"Sievert\", role = c(\"aut\", \"cre\"), email = \"carson@rstudio.com\", comment = c(ORCID = \"0000-0002-4958-2844\")), person(\"Joe\", \"Cheng\", role = \"aut\", email = \"joe@rstudio.com\"), person(family = \"RStudio\", role = \"cph\"), person(family = \"jQuery Foundation\", role = \"cph\", comment = \"jQuery library and jQuery UI library\"), person(family = \"jQuery contributors\", role = c(\"ctb\", \"cph\"), comment = \"jQuery library; authors listed in inst/lib/jquery-AUTHORS.txt\") )", - "Description": "Obtain any major version of 'jQuery' () and use it in any webpage generated by 'htmltools' (e.g. 'shiny', 'htmlwidgets', and 'rmarkdown'). Most R users don't need to use this package directly, but other R packages (e.g. 'shiny', 'rmarkdown', etc.) depend on this package to avoid bundling redundant copies of 'jQuery'.", - "License": "MIT + file LICENSE", - "Encoding": "UTF-8", - "Config/testthat/edition": "3", - "RoxygenNote": "7.0.2", - "Imports": [ - "htmltools" - ], - "Suggests": [ - "testthat" - ], - "NeedsCompilation": "no", - "Author": "Carson Sievert [aut, cre] (), Joe Cheng [aut], RStudio [cph], jQuery Foundation [cph] (jQuery library and jQuery UI library), jQuery contributors [ctb, cph] (jQuery library; authors listed in inst/lib/jquery-AUTHORS.txt)", - "Maintainer": "Carson Sievert ", - "Repository": "CRAN" - }, - "jsonlite": { - "Package": "jsonlite", - "Version": "1.9.1", - "Source": "Repository", - "Title": "A Simple and Robust JSON Parser and Generator for R", - "License": "MIT + file LICENSE", - "Depends": [ - "methods" - ], - "Authors@R": "c( person(\"Jeroen\", \"Ooms\", role = c(\"aut\", \"cre\"), email = \"jeroenooms@gmail.com\", comment = c(ORCID = \"0000-0002-4035-0289\")), person(\"Duncan\", \"Temple Lang\", role = \"ctb\"), person(\"Lloyd\", \"Hilaiel\", role = \"cph\", comment=\"author of bundled libyajl\"))", - "URL": "https://jeroen.r-universe.dev/jsonlite https://arxiv.org/abs/1403.2805", - "BugReports": "https://github.com/jeroen/jsonlite/issues", - "Maintainer": "Jeroen Ooms ", - "VignetteBuilder": "knitr, R.rsp", - "Description": "A reasonably fast JSON parser and generator, optimized for statistical data and the web. Offers simple, flexible tools for working with JSON in R, and is particularly powerful for building pipelines and interacting with a web API. The implementation is based on the mapping described in the vignette (Ooms, 2014). In addition to converting JSON data from/to R objects, 'jsonlite' contains functions to stream, validate, and prettify JSON data. The unit tests included with the package verify that all edge cases are encoded and decoded consistently for use with dynamic data in systems and applications.", - "Suggests": [ - "httr", - "vctrs", - "testthat", - "knitr", - "rmarkdown", - "R.rsp", - "sf" - ], - "RoxygenNote": "7.2.3", - "Encoding": "UTF-8", - "NeedsCompilation": "yes", - "Author": "Jeroen Ooms [aut, cre] (), Duncan Temple Lang [ctb], Lloyd Hilaiel [cph] (author of bundled libyajl)", - "Repository": "CRAN" - }, - "knitr": { - "Package": "knitr", - "Version": "1.51", - "Source": "Repository", - "Type": "Package", - "Title": "A General-Purpose Package for Dynamic Report Generation in R", - "Authors@R": "c( person(\"Yihui\", \"Xie\", role = c(\"aut\", \"cre\"), email = \"xie@yihui.name\", comment = c(ORCID = \"0000-0003-0645-5666\")), person(\"Abhraneel\", \"Sarma\", role = \"ctb\"), person(\"Adam\", \"Vogt\", role = \"ctb\"), person(\"Alastair\", \"Andrew\", role = \"ctb\"), person(\"Alex\", \"Zvoleff\", role = \"ctb\"), person(\"Amar\", \"Al-Zubaidi\", role = \"ctb\"), person(\"Andre\", \"Simon\", role = \"ctb\", comment = \"the CSS files under inst/themes/ were derived from the Highlight package http://www.andre-simon.de\"), person(\"Aron\", \"Atkins\", role = \"ctb\"), person(\"Aaron\", \"Wolen\", role = \"ctb\"), person(\"Ashley\", \"Manton\", role = \"ctb\"), person(\"Atsushi\", \"Yasumoto\", role = \"ctb\", comment = c(ORCID = \"0000-0002-8335-495X\")), person(\"Ben\", \"Baumer\", role = \"ctb\"), person(\"Brian\", \"Diggs\", role = \"ctb\"), person(\"Brian\", \"Zhang\", role = \"ctb\"), person(\"Bulat\", \"Yapparov\", role = \"ctb\"), person(\"Cassio\", \"Pereira\", role = \"ctb\"), person(\"Christophe\", \"Dervieux\", role = \"ctb\"), person(\"David\", \"Hall\", role = \"ctb\"), person(\"David\", \"Hugh-Jones\", role = \"ctb\"), person(\"David\", \"Robinson\", role = \"ctb\"), person(\"Doug\", \"Hemken\", role = \"ctb\"), person(\"Duncan\", \"Murdoch\", role = \"ctb\"), person(\"Elio\", \"Campitelli\", role = \"ctb\"), person(\"Ellis\", \"Hughes\", role = \"ctb\"), person(\"Emily\", \"Riederer\", role = \"ctb\"), person(\"Fabian\", \"Hirschmann\", role = \"ctb\"), person(\"Fitch\", \"Simeon\", role = \"ctb\"), person(\"Forest\", \"Fang\", role = \"ctb\"), person(c(\"Frank\", \"E\", \"Harrell\", \"Jr\"), role = \"ctb\", comment = \"the Sweavel package at inst/misc/Sweavel.sty\"), person(\"Garrick\", \"Aden-Buie\", role = \"ctb\"), person(\"Gregoire\", \"Detrez\", role = \"ctb\"), person(\"Hadley\", \"Wickham\", role = \"ctb\"), person(\"Hao\", \"Zhu\", role = \"ctb\"), person(\"Heewon\", \"Jeon\", role = \"ctb\"), person(\"Henrik\", \"Bengtsson\", role = \"ctb\"), person(\"Hiroaki\", \"Yutani\", role = \"ctb\"), person(\"Ian\", \"Lyttle\", role = \"ctb\"), person(\"Hodges\", \"Daniel\", role = \"ctb\"), person(\"Jacob\", \"Bien\", role = \"ctb\"), person(\"Jake\", \"Burkhead\", role = \"ctb\"), person(\"James\", \"Manton\", role = \"ctb\"), person(\"Jared\", \"Lander\", role = \"ctb\"), person(\"Jason\", \"Punyon\", role = \"ctb\"), person(\"Javier\", \"Luraschi\", role = \"ctb\"), person(\"Jeff\", \"Arnold\", role = \"ctb\"), person(\"Jenny\", \"Bryan\", role = \"ctb\"), person(\"Jeremy\", \"Ashkenas\", role = c(\"ctb\", \"cph\"), comment = \"the CSS file at inst/misc/docco-classic.css\"), person(\"Jeremy\", \"Stephens\", role = \"ctb\"), person(\"Jim\", \"Hester\", role = \"ctb\"), person(\"Joe\", \"Cheng\", role = \"ctb\"), person(\"Johannes\", \"Ranke\", role = \"ctb\"), person(\"John\", \"Honaker\", role = \"ctb\"), person(\"John\", \"Muschelli\", role = \"ctb\"), person(\"Jonathan\", \"Keane\", role = \"ctb\"), person(\"JJ\", \"Allaire\", role = \"ctb\"), person(\"Johan\", \"Toloe\", role = \"ctb\"), person(\"Jonathan\", \"Sidi\", role = \"ctb\"), person(\"Joseph\", \"Larmarange\", role = \"ctb\"), person(\"Julien\", \"Barnier\", role = \"ctb\"), person(\"Kaiyin\", \"Zhong\", role = \"ctb\"), person(\"Kamil\", \"Slowikowski\", role = \"ctb\"), person(\"Karl\", \"Forner\", role = \"ctb\"), person(c(\"Kevin\", \"K.\"), \"Smith\", role = \"ctb\"), person(\"Kirill\", \"Mueller\", role = \"ctb\"), person(\"Kohske\", \"Takahashi\", role = \"ctb\"), person(\"Lorenz\", \"Walthert\", role = \"ctb\"), person(\"Lucas\", \"Gallindo\", role = \"ctb\"), person(\"Marius\", \"Hofert\", role = \"ctb\"), person(\"Martin\", \"Modrák\", role = \"ctb\"), person(\"Michael\", \"Chirico\", role = \"ctb\"), person(\"Michael\", \"Friendly\", role = \"ctb\"), person(\"Michal\", \"Bojanowski\", role = \"ctb\"), person(\"Michel\", \"Kuhlmann\", role = \"ctb\"), person(\"Miller\", \"Patrick\", role = \"ctb\"), person(\"Nacho\", \"Caballero\", role = \"ctb\"), person(\"Nick\", \"Salkowski\", role = \"ctb\"), person(\"Niels Richard\", \"Hansen\", role = \"ctb\"), person(\"Noam\", \"Ross\", role = \"ctb\"), person(\"Obada\", \"Mahdi\", role = \"ctb\"), person(\"Pavel N.\", \"Krivitsky\", role = \"ctb\", comment=c(ORCID = \"0000-0002-9101-3362\")), person(\"Pedro\", \"Faria\", role = \"ctb\"), person(\"Qiang\", \"Li\", role = \"ctb\"), person(\"Ramnath\", \"Vaidyanathan\", role = \"ctb\"), person(\"Richard\", \"Cotton\", role = \"ctb\"), person(\"Robert\", \"Krzyzanowski\", role = \"ctb\"), person(\"Rodrigo\", \"Copetti\", role = \"ctb\"), person(\"Romain\", \"Francois\", role = \"ctb\"), person(\"Ruaridh\", \"Williamson\", role = \"ctb\"), person(\"Sagiru\", \"Mati\", role = \"ctb\", comment = c(ORCID = \"0000-0003-1413-3974\")), person(\"Scott\", \"Kostyshak\", role = \"ctb\"), person(\"Sebastian\", \"Meyer\", role = \"ctb\"), person(\"Sietse\", \"Brouwer\", role = \"ctb\"), person(c(\"Simon\", \"de\"), \"Bernard\", role = \"ctb\"), person(\"Sylvain\", \"Rousseau\", role = \"ctb\"), person(\"Taiyun\", \"Wei\", role = \"ctb\"), person(\"Thibaut\", \"Assus\", role = \"ctb\"), person(\"Thibaut\", \"Lamadon\", role = \"ctb\"), person(\"Thomas\", \"Leeper\", role = \"ctb\"), person(\"Tim\", \"Mastny\", role = \"ctb\"), person(\"Tom\", \"Torsney-Weir\", role = \"ctb\"), person(\"Trevor\", \"Davis\", role = \"ctb\"), person(\"Viktoras\", \"Veitas\", role = \"ctb\"), person(\"Weicheng\", \"Zhu\", role = \"ctb\"), person(\"Wush\", \"Wu\", role = \"ctb\"), person(\"Zachary\", \"Foster\", role = \"ctb\"), person(\"Zhian N.\", \"Kamvar\", role = \"ctb\", comment = c(ORCID = \"0000-0003-1458-7108\")), person(given = \"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )", - "Description": "Provides a general-purpose tool for dynamic report generation in R using Literate Programming techniques.", - "Depends": [ - "R (>= 3.6.0)" - ], - "Imports": [ - "evaluate (>= 0.15)", - "highr (>= 0.11)", - "methods", - "tools", - "xfun (>= 0.48)", - "yaml (>= 2.1.19)" - ], - "Suggests": [ - "bslib", - "codetools", - "DBI (>= 0.4-1)", - "digest", - "formatR", - "gifski", - "gridSVG", - "htmlwidgets (>= 0.7)", - "jpeg", - "JuliaCall (>= 0.11.1)", - "magick", - "litedown", - "markdown (>= 1.3)", - "png", - "ragg", - "reticulate (>= 1.4)", - "rgl (>= 0.95.1201)", - "rlang", - "rmarkdown", - "sass", - "showtext", - "styler (>= 1.2.0)", - "targets (>= 0.6.0)", - "testit", - "tibble", - "tikzDevice (>= 0.10)", - "tinytex (>= 0.46)", - "webshot", - "rstudioapi", - "svglite" - ], - "License": "GPL", - "URL": "https://yihui.org/knitr/", - "BugReports": "https://github.com/yihui/knitr/issues", - "Encoding": "UTF-8", - "VignetteBuilder": "litedown, knitr", - "SystemRequirements": "Package vignettes based on R Markdown v2 or reStructuredText require Pandoc (http://pandoc.org). The function rst2pdf() requires rst2pdf (https://github.com/rst2pdf/rst2pdf).", - "Collate": "'block.R' 'cache.R' 'utils.R' 'citation.R' 'hooks-html.R' 'plot.R' 'defaults.R' 'concordance.R' 'engine.R' 'highlight.R' 'themes.R' 'header.R' 'hooks-asciidoc.R' 'hooks-chunk.R' 'hooks-extra.R' 'hooks-latex.R' 'hooks-md.R' 'hooks-rst.R' 'hooks-textile.R' 'hooks.R' 'output.R' 'package.R' 'pandoc.R' 'params.R' 'parser.R' 'pattern.R' 'rocco.R' 'spin.R' 'table.R' 'template.R' 'utils-conversion.R' 'utils-rd2html.R' 'utils-string.R' 'utils-sweave.R' 'utils-upload.R' 'utils-vignettes.R' 'zzz.R'", - "RoxygenNote": "7.3.2", - "NeedsCompilation": "no", - "Author": "Yihui Xie [aut, cre] (), Abhraneel Sarma [ctb], Adam Vogt [ctb], Alastair Andrew [ctb], Alex Zvoleff [ctb], Amar Al-Zubaidi [ctb], Andre Simon [ctb] (the CSS files under inst/themes/ were derived from the Highlight package http://www.andre-simon.de), Aron Atkins [ctb], Aaron Wolen [ctb], Ashley Manton [ctb], Atsushi Yasumoto [ctb] (), Ben Baumer [ctb], Brian Diggs [ctb], Brian Zhang [ctb], Bulat Yapparov [ctb], Cassio Pereira [ctb], Christophe Dervieux [ctb], David Hall [ctb], David Hugh-Jones [ctb], David Robinson [ctb], Doug Hemken [ctb], Duncan Murdoch [ctb], Elio Campitelli [ctb], Ellis Hughes [ctb], Emily Riederer [ctb], Fabian Hirschmann [ctb], Fitch Simeon [ctb], Forest Fang [ctb], Frank E Harrell Jr [ctb] (the Sweavel package at inst/misc/Sweavel.sty), Garrick Aden-Buie [ctb], Gregoire Detrez [ctb], Hadley Wickham [ctb], Hao Zhu [ctb], Heewon Jeon [ctb], Henrik Bengtsson [ctb], Hiroaki Yutani [ctb], Ian Lyttle [ctb], Hodges Daniel [ctb], Jacob Bien [ctb], Jake Burkhead [ctb], James Manton [ctb], Jared Lander [ctb], Jason Punyon [ctb], Javier Luraschi [ctb], Jeff Arnold [ctb], Jenny Bryan [ctb], Jeremy Ashkenas [ctb, cph] (the CSS file at inst/misc/docco-classic.css), Jeremy Stephens [ctb], Jim Hester [ctb], Joe Cheng [ctb], Johannes Ranke [ctb], John Honaker [ctb], John Muschelli [ctb], Jonathan Keane [ctb], JJ Allaire [ctb], Johan Toloe [ctb], Jonathan Sidi [ctb], Joseph Larmarange [ctb], Julien Barnier [ctb], Kaiyin Zhong [ctb], Kamil Slowikowski [ctb], Karl Forner [ctb], Kevin K. Smith [ctb], Kirill Mueller [ctb], Kohske Takahashi [ctb], Lorenz Walthert [ctb], Lucas Gallindo [ctb], Marius Hofert [ctb], Martin Modrák [ctb], Michael Chirico [ctb], Michael Friendly [ctb], Michal Bojanowski [ctb], Michel Kuhlmann [ctb], Miller Patrick [ctb], Nacho Caballero [ctb], Nick Salkowski [ctb], Niels Richard Hansen [ctb], Noam Ross [ctb], Obada Mahdi [ctb], Pavel N. Krivitsky [ctb] (), Pedro Faria [ctb], Qiang Li [ctb], Ramnath Vaidyanathan [ctb], Richard Cotton [ctb], Robert Krzyzanowski [ctb], Rodrigo Copetti [ctb], Romain Francois [ctb], Ruaridh Williamson [ctb], Sagiru Mati [ctb] (), Scott Kostyshak [ctb], Sebastian Meyer [ctb], Sietse Brouwer [ctb], Simon de Bernard [ctb], Sylvain Rousseau [ctb], Taiyun Wei [ctb], Thibaut Assus [ctb], Thibaut Lamadon [ctb], Thomas Leeper [ctb], Tim Mastny [ctb], Tom Torsney-Weir [ctb], Trevor Davis [ctb], Viktoras Veitas [ctb], Weicheng Zhu [ctb], Wush Wu [ctb], Zachary Foster [ctb], Zhian N. Kamvar [ctb] (), Posit Software, PBC [cph, fnd]", - "Maintainer": "Yihui Xie ", - "Repository": "CRAN" - }, - "lifecycle": { - "Package": "lifecycle", - "Version": "1.0.4", - "Source": "Repository", - "Title": "Manage the Life Cycle of your Package Functions", - "Authors@R": "c( person(\"Lionel\", \"Henry\", , \"lionel@posit.co\", role = c(\"aut\", \"cre\")), person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0003-4757-117X\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )", - "Description": "Manage the life cycle of your exported functions with shared conventions, documentation badges, and user-friendly deprecation warnings.", - "License": "MIT + file LICENSE", - "URL": "https://lifecycle.r-lib.org/, https://github.com/r-lib/lifecycle", - "BugReports": "https://github.com/r-lib/lifecycle/issues", - "Depends": [ - "R (>= 3.6)" - ], - "Imports": [ - "cli (>= 3.4.0)", - "glue", - "rlang (>= 1.1.0)" - ], - "Suggests": [ - "covr", - "crayon", - "knitr", - "lintr", - "rmarkdown", - "testthat (>= 3.0.1)", - "tibble", - "tidyverse", - "tools", - "vctrs", - "withr" - ], - "VignetteBuilder": "knitr", - "Config/Needs/website": "tidyverse/tidytemplate, usethis", - "Config/testthat/edition": "3", - "Encoding": "UTF-8", - "RoxygenNote": "7.2.1", - "NeedsCompilation": "no", - "Author": "Lionel Henry [aut, cre], Hadley Wickham [aut] (), Posit Software, PBC [cph, fnd]", - "Maintainer": "Lionel Henry ", - "Repository": "CRAN" - }, - "memoise": { - "Package": "memoise", - "Version": "2.0.1", - "Source": "Repository", - "Title": "'Memoisation' of Functions", - "Authors@R": "c(person(given = \"Hadley\", family = \"Wickham\", role = \"aut\", email = \"hadley@rstudio.com\"), person(given = \"Jim\", family = \"Hester\", role = \"aut\"), person(given = \"Winston\", family = \"Chang\", role = c(\"aut\", \"cre\"), email = \"winston@rstudio.com\"), person(given = \"Kirill\", family = \"Müller\", role = \"aut\", email = \"krlmlr+r@mailbox.org\"), person(given = \"Daniel\", family = \"Cook\", role = \"aut\", email = \"danielecook@gmail.com\"), person(given = \"Mark\", family = \"Edmondson\", role = \"ctb\", email = \"r@sunholo.com\"))", - "Description": "Cache the results of a function so that when you call it again with the same arguments it returns the previously computed value.", - "License": "MIT + file LICENSE", - "URL": "https://memoise.r-lib.org, https://github.com/r-lib/memoise", - "BugReports": "https://github.com/r-lib/memoise/issues", - "Imports": [ - "rlang (>= 0.4.10)", - "cachem" - ], - "Suggests": [ - "digest", - "aws.s3", - "covr", - "googleAuthR", - "googleCloudStorageR", - "httr", - "testthat" - ], - "Encoding": "UTF-8", - "RoxygenNote": "7.1.2", - "NeedsCompilation": "no", - "Author": "Hadley Wickham [aut], Jim Hester [aut], Winston Chang [aut, cre], Kirill Müller [aut], Daniel Cook [aut], Mark Edmondson [ctb]", - "Maintainer": "Winston Chang ", - "Repository": "CRAN" - }, - "mime": { - "Package": "mime", - "Version": "0.12", - "Source": "Repository", - "Type": "Package", - "Title": "Map Filenames to MIME Types", - "Authors@R": "c( person(\"Yihui\", \"Xie\", role = c(\"aut\", \"cre\"), email = \"xie@yihui.name\", comment = c(ORCID = \"0000-0003-0645-5666\")), person(\"Jeffrey\", \"Horner\", role = \"ctb\"), person(\"Beilei\", \"Bian\", role = \"ctb\") )", - "Description": "Guesses the MIME type from a filename extension using the data derived from /etc/mime.types in UNIX-type systems.", - "Imports": [ - "tools" - ], - "License": "GPL", - "URL": "https://github.com/yihui/mime", - "BugReports": "https://github.com/yihui/mime/issues", - "RoxygenNote": "7.1.1", - "Encoding": "UTF-8", - "NeedsCompilation": "yes", - "Author": "Yihui Xie [aut, cre] (), Jeffrey Horner [ctb], Beilei Bian [ctb]", - "Maintainer": "Yihui Xie ", - "Repository": "CRAN" - }, - "rappdirs": { - "Package": "rappdirs", - "Version": "0.3.3", - "Source": "Repository", - "Type": "Package", - "Title": "Application Directories: Determine Where to Save Data, Caches, and Logs", - "Authors@R": "c(person(given = \"Hadley\", family = \"Wickham\", role = c(\"trl\", \"cre\", \"cph\"), email = \"hadley@rstudio.com\"), person(given = \"RStudio\", role = \"cph\"), person(given = \"Sridhar\", family = \"Ratnakumar\", role = \"aut\"), person(given = \"Trent\", family = \"Mick\", role = \"aut\"), person(given = \"ActiveState\", role = \"cph\", comment = \"R/appdir.r, R/cache.r, R/data.r, R/log.r translated from appdirs\"), person(given = \"Eddy\", family = \"Petrisor\", role = \"ctb\"), person(given = \"Trevor\", family = \"Davis\", role = c(\"trl\", \"aut\")), person(given = \"Gabor\", family = \"Csardi\", role = \"ctb\"), person(given = \"Gregory\", family = \"Jefferis\", role = \"ctb\"))", - "Description": "An easy way to determine which directories on the users computer you should use to save data, caches and logs. A port of Python's 'Appdirs' () to R.", - "License": "MIT + file LICENSE", - "URL": "https://rappdirs.r-lib.org, https://github.com/r-lib/rappdirs", - "BugReports": "https://github.com/r-lib/rappdirs/issues", - "Depends": [ - "R (>= 3.2)" - ], - "Suggests": [ - "roxygen2", - "testthat (>= 3.0.0)", - "covr", - "withr" - ], - "Copyright": "Original python appdirs module copyright (c) 2010 ActiveState Software Inc. R port copyright Hadley Wickham, RStudio. See file LICENSE for details.", - "Encoding": "UTF-8", - "RoxygenNote": "7.1.1", - "Config/testthat/edition": "3", - "NeedsCompilation": "yes", - "Author": "Hadley Wickham [trl, cre, cph], RStudio [cph], Sridhar Ratnakumar [aut], Trent Mick [aut], ActiveState [cph] (R/appdir.r, R/cache.r, R/data.r, R/log.r translated from appdirs), Eddy Petrisor [ctb], Trevor Davis [trl, aut], Gabor Csardi [ctb], Gregory Jefferis [ctb]", - "Maintainer": "Hadley Wickham ", - "Repository": "CRAN" - }, - "renv": { - "Package": "renv", - "Version": "1.1.2", - "Source": "Repository", - "Type": "Package", - "Title": "Project Environments", - "Authors@R": "c( person(\"Kevin\", \"Ushey\", role = c(\"aut\", \"cre\"), email = \"kevin@rstudio.com\", comment = c(ORCID = \"0000-0003-2880-7407\")), person(\"Hadley\", \"Wickham\", role = c(\"aut\"), email = \"hadley@rstudio.com\", comment = c(ORCID = \"0000-0003-4757-117X\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )", - "Description": "A dependency management toolkit for R. Using 'renv', you can create and manage project-local R libraries, save the state of these libraries to a 'lockfile', and later restore your library as required. Together, these tools can help make your projects more isolated, portable, and reproducible.", - "License": "MIT + file LICENSE", - "URL": "https://rstudio.github.io/renv/, https://github.com/rstudio/renv", - "BugReports": "https://github.com/rstudio/renv/issues", - "Imports": [ - "utils" - ], - "Suggests": [ - "BiocManager", - "cli", - "compiler", - "covr", - "cpp11", - "devtools", - "gitcreds", - "jsonlite", - "jsonvalidate", - "knitr", - "miniUI", - "modules", - "packrat", - "pak", - "R6", - "remotes", - "reticulate", - "rmarkdown", - "rstudioapi", - "shiny", - "testthat", - "uuid", - "waldo", - "yaml", - "webfakes" - ], - "Encoding": "UTF-8", - "RoxygenNote": "7.3.2", - "VignetteBuilder": "knitr", - "Config/Needs/website": "tidyverse/tidytemplate", - "Config/testthat/edition": "3", - "Config/testthat/parallel": "true", - "Config/testthat/start-first": "bioconductor,python,install,restore,snapshot,retrieve,remotes", - "NeedsCompilation": "no", - "Author": "Kevin Ushey [aut, cre] (), Hadley Wickham [aut] (), Posit Software, PBC [cph, fnd]", - "Maintainer": "Kevin Ushey ", - "Repository": "RSPM" - }, - "rlang": { - "Package": "rlang", - "Version": "1.1.5", - "Source": "Repository", - "Title": "Functions for Base Types and Core R and 'Tidyverse' Features", - "Description": "A toolbox for working with base types, core R features like the condition system, and core 'Tidyverse' features like tidy evaluation.", - "Authors@R": "c( person(\"Lionel\", \"Henry\", ,\"lionel@posit.co\", c(\"aut\", \"cre\")), person(\"Hadley\", \"Wickham\", ,\"hadley@posit.co\", \"aut\"), person(given = \"mikefc\", email = \"mikefc@coolbutuseless.com\", role = \"cph\", comment = \"Hash implementation based on Mike's xxhashlite\"), person(given = \"Yann\", family = \"Collet\", role = \"cph\", comment = \"Author of the embedded xxHash library\"), person(given = \"Posit, PBC\", role = c(\"cph\", \"fnd\")) )", - "License": "MIT + file LICENSE", - "ByteCompile": "true", - "Biarch": "true", - "Depends": [ - "R (>= 3.5.0)" - ], - "Imports": [ - "utils" - ], - "Suggests": [ - "cli (>= 3.1.0)", - "covr", - "crayon", - "fs", - "glue", - "knitr", - "magrittr", - "methods", - "pillar", - "rmarkdown", - "stats", - "testthat (>= 3.0.0)", - "tibble", - "usethis", - "vctrs (>= 0.2.3)", - "withr" - ], - "Enhances": [ - "winch" - ], - "Encoding": "UTF-8", - "RoxygenNote": "7.3.2", - "URL": "https://rlang.r-lib.org, https://github.com/r-lib/rlang", - "BugReports": "https://github.com/r-lib/rlang/issues", - "Config/testthat/edition": "3", - "Config/Needs/website": "dplyr, tidyverse/tidytemplate", - "NeedsCompilation": "yes", - "Author": "Lionel Henry [aut, cre], Hadley Wickham [aut], mikefc [cph] (Hash implementation based on Mike's xxhashlite), Yann Collet [cph] (Author of the embedded xxHash library), Posit, PBC [cph, fnd]", - "Maintainer": "Lionel Henry ", - "Repository": "CRAN" - }, - "rmarkdown": { - "Package": "rmarkdown", - "Version": "2.31", - "Source": "Repository", - "Type": "Package", - "Title": "Dynamic Documents for R", - "Authors@R": "c( person(\"JJ\", \"Allaire\", , \"jj@posit.co\", role = \"aut\"), person(\"Yihui\", \"Xie\", , \"xie@yihui.name\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0003-0645-5666\")), person(\"Christophe\", \"Dervieux\", , \"cderv@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0003-4474-2498\")), person(\"Jonathan\", \"McPherson\", , \"jonathan@posit.co\", role = \"aut\"), person(\"Javier\", \"Luraschi\", role = \"aut\"), person(\"Kevin\", \"Ushey\", , \"kevin@posit.co\", role = \"aut\"), person(\"Aron\", \"Atkins\", , \"aron@posit.co\", role = \"aut\"), person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = \"aut\"), person(\"Joe\", \"Cheng\", , \"joe@posit.co\", role = \"aut\"), person(\"Winston\", \"Chang\", , \"winston@posit.co\", role = \"aut\"), person(\"Richard\", \"Iannone\", , \"rich@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0003-3925-190X\")), person(\"Andrew\", \"Dunning\", role = \"ctb\", comment = c(ORCID = \"0000-0003-0464-5036\")), person(\"Atsushi\", \"Yasumoto\", role = c(\"ctb\", \"cph\"), comment = c(ORCID = \"0000-0002-8335-495X\", cph = \"Number sections Lua filter\")), person(\"Barret\", \"Schloerke\", role = \"ctb\"), person(\"Carson\", \"Sievert\", role = \"ctb\", comment = c(ORCID = \"0000-0002-4958-2844\")), person(\"Devon\", \"Ryan\", , \"dpryan79@gmail.com\", role = \"ctb\", comment = c(ORCID = \"0000-0002-8549-0971\")), person(\"Frederik\", \"Aust\", , \"frederik.aust@uni-koeln.de\", role = \"ctb\", comment = c(ORCID = \"0000-0003-4900-788X\")), person(\"Jeff\", \"Allen\", , \"jeff@posit.co\", role = \"ctb\"), person(\"JooYoung\", \"Seo\", role = \"ctb\", comment = c(ORCID = \"0000-0002-4064-6012\")), person(\"Malcolm\", \"Barrett\", role = \"ctb\"), person(\"Rob\", \"Hyndman\", , \"Rob.Hyndman@monash.edu\", role = \"ctb\"), person(\"Romain\", \"Lesur\", role = \"ctb\"), person(\"Roy\", \"Storey\", role = \"ctb\"), person(\"Ruben\", \"Arslan\", , \"ruben.arslan@uni-goettingen.de\", role = \"ctb\"), person(\"Sergio\", \"Oller\", role = \"ctb\"), person(given = \"Posit Software, PBC\", role = c(\"cph\", \"fnd\")), person(, \"jQuery UI contributors\", role = c(\"ctb\", \"cph\"), comment = \"jQuery UI library; authors listed in inst/rmd/h/jqueryui/AUTHORS.txt\"), person(\"Mark\", \"Otto\", role = \"ctb\", comment = \"Bootstrap library\"), person(\"Jacob\", \"Thornton\", role = \"ctb\", comment = \"Bootstrap library\"), person(, \"Bootstrap contributors\", role = \"ctb\", comment = \"Bootstrap library\"), person(, \"Twitter, Inc\", role = \"cph\", comment = \"Bootstrap library\"), person(\"Alexander\", \"Farkas\", role = c(\"ctb\", \"cph\"), comment = \"html5shiv library\"), person(\"Scott\", \"Jehl\", role = c(\"ctb\", \"cph\"), comment = \"Respond.js library\"), person(\"Ivan\", \"Sagalaev\", role = c(\"ctb\", \"cph\"), comment = \"highlight.js library\"), person(\"Greg\", \"Franko\", role = c(\"ctb\", \"cph\"), comment = \"tocify library\"), person(\"John\", \"MacFarlane\", role = c(\"ctb\", \"cph\"), comment = \"Pandoc templates\"), person(, \"Google, Inc.\", role = c(\"ctb\", \"cph\"), comment = \"ioslides library\"), person(\"Dave\", \"Raggett\", role = \"ctb\", comment = \"slidy library\"), person(, \"W3C\", role = \"cph\", comment = \"slidy library\"), person(\"Dave\", \"Gandy\", role = c(\"ctb\", \"cph\"), comment = \"Font-Awesome\"), person(\"Ben\", \"Sperry\", role = \"ctb\", comment = \"Ionicons\"), person(, \"Drifty\", role = \"cph\", comment = \"Ionicons\"), person(\"Aidan\", \"Lister\", role = c(\"ctb\", \"cph\"), comment = \"jQuery StickyTabs\"), person(\"Benct Philip\", \"Jonsson\", role = c(\"ctb\", \"cph\"), comment = \"pagebreak Lua filter\"), person(\"Albert\", \"Krewinkel\", role = c(\"ctb\", \"cph\"), comment = \"pagebreak Lua filter\") )", - "Description": "Convert R Markdown documents into a variety of formats.", - "License": "GPL-3", - "URL": "https://github.com/rstudio/rmarkdown, https://pkgs.rstudio.com/rmarkdown/", - "BugReports": "https://github.com/rstudio/rmarkdown/issues", - "Depends": [ - "R (>= 3.0)" - ], - "Imports": [ - "bslib (>= 0.2.5.1)", - "evaluate (>= 0.13)", - "fontawesome (>= 0.5.0)", - "htmltools (>= 0.5.1)", - "jquerylib", - "jsonlite", - "knitr (>= 1.43)", - "methods", - "tinytex (>= 0.31)", - "tools", - "utils", - "xfun (>= 0.36)", - "yaml (>= 2.1.19)" - ], - "Suggests": [ - "digest", - "dygraphs", - "fs", - "rsconnect", - "downlit (>= 0.4.0)", - "katex (>= 1.4.0)", - "sass (>= 0.4.0)", - "shiny (>= 1.6.0)", - "testthat (>= 3.0.3)", - "tibble", - "vctrs", - "cleanrmd", - "withr (>= 2.4.2)", - "xml2" - ], - "VignetteBuilder": "knitr", - "Config/Needs/website": "rstudio/quillt, pkgdown", - "Config/testthat/edition": "3", - "Encoding": "UTF-8", - "RoxygenNote": "7.3.2", - "SystemRequirements": "pandoc (>= 1.14) - http://pandoc.org", - "NeedsCompilation": "no", - "Author": "JJ Allaire [aut], Yihui Xie [aut, cre] (), Christophe Dervieux [aut] (), Jonathan McPherson [aut], Javier Luraschi [aut], Kevin Ushey [aut], Aron Atkins [aut], Hadley Wickham [aut], Joe Cheng [aut], Winston Chang [aut], Richard Iannone [aut] (), Andrew Dunning [ctb] (), Atsushi Yasumoto [ctb, cph] (, Number sections Lua filter), Barret Schloerke [ctb], Carson Sievert [ctb] (), Devon Ryan [ctb] (), Frederik Aust [ctb] (), Jeff Allen [ctb], JooYoung Seo [ctb] (), Malcolm Barrett [ctb], Rob Hyndman [ctb], Romain Lesur [ctb], Roy Storey [ctb], Ruben Arslan [ctb], Sergio Oller [ctb], Posit Software, PBC [cph, fnd], jQuery UI contributors [ctb, cph] (jQuery UI library; authors listed in inst/rmd/h/jqueryui/AUTHORS.txt), Mark Otto [ctb] (Bootstrap library), Jacob Thornton [ctb] (Bootstrap library), Bootstrap contributors [ctb] (Bootstrap library), Twitter, Inc [cph] (Bootstrap library), Alexander Farkas [ctb, cph] (html5shiv library), Scott Jehl [ctb, cph] (Respond.js library), Ivan Sagalaev [ctb, cph] (highlight.js library), Greg Franko [ctb, cph] (tocify library), John MacFarlane [ctb, cph] (Pandoc templates), Google, Inc. [ctb, cph] (ioslides library), Dave Raggett [ctb] (slidy library), W3C [cph] (slidy library), Dave Gandy [ctb, cph] (Font-Awesome), Ben Sperry [ctb] (Ionicons), Drifty [cph] (Ionicons), Aidan Lister [ctb, cph] (jQuery StickyTabs), Benct Philip Jonsson [ctb, cph] (pagebreak Lua filter), Albert Krewinkel [ctb, cph] (pagebreak Lua filter)", - "Maintainer": "Yihui Xie ", - "Repository": "CRAN" - }, - "sass": { - "Package": "sass", - "Version": "0.4.9", - "Source": "Repository", - "Type": "Package", - "Title": "Syntactically Awesome Style Sheets ('Sass')", - "Description": "An 'SCSS' compiler, powered by the 'LibSass' library. With this, R developers can use variables, inheritance, and functions to generate dynamic style sheets. The package uses the 'Sass CSS' extension language, which is stable, powerful, and CSS compatible.", - "Authors@R": "c( person(\"Joe\", \"Cheng\", , \"joe@rstudio.com\", \"aut\"), person(\"Timothy\", \"Mastny\", , \"tim.mastny@gmail.com\", \"aut\"), person(\"Richard\", \"Iannone\", , \"rich@rstudio.com\", \"aut\", comment = c(ORCID = \"0000-0003-3925-190X\")), person(\"Barret\", \"Schloerke\", , \"barret@rstudio.com\", \"aut\", comment = c(ORCID = \"0000-0001-9986-114X\")), person(\"Carson\", \"Sievert\", , \"carson@rstudio.com\", c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-4958-2844\")), person(\"Christophe\", \"Dervieux\", , \"cderv@rstudio.com\", c(\"ctb\"), comment = c(ORCID = \"0000-0003-4474-2498\")), person(family = \"RStudio\", role = c(\"cph\", \"fnd\")), person(family = \"Sass Open Source Foundation\", role = c(\"ctb\", \"cph\"), comment = \"LibSass library\"), person(\"Greter\", \"Marcel\", role = c(\"ctb\", \"cph\"), comment = \"LibSass library\"), person(\"Mifsud\", \"Michael\", role = c(\"ctb\", \"cph\"), comment = \"LibSass library\"), person(\"Hampton\", \"Catlin\", role = c(\"ctb\", \"cph\"), comment = \"LibSass library\"), person(\"Natalie\", \"Weizenbaum\", role = c(\"ctb\", \"cph\"), comment = \"LibSass library\"), person(\"Chris\", \"Eppstein\", role = c(\"ctb\", \"cph\"), comment = \"LibSass library\"), person(\"Adams\", \"Joseph\", role = c(\"ctb\", \"cph\"), comment = \"json.cpp\"), person(\"Trifunovic\", \"Nemanja\", role = c(\"ctb\", \"cph\"), comment = \"utf8.h\") )", - "License": "MIT + file LICENSE", - "URL": "https://rstudio.github.io/sass/, https://github.com/rstudio/sass", - "BugReports": "https://github.com/rstudio/sass/issues", - "Encoding": "UTF-8", - "RoxygenNote": "7.3.1", - "SystemRequirements": "GNU make", - "Imports": [ - "fs (>= 1.2.4)", - "rlang (>= 0.4.10)", - "htmltools (>= 0.5.1)", - "R6", - "rappdirs" - ], - "Suggests": [ - "testthat", - "knitr", - "rmarkdown", - "withr", - "shiny", - "curl" - ], - "VignetteBuilder": "knitr", - "Config/testthat/edition": "3", - "NeedsCompilation": "yes", - "Author": "Joe Cheng [aut], Timothy Mastny [aut], Richard Iannone [aut] (), Barret Schloerke [aut] (), Carson Sievert [aut, cre] (), Christophe Dervieux [ctb] (), RStudio [cph, fnd], Sass Open Source Foundation [ctb, cph] (LibSass library), Greter Marcel [ctb, cph] (LibSass library), Mifsud Michael [ctb, cph] (LibSass library), Hampton Catlin [ctb, cph] (LibSass library), Natalie Weizenbaum [ctb, cph] (LibSass library), Chris Eppstein [ctb, cph] (LibSass library), Adams Joseph [ctb, cph] (json.cpp), Trifunovic Nemanja [ctb, cph] (utf8.h)", - "Maintainer": "Carson Sievert ", - "Repository": "CRAN" - }, - "tinytex": { - "Package": "tinytex", - "Version": "0.56", - "Source": "Repository", - "Type": "Package", - "Title": "Helper Functions to Install and Maintain TeX Live, and Compile LaTeX Documents", - "Authors@R": "c( person(\"Yihui\", \"Xie\", role = c(\"aut\", \"cre\", \"cph\"), email = \"xie@yihui.name\", comment = c(ORCID = \"0000-0003-0645-5666\")), person(given = \"Posit Software, PBC\", role = c(\"cph\", \"fnd\")), person(\"Christophe\", \"Dervieux\", role = \"ctb\", comment = c(ORCID = \"0000-0003-4474-2498\")), person(\"Devon\", \"Ryan\", role = \"ctb\", email = \"dpryan79@gmail.com\", comment = c(ORCID = \"0000-0002-8549-0971\")), person(\"Ethan\", \"Heinzen\", role = \"ctb\"), person(\"Fernando\", \"Cagua\", role = \"ctb\"), person() )", - "Description": "Helper functions to install and maintain the 'LaTeX' distribution named 'TinyTeX' (), a lightweight, cross-platform, portable, and easy-to-maintain version of 'TeX Live'. This package also contains helper functions to compile 'LaTeX' documents, and install missing 'LaTeX' packages automatically.", - "Imports": [ - "xfun (>= 0.48)" - ], - "Suggests": [ - "testit", - "rstudioapi" - ], - "License": "MIT + file LICENSE", - "URL": "https://github.com/rstudio/tinytex", - "BugReports": "https://github.com/rstudio/tinytex/issues", - "Encoding": "UTF-8", - "RoxygenNote": "7.3.2", - "NeedsCompilation": "no", - "Author": "Yihui Xie [aut, cre, cph] (), Posit Software, PBC [cph, fnd], Christophe Dervieux [ctb] (), Devon Ryan [ctb] (), Ethan Heinzen [ctb], Fernando Cagua [ctb]", - "Maintainer": "Yihui Xie ", - "Repository": "CRAN" - }, - "xfun": { - "Package": "xfun", - "Version": "0.57", - "Source": "Repository", - "Type": "Package", - "Title": "Supporting Functions for Packages Maintained by 'Yihui Xie'", - "Authors@R": "c( person(\"Yihui\", \"Xie\", role = c(\"aut\", \"cre\", \"cph\"), email = \"xie@yihui.name\", comment = c(ORCID = \"0000-0003-0645-5666\", URL = \"https://yihui.org\")), person(\"Wush\", \"Wu\", role = \"ctb\"), person(\"Daijiang\", \"Li\", role = \"ctb\"), person(\"Xianying\", \"Tan\", role = \"ctb\"), person(\"Salim\", \"Brüggemann\", role = \"ctb\", email = \"salim-b@pm.me\", comment = c(ORCID = \"0000-0002-5329-5987\")), person(\"Christophe\", \"Dervieux\", role = \"ctb\"), person() )", - "Description": "Miscellaneous functions commonly used in other packages maintained by 'Yihui Xie'.", - "Depends": [ - "R (>= 3.2.0)" - ], - "Imports": [ - "grDevices", - "stats", - "tools" - ], - "Suggests": [ - "testit", - "parallel", - "codetools", - "methods", - "rstudioapi", - "tinytex (>= 0.30)", - "mime", - "litedown (>= 0.4)", - "commonmark", - "knitr (>= 1.47)", - "remotes", - "pak", - "rhub", - "renv", - "curl", - "xml2", - "jsonlite", - "magick", - "yaml", - "qs", - "rmarkdown" - ], - "License": "MIT + file LICENSE", - "URL": "https://github.com/yihui/xfun", - "BugReports": "https://github.com/yihui/xfun/issues", - "Encoding": "UTF-8", - "RoxygenNote": "7.3.2", - "VignetteBuilder": "litedown", - "NeedsCompilation": "yes", - "Author": "Yihui Xie [aut, cre, cph] (, https://yihui.org), Wush Wu [ctb], Daijiang Li [ctb], Xianying Tan [ctb], Salim Brüggemann [ctb] (), Christophe Dervieux [ctb]", - "Maintainer": "Yihui Xie ", - "Repository": "CRAN" - }, - "yaml": { - "Package": "yaml", - "Version": "2.3.10", - "Source": "Repository", - "Type": "Package", - "Title": "Methods to Convert R Data to YAML and Back", - "Date": "2024-07-22", - "Suggests": [ - "RUnit" - ], - "Author": "Shawn P Garbett [aut], Jeremy Stephens [aut, cre], Kirill Simonov [aut], Yihui Xie [ctb], Zhuoer Dong [ctb], Hadley Wickham [ctb], Jeffrey Horner [ctb], reikoch [ctb], Will Beasley [ctb], Brendan O'Connor [ctb], Gregory R. Warnes [ctb], Michael Quinn [ctb], Zhian N. Kamvar [ctb], Charlie Gao [ctb]", - "Maintainer": "Shawn Garbett ", - "License": "BSD_3_clause + file LICENSE", - "Description": "Implements the 'libyaml' 'YAML' 1.1 parser and emitter () for R.", - "URL": "https://github.com/vubiostat/r-yaml/", - "BugReports": "https://github.com/vubiostat/r-yaml/issues", - "NeedsCompilation": "yes", - "Repository": "CRAN" - } - } -} diff --git a/renv/profiles/lesson-requirements/renv/.gitignore b/renv/profiles/lesson-requirements/renv/.gitignore deleted file mode 100644 index 0ec0cbb..0000000 --- a/renv/profiles/lesson-requirements/renv/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -library/ -local/ -cellar/ -lock/ -python/ -sandbox/ -staging/ diff --git a/renv/profiles/lesson-requirements/renv/settings.json b/renv/profiles/lesson-requirements/renv/settings.json deleted file mode 100644 index ffdbb32..0000000 --- a/renv/profiles/lesson-requirements/renv/settings.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "bioconductor.version": null, - "external.libraries": [], - "ignored.packages": [], - "package.dependency.fields": [ - "Imports", - "Depends", - "LinkingTo" - ], - "ppm.enabled": null, - "ppm.ignored.urls": [], - "r.version": null, - "snapshot.type": "implicit", - "use.cache": true, - "vcs.ignore.cellar": true, - "vcs.ignore.library": true, - "vcs.ignore.local": true, - "vcs.manage.ignores": true -} From 051879d2d490416e5b50dc0e1a51f25fd553a589 Mon Sep 17 00:00:00 2001 From: Douglas Lowe <10961945+douglowe@users.noreply.github.com> Date: Fri, 2 Oct 2026 16:42:45 +0100 Subject: [PATCH 4/5] remove renv cache workflow as unneeded --- .github/workflows/update-cache.yaml | 190 ---------------------------- 1 file changed, 190 deletions(-) delete mode 100644 .github/workflows/update-cache.yaml diff --git a/.github/workflows/update-cache.yaml b/.github/workflows/update-cache.yaml deleted file mode 100644 index b711f2d..0000000 --- a/.github/workflows/update-cache.yaml +++ /dev/null @@ -1,190 +0,0 @@ -name: "02 Maintain: Check for Updated Packages" -description: "Check for updated R packages and create a pull request to update the lesson's renv lockfile and package cache" -on: - schedule: - - cron: '0 0 * * 2' # every Tuesday at midnight UTC - workflow_dispatch: - inputs: - name: - description: 'Who triggered this build?' - required: true - default: 'Maintainer (via GitHub)' - force-renv-init: - description: 'Force full lockfile update?' - required: false - default: false - type: boolean - update-packages: - description: 'Install any package updates?' - required: false - default: true - type: boolean - generate-cache: - description: 'Generate separate package cache?' - required: false - default: false - type: boolean - -env: - LOCKFILE_CACHE_GEN: ${{ vars.LOCKFILE_CACHE_GEN || github.event.inputs.generate-cache || 'false' }} - FORCE_RENV_INIT: ${{ vars.FORCE_RENV_INIT || github.event.inputs.force-renv-init || 'false' }} - UPDATE_PACKAGES: ${{ vars.UPDATE_PACKAGES || github.event.inputs.update-packages || 'true' }} - -jobs: - preflight: - name: "Preflight: Manual or Scheduled Trigger?" - runs-on: ubuntu-latest - outputs: - ok: ${{ steps.check.outputs.ok }} - steps: - - id: check - run: | - if [[ "${{ github.event_name }}" == 'workflow_dispatch' ]]; then - echo "ok=true" >> $GITHUB_OUTPUT - echo "Running on request" - # using single brackets here to avoid 08 being interpreted as octal - # https://github.com/carpentries/sandpaper/issues/250 - elif [ `date +%d` -le 7 ]; then - # If the Tuesday lands in the first week of the month, run it - echo "ok=true" >> $GITHUB_OUTPUT - echo "Running on schedule" - else - echo "ok=false" >> $GITHUB_OUTPUT - echo "Not Running Today" - fi - shell: bash - - check-renv: - name: "Check If We Need {renv}" - runs-on: ubuntu-latest - needs: preflight - if: ${{ needs.preflight.outputs.ok == 'true' }} - outputs: - renv-needed: ${{ steps.renv-check.outputs.renv-needed }} - steps: - - name: "Checkout Lesson" - uses: actions/checkout@v6 - - - name: "Is renv required?" - id: renv-check - uses: carpentries/actions/renv-checks@v1 - with: - CACHE_VERSION: ${{ inputs.CACHE_VERSION || '' }} - skip-cache-check: true - - update_cache: - name: "Create Package Update Pull Request" - runs-on: ubuntu-22.04 - needs: check-renv - permissions: - contents: write - pull-requests: write - actions: write - issues: write - id-token: write - if: needs.check-renv.outputs.renv-needed == 'true' - env: - GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - RENV_PATHS_ROOT: ~/.local/share/renv/ - steps: - - name: "Checkout Lesson" - uses: actions/checkout@v6 - - - name: "Set up R" - uses: r-lib/actions/setup-r@v2 - with: - use-public-rspm: true - install-r: false - - - name: "Update {renv} deps and determine if a PR is needed" - id: update - uses: carpentries/actions/update-lockfile@v1 - with: - update: ${{ env.UPDATE_PACKAGES }} - force-renv-init: ${{ env.FORCE_RENV_INIT }} - generate-cache: ${{ env.LOCKFILE_CACHE_GEN }} - cache-version: ${{ secrets.CACHE_VERSION }} - - - name: "Validate Current Org and Workflow" - id: validate-org-workflow - uses: carpentries/actions/validate-org-workflow@v1 - with: - repo: ${{ github.repository }} - workflow: ${{ github.workflow }} - - - name: "Configure AWS credentials via OIDC" - env: - role-to-assume: ${{ secrets.AWS_GH_OIDC_ARN }} - aws-region: ${{ secrets.AWS_GH_OIDC_REGION }} - if: | - steps.validate-org-workflow.outputs.is_valid == 'true' && - env.role-to-assume != '' && - env.aws-region != '' - uses: aws-actions/configure-aws-credentials@v6 - with: - role-to-assume: ${{ env.role-to-assume }} - aws-region: ${{ env.aws-region }} - - - name: "Set PAT from AWS Secrets Manager" - env: - role-to-assume: ${{ secrets.AWS_GH_OIDC_ARN }} - aws-region: ${{ secrets.AWS_GH_OIDC_REGION }} - if: | - steps.validate-org-workflow.outputs.is_valid == 'true' && - env.role-to-assume != '' && - env.aws-region != '' - id: set-pat - run: | - SECRET=$(aws secretsmanager get-secret-value \ - --secret-id carpentries-bot/github-pat \ - --query SecretString --output text) - PAT=$(echo "$SECRET" | jq -r .[]) - echo "::add-mask::$PAT" - echo "pat=$PAT" >> "$GITHUB_OUTPUT" - shell: bash - - # Create the PR with the following roles in order of preference: - # - Carpentries Bot classic PAT fetched from AWS (will only work in official Carpentries repos) - # - repo-scoped SANDPAPER_WORKFLOW classic PAT (will work in all scenarios) - # - default GITHUB_TOKEN (will work suitably, but workflows need to be triggered) - - name: "Create Pull Request" - id: cpr - if: | - steps.update.outputs.n > 0 - uses: carpentries/create-pull-request@main - with: - token: ${{ steps.set-pat.outputs.pat || secrets.SANDPAPER_WORKFLOW }} - delete-branch: true - branch: "update/packages" - commit-message: "[actions] update ${{ steps.update.outputs.n }} packages" - title: "Update ${{ steps.update.outputs.n }} packages" - body: | - :robot: This is an automated build - - This will update ${{ steps.update.outputs.n }} packages in your lesson with the following versions: - - ``` - ${{ steps.update.outputs.report }} - ``` - - :stopwatch: In a few minutes, a comment will appear that will show you how the output has changed based on these updates. - - If you want to inspect these changes locally, you can use the following code to check out a new branch: - - ```bash - git fetch origin update/packages - git checkout update/packages - ``` - - - Auto-generated by [create-pull-request][1] on ${{ steps.update.outputs.date }} - - [1]: https://github.com/carpentries/create-pull-request/tree/main - labels: "type: package cache" - draft: false - - - name: "Skip PR creation" - if: steps.update.outputs.n == 0 - run: | - echo "No updates needed, skipping PR creation" - shell: bash From 26719fc31b644e86bc5507f71914b9e4c28c064d Mon Sep 17 00:00:00 2001 From: Douglas Lowe <10961945+douglowe@users.noreply.github.com> Date: Fri, 2 Oct 2026 16:47:08 +0100 Subject: [PATCH 5/5] no renv cache needed for docker images either --- .github/workflows/docker_apply_cache.yaml | 187 ---------------------- 1 file changed, 187 deletions(-) delete mode 100644 .github/workflows/docker_apply_cache.yaml diff --git a/.github/workflows/docker_apply_cache.yaml b/.github/workflows/docker_apply_cache.yaml deleted file mode 100644 index dcebb3b..0000000 --- a/.github/workflows/docker_apply_cache.yaml +++ /dev/null @@ -1,187 +0,0 @@ -name: "03 Maintain: Apply Package Cache" -description: "Build and publish the lesson dependency image after a pull request has been merged or via manual trigger" -on: - workflow_dispatch: - inputs: - name: - description: 'Who triggered this build?' - required: true - default: 'Maintainer (via GitHub)' - force-dependency-image-rebuild: - description: 'Rebuild the dependency image layer even if one already exists?' - required: false - default: false - type: boolean - prune-keep-count: - description: 'How many existing dependency image layers to keep?' - required: false - default: 1 - type: number - pull_request: - types: - - closed - branches: - - main - -# queue cache runs -concurrency: - group: docker-apply-cache - cancel-in-progress: false - -jobs: - preflight: - name: "Preflight: PR or Manual Trigger?" - runs-on: ubuntu-latest - outputs: - do-apply: ${{ steps.check.outputs.merged_or_manual }} - steps: - - name: "Should we run cache application?" - id: check - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" || - ("${{ github.ref }}" == "refs/heads/main" && "${{ github.event.action }}" == "closed" && "${{ github.event.pull_request.merged }}" == "true") ]]; then - echo "merged_or_manual=true" >> $GITHUB_OUTPUT - else - echo "This was not a manual trigger and no PR was merged. No action taken." - echo "merged_or_manual=false" >> $GITHUB_OUTPUT - fi - shell: bash - - check-renv: - name: "Check If We Need {renv}" - runs-on: ubuntu-latest - needs: preflight - if: needs.preflight.outputs.do-apply == 'true' - outputs: - renv-needed: ${{ steps.check-for-renv.outputs.renv-needed }} - renv-cache-hashsum: ${{ steps.check-for-renv.outputs.renv-cache-hashsum }} - steps: - - name: "Check for renv" - id: check-for-renv - uses: carpentries/actions/renv-checks@v1 - with: - WORKBENCH_TAG: ${{ vars.WORKBENCH_TAG || 'latest' }} - skip-cache-check: true - - no-renv-cache-used: - name: "No renv package dependency image needed" - runs-on: ubuntu-latest - needs: check-renv - if: needs.check-renv.outputs.renv-needed != 'true' - steps: - - name: "No dependency image needed" - run: echo "No renv dependency image needed for this lesson" - - update-renv-cache: - name: "Publish renv package dependency image" - runs-on: ubuntu-latest - needs: check-renv - if: needs.check-renv.outputs.renv-needed == 'true' - permissions: - contents: read - packages: write - steps: - - uses: actions/checkout@v6 - - - name: "Get Container Version Used" - id: wb-vers - uses: carpentries/actions/container-version@v1 - with: - WORKBENCH_TAG: ${{ vars.WORKBENCH_TAG }} - renv-needed: ${{ needs.check-renv.outputs.renv-needed }} - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Log in to GHCR - uses: docker/login-action@v4 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Set dependency image tags - id: image - env: - IMAGE_OWNER: ${{ github.repository_owner }} - IMAGE_NAME: ${{ github.event.repository.name }} - WB_VERSION: ${{ steps.wb-vers.outputs.container-version }} - RENV_HASH: ${{ needs.check-renv.outputs.renv-cache-hashsum }} - run: | - set -euo pipefail - exact_image="ghcr.io/${IMAGE_OWNER}/${IMAGE_NAME}-deps:${WB_VERSION}_renv-${RENV_HASH}" - latest_image="ghcr.io/${IMAGE_OWNER}/${IMAGE_NAME}-deps:latest" - - # lowercaseify - echo "exact_image=${exact_image,,}" >> "$GITHUB_OUTPUT" - echo "latest_image=${latest_image,,}" >> "$GITHUB_OUTPUT" - shell: bash - - - name: Check for existing dependency image tag - id: image-exists - env: - EXACT_IMAGE: ${{ steps.image.outputs.exact_image }} - run: | - set -euo pipefail - if docker manifest inspect "${EXACT_IMAGE}" >/dev/null 2>&1; then - echo "exists=true" >> "$GITHUB_OUTPUT" - echo "## ⚠️ Dependency image already exists" >> $GITHUB_STEP_SUMMARY - echo "Dependency image already exists for this renv hash: ${EXACT_IMAGE}" >> $GITHUB_STEP_SUMMARY - echo "Dependency image already exists for this renv hash: ${EXACT_IMAGE}" - else - echo "exists=false" >> "$GITHUB_OUTPUT" - echo "No existing dependency image found for this renv hash: ${EXACT_IMAGE}" - fi - shell: bash - - - name: Build and push dependency image layer - id: build-push-deps-layer - if: | - steps.image-exists.outputs.exists != 'true' || - ( - github.event_name == 'workflow_dispatch' && - github.event.inputs.force-dependency-image-rebuild == 'true' - ) - uses: carpentries/actions/build-dependency-image@v1 - with: - workbench-tag: ${{ vars.WORKBENCH_TAG || 'latest' }} - github-token: ${{ secrets.GITHUB_TOKEN }} - github-repository: ${{ github.repository }} - github-sha: ${{ github.sha }} - exact-image: ${{ steps.image.outputs.exact_image }} - latest-image: ${{ steps.image.outputs.latest_image }} - build-context: ${{ github.workspace }} - - prune-dependency-images: - name: "Prune Dependency Images" - runs-on: ubuntu-latest - needs: check-renv - steps: - - name: Prune any old dependency image layers - uses: carpentries/actions/prune-dependency-images@v1 - if: needs.check-renv.outputs.renv-needed == 'true' - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - owner: ${{ github.repository_owner }} - owner-type: ${{ github.event.repository.owner.type }} - repository: ${{ github.event.repository.name }} - package-name: ${{ github.event.repository.name }}-deps - keep-count: ${{ github.event.inputs.prune-keep-count }} - continue-on-error: true - - record-cache-result: - name: "Record Caching Status" - runs-on: ubuntu-latest - needs: [check-renv, update-renv-cache] - if: always() - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - steps: - - name: "Record cache result" - run: | - echo "${{ needs.check-renv.outputs.renv-needed != 'true' || needs.update-renv-cache.result == 'success' }}" > ${{ github.workspace }}/apply-cache-result - shell: bash - - - name: "Upload cache result" - uses: actions/upload-artifact@v7 - with: - name: apply-cache-result - path: ${{ github.workspace }}/apply-cache-result