diff --git a/NAMESPACE b/NAMESPACE index 9ac88c19..f4b7767f 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -6,6 +6,7 @@ export(rix) export(with_nix) importFrom(codetools,checkUsage) importFrom(codetools,findGlobals) +export(tar_nix_ga) importFrom(httr,GET) importFrom(httr,content) importFrom(httr,stop_for_status) diff --git a/R/tar_nix_ga.R b/R/tar_nix_ga.R new file mode 100644 index 00000000..5972cbc2 --- /dev/null +++ b/R/tar_nix_ga.R @@ -0,0 +1,30 @@ +# WARNING - Generated by {fusen} from dev/cicd.Rmd: do not edit by hand + +#' tar_nix_ga Run a {targets} pipeline on Github Actions. +#' @details This function puts a `.yaml` file inside the `.github/workflows/` +#' folders on the root of your project. This workflow file will use the +#' projects `default.nix` file to generate the development environment on +#' Github Actions and will then run the projects {targets} pipeline. Make +#' sure to give read and write permissions to the Github Actions bot. +#' @return Nothing, copies file to a diretory. +#' @export +tar_nix_ga <- function(){ + # Add an empty .gitignore file if there isn’t any + + if(file.exists(".gitignore")){ + NULL + } else { + file.create(".gitignore") + } + + path <- ".github/workflows" + + dir.create(path, recursive = TRUE) + source <- system.file( + file.path("extdata", "run-pipeline.yaml"), + package = "rix", + mustWork = TRUE + ) + file.copy(source, path, overwrite = TRUE) + invisible() +} diff --git a/R/zzz.R b/R/zzz.R index 8b1be328..a5a9138b 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -1,7 +1,6 @@ # WARNING - Generated by {fusen} from dev/zzz.Rmd: do not edit by hand -#' zzz -#' -#' Global imports +#' zzz Global imports +#' @noRd #' @importFrom utils data utils::globalVariables(c("r_nix_revs")) diff --git a/README.Rmd b/README.Rmd index 311b4789..e6f47bb1 100644 --- a/README.Rmd +++ b/README.Rmd @@ -24,7 +24,7 @@ knitr::opts_chunk$set( -# Rix: Reproducible Environments with Nix +# Reproducible Environments with Nix ## Introduction @@ -70,7 +70,7 @@ install.packages("rix", repos = c("https://b-rodrigues.r-universe.dev", library("rix") ``` -You can try that everything works well by trying to built the Nix expression +You can check that everything works well by trying to build the Nix expression that ships with `{rix}`. Nix expressions are typically saved into files with the name `default.nix`. This expression installs the latest version of R and `{rix}` in a separate, reproducible environment: @@ -88,7 +88,7 @@ nix_build(project_path = ".") If everything worked well, you should see a file called `result` next to `default.nix`. You can now enter this newly built development environment by -starting opening a terminal in that folder and typing `nix-shell`. You should +opening a terminal in that folder and typing `nix-shell`. You should be immediately dropped into an interactive R session. If you don't have R installed, but have the Nix package manager installed, you @@ -135,14 +135,15 @@ The idea of `{rix}` is for you to declare the environment you need, using the provided `rix()` function, which in turn writes the required expression in a file for Nix to actually build that environment. You can then use this environment to either work interactively, or run R scripts. It is possible to -have as many environments as projects. Each environment is isolated (or not, -it's up to you). +have as many environments as projects. Each environment is isolated, but can +still interact with your system's files, unlike with Docker where a volume must +be mounted. The main function of `{rix}` is called `rix()`. `rix()` has several arguments: - the R version you need for your project - a list of R packages that your project needs -- an optional list of additional software (for example, a Python interpreter, or Quarto) +- an optional list of additional software (for example a Python interpreter, or Quarto) - an optional list with packages to install from Github - an optional list of LaTeX packages - whether you want to use RStudio as an IDE for your project (or VS Code, or another environment) @@ -159,16 +160,19 @@ rix(r_ver = "latest", The call above writes a `default.nix` file in the current working directory. This `default.nix` can in turn be used by Nix to build an environment containing RStudio, the latest version of R, and the latest versions of the `{dplyr}` and -`{chronicler}` packages. It should be noted that as of September 2023, RStudio -is not available for macOS through Nix so the expression generated by the call -above will not build successfully. It is also not possible to use RStudio +`{chronicler}` packages. It should be noted that as of January 2024, RStudio is +not available for macOS through Nix so the expression generated by the call +above will not build successfully on macOS and is not possible to use RStudio installed by other means with a Nix environment. This is because RStudio changes some default environment variables and a globally installed RStudio (the one you -install normally) would not recognize the R installed in the Nix environment. -This is not the case for other IDEs such as VS code or Emacs. Another example: +install normally) would not recognize the R version installed in the Nix +environment. This is not the case for other IDEs such as VS code or Emacs. +Another example: ```{r, eval = FALSE} -rix(r_ver = "4.2.2", r_pkgs = c("dplyr", "chronicler"), ide = "code") +rix(r_ver = "4.2.2", + r_pkgs = c("dplyr", "chronicler"), + ide = "code") ``` This call will generate a `default.nix` that installs R version 4.2.2, with the @@ -176,12 +180,24 @@ This call will generate a `default.nix` that installs R version 4.2.2, with the the `ide` argument was set to "code". This installs the required `{languageserver}` package as well, but unlike `ide = "rstudio"` does not install VS Code in that environment. Users should instead use the globally -installed VS Code by starting it from that environment. +installed VS Code by starting it from that environment. If you wish to also +install VS Code using Nix, you could change the above expression to this: + +```{r, eval = FALSE} +rix(r_ver = "4.2.2", + r_pkgs = c("dplyr", "chronicler"), + system_pkgs = "vscodium", + ide = "code") +``` + +or change "vscodium" to "vscode" if you prefer the MS branded version. It's also possible to install specific versions of packages: ```{r, eval = FALSE} -rix(r_ver = "latest", r_pkgs = c("dplyr@1.0.0"), ide = "code") +rix(r_ver = "latest", + r_pkgs = c("dplyr@1.0.0"), + ide = "code") ``` but usually it is better to build an environment using the version of R that was @@ -293,13 +309,13 @@ rix(r_ver = "latest", r_pkgs = c("dplyr", "ggplot2"), system_pkgs = NULL, git_pkgs = NULL, - ide = "rstudio", + ide = "other", project_path = ".", overwrite = TRUE) ``` to generate a `default.nix`, and then use that file to generate an environment -with R, Rstudio, `{dplyr}` and `{ggplot2}`. If you need to add packages for your +with R, `{dplyr}` and `{ggplot2}`. If you need to add packages for your project, rerun the command above, but add the needed packages to `r_pkgs`. ## Installing Nix @@ -333,11 +349,11 @@ wsl --shutdown # relaunch Ubuntu WSL2 ``` -Afterwards, you can install Nix like business as usual. You can proceed with -the Determinant Systems installer. If you cannot or have decided not to activate +Afterwards, you can install Nix like business as usual. You can proceed with the +Determinate Systems installer. If you cannot or have decided not to activate systemd, then you have to append `--init none` to the command. More details -about this you can find at -[The Determinante Nix Installer](https://github.com/DeterminateSystems/nix-installer). +about this you can find at [The Determinante Nix +Installer](https://github.com/DeterminateSystems/nix-installer). ### Installing Nix using the Determinate Systems installer diff --git a/README.md b/README.md index a20c4adc..7498e988 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -- [Rix: Reproducible Environments with - Nix](#rix-reproducible-environments-with-nix) +- [Reproducible Environments with + Nix](#reproducible-environments-with-nix) - [Introduction](#introduction) - [Returning users](#returning-users) - [The Nix package manager](#the-nix-package-manager) @@ -29,7 +29,7 @@ rix](https://b-rodrigues.r-universe.dev/badges/rix?scale=1&color=pink&style=roun -# Rix: Reproducible Environments with Nix +# Reproducible Environments with Nix ## Introduction @@ -78,7 +78,7 @@ install.packages("rix", repos = c("https://b-rodrigues.r-universe.dev", library("rix") ``` -You can try that everything works well by trying to built the Nix +You can check that everything works well by trying to build the Nix expression that ships with `{rix}`. Nix expressions are typically saved into files with the name `default.nix`. This expression installs the latest version of R and `{rix}` in a separate, reproducible environment: @@ -96,9 +96,8 @@ nix_build(project_path = ".") If everything worked well, you should see a file called `result` next to `default.nix`. You can now enter this newly built development -environment by starting opening a terminal in that folder and typing -`nix-shell`. You should be immediately dropped into an interactive R -session. +environment by opening a terminal in that folder and typing `nix-shell`. +You should be immediately dropped into an interactive R session. If you don’t have R installed, but have the Nix package manager installed, you can run a temporary R session with R using this command @@ -146,14 +145,15 @@ using the provided `rix()` function, which in turn writes the required expression in a file for Nix to actually build that environment. You can then use this environment to either work interactively, or run R scripts. It is possible to have as many environments as projects. Each -environment is isolated (or not, it’s up to you). +environment is isolated, but can still interact with your system’s +files, unlike with Docker where a volume must be mounted. The main function of `{rix}` is called `rix()`. `rix()` has several arguments: - the R version you need for your project - a list of R packages that your project needs -- an optional list of additional software (for example, a Python +- an optional list of additional software (for example a Python interpreter, or Quarto) - an optional list with packages to install from Github - an optional list of LaTeX packages @@ -173,17 +173,19 @@ The call above writes a `default.nix` file in the current working directory. This `default.nix` can in turn be used by Nix to build an environment containing RStudio, the latest version of R, and the latest versions of the `{dplyr}` and `{chronicler}` packages. It should be -noted that as of September 2023, RStudio is not available for macOS +noted that as of January 2024, RStudio is not available for macOS through Nix so the expression generated by the call above will not build -successfully. It is also not possible to use RStudio installed by other -means with a Nix environment. This is because RStudio changes some +successfully on macOS and is not possible to use RStudio installed by +other means with a Nix environment. This is because RStudio changes some default environment variables and a globally installed RStudio (the one -you install normally) would not recognize the R installed in the Nix -environment. This is not the case for other IDEs such as VS code or +you install normally) would not recognize the R version installed in the +Nix environment. This is not the case for other IDEs such as VS code or Emacs. Another example: ``` r -rix(r_ver = "4.2.2", r_pkgs = c("dplyr", "chronicler"), ide = "code") +rix(r_ver = "4.2.2", + r_pkgs = c("dplyr", "chronicler"), + ide = "code") ``` This call will generate a `default.nix` that installs R version 4.2.2, @@ -192,12 +194,24 @@ to use VS Code, the `ide` argument was set to “code”. This installs the required `{languageserver}` package as well, but unlike `ide = "rstudio"` does not install VS Code in that environment. Users should instead use the globally installed VS Code by starting it from -that environment. +that environment. If you wish to also install VS Code using Nix, you +could change the above expression to this: + +``` r +rix(r_ver = "4.2.2", + r_pkgs = c("dplyr", "chronicler"), + system_pkgs = "vscodium", + ide = "code") +``` + +or change “vscodium” to “vscode” if you prefer the MS branded version. It’s also possible to install specific versions of packages: ``` r -rix(r_ver = "latest", r_pkgs = c("dplyr@1.0.0"), ide = "code") +rix(r_ver = "latest", + r_pkgs = c("dplyr@1.0.0"), + ide = "code") ``` but usually it is better to build an environment using the version of R @@ -302,14 +316,14 @@ now run something like this: r_pkgs = c("dplyr", "ggplot2"), system_pkgs = NULL, git_pkgs = NULL, - ide = "rstudio", + ide = "other", project_path = ".", overwrite = TRUE) to generate a `default.nix`, and then use that file to generate an -environment with R, Rstudio, `{dplyr}` and `{ggplot2}`. If you need to -add packages for your project, rerun the command above, but add the -needed packages to `r_pkgs`. +environment with R, `{dplyr}` and `{ggplot2}`. If you need to add +packages for your project, rerun the command above, but add the needed +packages to `r_pkgs`. ## Installing Nix @@ -342,7 +356,7 @@ wsl --shutdown ``` Afterwards, you can install Nix like business as usual. You can proceed -with the Determinant Systems installer. If you cannot or have decided +with the Determinate Systems installer. If you cannot or have decided not to activate systemd, then you have to append `--init none` to the command. More details about this you can find at [The Determinante Nix Installer](https://github.com/DeterminateSystems/nix-installer). diff --git a/dev/0-dev_history.Rmd b/dev/0-dev_history.Rmd index 4c9017e8..d0fbe247 100755 --- a/dev/0-dev_history.Rmd +++ b/dev/0-dev_history.Rmd @@ -97,6 +97,12 @@ fusen::inflate(flat_file = "dev/build_envs.Rmd", overwrite = TRUE) ``` +```{r} +fusen::inflate(flat_file = "dev/cicd.Rmd", + vignette_name = NA, + overwrite = TRUE) +``` + ```{r} fusen::inflate(flat_file = "dev/zzz.Rmd", diff --git a/dev/cicd.Rmd b/dev/cicd.Rmd new file mode 100644 index 00000000..310d53c8 --- /dev/null +++ b/dev/cicd.Rmd @@ -0,0 +1,55 @@ +--- +title: "Functions for Github Actions CI/CD service" +output: html_document +editor_options: + chunk_output_type: console +--- + +```{r development, include=FALSE} +library(testthat) +``` + + + +```{r development-load} +# Load already included functions if relevant +pkgload::load_all(export_all = FALSE) +``` + +The function below copies a Github actions workflow file into the +`.github/workflows/run-pipeline.yaml`: + +```{r function-tar_nix_ga} +#' tar_nix_ga Run a {targets} pipeline on Github Actions. +#' @details This function puts a `.yaml` file inside the `.github/workflows/` +#' folders on the root of your project. This workflow file will use the +#' projects `default.nix` file to generate the development environment on +#' Github Actions and will then run the projects {targets} pipeline. Make +#' sure to give read and write permissions to the Github Actions bot. +#' @return Nothing, copies file to a diretory. +#' @export +tar_nix_ga <- function(){ + # Add an empty .gitignore file if there isn’t any + + if(file.exists(".gitignore")){ + NULL + } else { + file.create(".gitignore") + } + + path <- ".github/workflows" + + dir.create(path, recursive = TRUE) + source <- system.file( + file.path("extdata", "run-pipeline.yaml"), + package = "rix", + mustWork = TRUE + ) + file.copy(source, path, overwrite = TRUE) + invisible() +} +``` + +Be sure to give Github Actions workflows read and write permissions. diff --git a/dev/config_fusen.yaml b/dev/config_fusen.yaml index 19f3c608..c60279b9 100644 --- a/dev/config_fusen.yaml +++ b/dev/config_fusen.yaml @@ -24,6 +24,19 @@ building_envs_with_rix.Rmd: check: true document: true overwrite: 'yes' +cicd.Rmd: + path: dev/cicd.Rmd + state: active + R: R/tar_nix_ga.R + tests: [] + vignettes: [] + inflate: + flat_file: dev/cicd.Rmd + vignette_name: .na + open_vignette: true + check: true + document: true + overwrite: 'yes' cran_archive.Rmd: path: dev/cran_archive.Rmd state: active @@ -139,5 +152,5 @@ zzz.Rmd: vignette_name: .na open_vignette: true check: true - document: true + document: false overwrite: 'yes' diff --git a/dev/zzz.Rmd b/dev/zzz.Rmd index 2998fc7d..2649e743 100644 --- a/dev/zzz.Rmd +++ b/dev/zzz.Rmd @@ -8,9 +8,8 @@ editor_options: ## zzz ```{r function-zzz, eval = F} -#' zzz -#' -#' Global imports +#' zzz Global imports +#' @noRd #' @importFrom utils data utils::globalVariables(c("r_nix_revs")) ``` diff --git a/inst/extdata/run-pipeline.yaml b/inst/extdata/run-pipeline.yaml new file mode 100644 index 00000000..35e57f1c --- /dev/null +++ b/inst/extdata/run-pipeline.yaml @@ -0,0 +1,117 @@ +# Inspired by the template in the {targets} package +# https://github.com/ropensci/targets/blob/3b16f37ba5cdca710adbb81c2301f6b1d7432cfb/inst/templates/github_actions.yaml + +# This file is licensed under the MIT +# Copyright © 2023 Bruno Rodrigues and Philipp Baumann +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +name: run-pipeline + +on: + push: + branches: + - main + - master + +jobs: + targets: + runs-on: ubuntu-latest + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + steps: + + - uses: actions/checkout@v3 + + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@main + with: + logger: pretty + log-directives: nix_installer=trace + backtrace: full + + - name: Nix cache + uses: DeterminateSystems/magic-nix-cache-action@main + + - name: Build development environment + run: | + nix-build + + - name: Check if previous runs exists + id: runs-exist + run: git ls-remote --exit-code --heads origin targets-runs + continue-on-error: true + + - name: Checkout previous run + if: steps.runs-exist.outcome == 'success' + uses: actions/checkout@v2 + with: + ref: targets-runs + fetch-depth: 1 + path: .targets-runs + + - name: Restore output files from the previous run + if: steps.runs-exist.outcome == 'success' + run: | + nix-shell default.nix --run "Rscript -e 'for (dest in scan(\".targets-runs/.targets-files\", what = character())) { + source <- file.path(\".targets-runs\", dest) + if (!file.exists(dirname(dest))) dir.create(dirname(dest), recursive = TRUE) + if (file.exists(source)) file.rename(source, dest) + }'" + + - name: Run model + run: | + nix-shell default.nix --run "Rscript -e 'targets::tar_make()'" + + - name: Identify files that the targets pipeline produced + run: git ls-files -mo --exclude=renv > .targets-files + + - name: Create the runs branch if it does not already exist + if: steps.runs-exist.outcome != 'success' + run: git checkout --orphan targets-runs + + - name: Put the worktree in the runs branch if the latter already exists + if: steps.runs-exist.outcome == 'success' + run: | + rm -r .git + mv .targets-runs/.git . + rm -r .targets-runs + + - name: Upload latest run + run: | + git config --local user.name "GitHub Actions" + git config --local user.email "actions@github.com" + rm -r .gitignore .github/workflows + git add --all -- ':!renv' + for file in $(git ls-files -mo --exclude=renv) + do + git add --force $file + done + git commit -am "Run pipeline" + git push origin targets-runs + + - name: Prepare failure artifact + if: failure() + run: rm -rf .git .github .targets-files .targets-runs + + - name: Post failure artifact + if: failure() + uses: actions/upload-artifact@main + with: + name: ${{ runner.os }}-r${{ matrix.config.r }}-results + path: . diff --git a/man/figures/README-pressure-1.png b/man/figures/README-pressure-1.png deleted file mode 100644 index b1318d48..00000000 Binary files a/man/figures/README-pressure-1.png and /dev/null differ diff --git a/man/tar_nix_ga.Rd b/man/tar_nix_ga.Rd new file mode 100644 index 00000000..da246a54 --- /dev/null +++ b/man/tar_nix_ga.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/tar_nix_ga.R +\name{tar_nix_ga} +\alias{tar_nix_ga} +\title{tar_nix_ga Run a {targets} pipeline on Github Actions.} +\usage{ +tar_nix_ga() +} +\value{ +Nothing, copies file to a diretory. +} +\description{ +tar_nix_ga Run a {targets} pipeline on Github Actions. +} +\details{ +This function puts a \code{.yaml} file inside the \verb{.github/workflows/} +folders on the root of your project. This workflow file will use the +projects \code{default.nix} file to generate the development environment on +Github Actions and will then run the projects {targets} pipeline. Make +sure to give read and write permissions to the Github Actions bot. +}