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:
125 |
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
126 |
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.
One function of the workbch package is to make navigation a little easier: job_open() allows you to switch between jobs, and job_openurl() opens a URL linked to the job in a browser window. The screencast below illustrates this:
100 |
101 |
102 |
103 |
104 | Git report
105 |
A second function of workbch is to keep track of the git status of various projects. A common workflow problem (for me, at least) is that I sometimes forget to commit changes or push them upstream, and then forget which projects I’ve left in this “unclean” state. The job_gitreport() function aims to make this easier by checking the git status for all jobs, and reporting those jobs that are not in a clean state. For example:
A third function of the workbch package is keeping track of job locations when they move around on the local machine, as long as they stay somewhere on the workbch search path (i.e., the “workbch.search” option). It does this by matching information stored in the “.workbch” sentinel file to entries in the “workbch_jobs.json” file. There are two functions that are useful for this:
120 |
121 |
122 | job_list() throws a warning if a job folder has moved
123 |
124 | job_seek() will ask if you want to update the location
125 |
126 |
This is illustrated in the screencast below:
127 |
128 |
129 |
130 |
131 | Modifying jobs
132 |
A common task is to update the information associated with a job. The priority may change, it may be assigned a new owner or acquire a new URL, etc. The job_modify() function can be used for this, as illustrated below:
should clean repositories be included in the output?
140 |
141 |
142 |
143 |
Value
144 |
145 |
A tibble with columns jobname, staged, unstaged,
146 | untracked, ahead and behind. The jobname column is
147 | a character vector, all others are integer valued.
148 |
149 |
Details
150 |
151 |
The role of the git_report() function is to provide an overview
152 | of the status of all workbch jobs that are associated with a git repository.
153 | For every job, it uses git2r::in_repository to determine if the job
154 | folder (i.e., the path for that job) is in a git repository. Jobs that are
155 | not in git repositories are ignored.
156 |
For jobs that are associated with git repositories, the git_report()
157 | function calls git2r::status() to determine the git status. If there is an
158 | upstream set (i.e., git2r::branch_get_upstream() detects an upstream
159 | repository), it will also call git2r::ahead_behind() to determine how many
160 | commits the local repository is ahead and/or behind of the upstream.
161 |
By default, no output is shown for clean repositories (show_clean = FALSE).
162 | A repository is deemed to be clean if there are no staged, unstaged or
163 | untracked files and it is neither ahead nor behind the upstream repository.
164 | If the user specifies show_clean = TRUE, then results are reported for every
165 | job that is linked to a git repository.
Name of the job to show (defaults to the current job)
140 |
141 |
142 |
143 |
Value
144 |
145 |
Invisibly returns the job as a list
146 |
147 |
Details
148 |
149 |
The job_glimpse() function displays parameter values for the
150 | job specified in the jobname argument. If no argument is specified
151 | job_glimpse() will attempt to guess the "current" job by looking at
152 | any open RStudio projects. If no project is open (or the RStudio API is not
153 | available) it attempts to guess by looking at the working directory. The
154 | output is presented to the user as a message.
The job_home() function returns the file path for `jobname`.
150 | This can be useful if you need to specify the location of files relative to
151 | a project.
152 |
If no argument is specified job_home() will attempt to guess the
153 | current job by looking at any open RStudio projects. If no project is open
154 | or the RStudio API is not available it attempts to guess by looking at the
155 | working directory.
An object of class worbch_tbl. It is regular tibble with a slightly
151 | modified print method that ensures all rows are printed in the output
152 |
153 |
Details
154 |
155 |
The job_list() function is used to display a summary of the
156 | jobs known to workbch, shown as a tibble with one row per job. By default
157 | only those jobs with a priority value of 1 or 2 will be shown, and
158 | only if their status is "active" or "inactive". Jobs that do not have
159 | sufficient priority or whose status is "complete", "abandoned" or "masked"
160 | are not shown.
161 |
The default behaviour can be overridden by specifying a search string (or
162 | object that can be coerced to a string). If the user specifies a value to
163 | search then job_list() attempts to match the search string with a parameter
164 | value. For instance job_list("active") will return all jobs that have status
165 | active and job_list(1) will return all jobs that have priority 1. At
166 | present this functionality requires that the search string be an exact value
167 | (e.g., search = "Dani" would not match a job owned by "Danielle"),
168 | though this may be extended in the future.
169 |
The output is returned to the user as a tibble, and by default the columns
170 | displayed are jobname, owner, priority, status,
171 | and description. The user can directly specify which columns to be
172 | included using the select argument, which should be a character vector
173 | specifying the names of the columns to include. In addition to the five
174 | columns made available by default, the output can include the path,
175 | tags and urls associated with the job. For convenience, if you
176 | set select = NULL then all columns will be returned.
The job_open() function opens a workbch job. The meaning of
146 | "open" here depends on context. If there is an RStudio project linked to the
147 | job and the RStudio API is available, then job_open() will switch the
148 | to the RStudio project that jobname is linked to. If this is not
149 | possible an there is a path associated with the job, then job_open()
150 | will change the working directory to that path. If neither option is possible
151 | then this function does nothing.
152 |
Note that when working interactively, job_open() can be called without
153 | specfying the jobname. In this case the user will be presented with
154 | prompts to select the desired job.
The job_openurl() function opens a URL associated with a
150 | job in a browser window. The site argument is the site nickname
151 | (e.g. "github", "homepage", etc) and the jobname argument specifies
152 | the job to use.
153 |
If no argument is specified job_openurl() will attempt to guess the
154 | current job by looking at any open RStudio projects. If no project is open
155 | or the RStudio API is not available it attempts to guess by looking at the
156 | working directory.
The job_seek() searches the folders listed in dirs
172 | to find possible candidates that could be added as workbch jobs, or to
173 | recover the location of any such jobs that may have moved. When candidate
174 | folders are found, the user is presented with prompts asking if they would
175 | like to add the folder as a workbch job (or pair it with an existing job
176 | if a match is discovered).
177 |
The search process uses a heuristic to discover possible jobs. A folder
178 | is considered a possible candidate if it has a .Rproj file, a
179 | .workbch file, or a git repository. If nesting = FALSE (the
180 | default), a directory that is contained within another directory that meets
181 | one of these criteria is not considered a candidate.
182 |
As much as possible the job_seek() function attempts to guess values
183 | for the various parameters. For instance, if there is a git repository that
184 | has an upstream remote (on gitbub, bitbucket or gitlab), it attempts to guess
185 | an appropriate URL for the remote. Similarly, if there is a .workbch
186 | sentinel file, it uses the contents of the file to try to match the folder
187 | against a known job and takes the jobname from the sentinel file. Otherwise
188 | it guesses a default value using the folder name.
189 | For parameter values that cannot be guessed from the folder itself, default
190 | values are specified using the owner, priority, status
191 | and tags arguments.
192 |
Regardless of the values guessed, the user is prompted either to confirm
193 | the guessed value (by hitting enter) or overriding the guess by supplying
194 | the value manually.
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
--------------------------------------------------------------------------------
/man/job_create.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/job_create.R
3 | \name{job_create}
4 | \alias{job_create}
5 | \title{Create a new job}
6 | \usage{
7 | job_create(jobname = NULL, description = NULL, owner = NULL,
8 | status = NULL, priority = NULL, tags = NULL, path = NULL)
9 | }
10 | \arguments{
11 | \item{jobname}{name of the job to create}
12 |
13 | \item{description}{brief description of the job}
14 |
15 | \item{owner}{should be a name or a nickname}
16 |
17 | \item{status}{should be "active", "inactive", "complete", "abandoned", "masked"}
18 |
19 | \item{priority}{numeric}
20 |
21 | \item{tags}{a string containing comma separated list of tags}
22 |
23 | \item{path}{path to the job home directory}
24 | }
25 | \value{
26 | Invisibly returns a list containing the parameters for the job
27 | }
28 | \description{
29 | Create a new job
30 | }
31 | \details{
32 | The role of the \code{job_create()} function is to create new workbch job.
33 | It can be called in two ways, interactively or programmatically. To call the
34 | function interactively, R must be in interactive mode and the function should
35 | be called with no arguments specified. When called in this fashion the user
36 | will be presented with a sequence of prompts, asking them to specify each
37 | of the parameters that define a job (e.g., a character string for \code{jobname},
38 | a number for \code{priority}). When used interactively, you do not need to include
39 | quote marks when entering a string: \code{job_create()} will coerce the input to
40 | the appropriate format, and then append the created job to the job file.
41 |
42 | When called programmatically, the user must specify the arguments in the
43 | call to \code{job_create()}. The \code{jobname}, \code{description} and
44 | \code{owner} arguments should be character strings of length 1, and all three
45 | are mandatory. The \code{status} for a job should be one of the following
46 | values: \code{"active"}, \code{"inactive"}, \code{"complete"}, \code{"abandoned"}
47 | or \code{"masked"}. The \code{priority} for a job should be a positive integer:
48 | the intent is that priority 1 is the highest priority, followed by priority 2,
49 | and so one. The \code{tags} for a job can be specified as a single string, using
50 | \code{|} as a separator character (e.g., \code{tags = "research | statistics"}
51 | would create two tags for the job). Finally, the \code{path} should specify the
52 | location of a folder containing the project files.
53 |
54 | For non-mandatory arguments, if the user does not specify a value, the
55 | \code{job_create()} function applies the following defaults: \code{priority = 1},
56 | \code{status = "active"}, \code{tags = character(0)} and \code{path = NA}`.
57 |
58 | Note that, although jobs can also be associated with URLs (e.g., link to a
59 | GitHub repository or a document on Overleaf), the \code{job_create()} function
60 | does not (at this time) allow you to specify URLs. These can be added using
61 | \code{job_modify()}.
62 | }
63 |
--------------------------------------------------------------------------------
/man/job_gitreport.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/job_gitreport.R
3 | \name{job_gitreport}
4 | \alias{job_gitreport}
5 | \title{Report the git status of all jobs}
6 | \usage{
7 | job_gitreport(show_clean = FALSE)
8 | }
9 | \arguments{
10 | \item{show_clean}{should clean repositories be included in the output?}
11 | }
12 | \value{
13 | A tibble with columns \code{jobname}, \code{staged}, \code{unstaged},
14 | \code{untracked}, \code{ahead} and \code{behind}. The \code{jobname} column is
15 | a character vector, all others are integer valued.
16 | }
17 | \description{
18 | Report the git status of all jobs
19 | }
20 | \details{
21 | The role of the \code{git_report()} function is to provide an overview
22 | of the status of all workbch jobs that are associated with a git repository.
23 | For every job, it uses \code{git2r::in_repository} to determine if the job
24 | folder (i.e., the \code{path} for that job) is in a git repository. Jobs that are
25 | not in git repositories are ignored.
26 |
27 | For jobs that are associated with git repositories, the \code{git_report()}
28 | function calls \code{git2r::status()} to determine the git status. If there is an
29 | upstream set (i.e., \code{git2r::branch_get_upstream()} detects an upstream
30 | repository), it will also call \code{git2r::ahead_behind()} to determine how many
31 | commits the local repository is ahead and/or behind of the upstream.
32 |
33 | By default, no output is shown for clean repositories (\code{show_clean = FALSE}).
34 | A repository is deemed to be clean if there are no staged, unstaged or
35 | untracked files and it is neither ahead nor behind the upstream repository.
36 | If the user specifies \code{show_clean = TRUE}, then results are reported for every
37 | job that is linked to a git repository.
38 | }
39 |
--------------------------------------------------------------------------------
/man/job_glimpse.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/job_glimpse.R
3 | \name{job_glimpse}
4 | \alias{job_glimpse}
5 | \title{View the information stored about a job}
6 | \usage{
7 | job_glimpse(jobname = NULL)
8 | }
9 | \arguments{
10 | \item{jobname}{Name of the job to show (defaults to the current job)}
11 | }
12 | \value{
13 | Invisibly returns the job as a list
14 | }
15 | \description{
16 | View the information stored about a job
17 | }
18 | \details{
19 | The \code{job_glimpse()} function displays parameter values for the
20 | job specified in the \code{jobname} argument. If no argument is specified
21 | \code{job_glimpse()} will attempt to guess the "current" job by looking at
22 | any open RStudio projects. If no project is open (or the RStudio API is not
23 | available) it attempts to guess by looking at the working directory. The
24 | output is presented to the user as a message.
25 | }
26 |
--------------------------------------------------------------------------------
/man/job_home.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/job_home.R
3 | \name{job_home}
4 | \alias{job_home}
5 | \title{Path to the job home}
6 | \usage{
7 | job_home(jobname = NULL)
8 | }
9 | \arguments{
10 | \item{jobname}{Name of job (defaults to current job)}
11 | }
12 | \value{
13 | Path to the job folder as a character string
14 | }
15 | \description{
16 | Path to the job home
17 | }
18 | \details{
19 | The \code{job_home()} function returns the file path for `jobname`.
20 | This can be useful if you need to specify the location of files relative to
21 | a project.
22 |
23 | If no argument is specified \code{job_home()} will attempt to guess the
24 | current job by looking at any open RStudio projects. If no project is open
25 | or the RStudio API is not available it attempts to guess by looking at the
26 | working directory.
27 | }
28 |
--------------------------------------------------------------------------------
/man/job_list.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/job_list.R
3 | \name{job_list}
4 | \alias{job_list}
5 | \title{View a list of all jobs}
6 | \usage{
7 | job_list(search = NULL, select = c("jobname", "owner", "priority",
8 | "status", "description"))
9 | }
10 | \arguments{
11 | \item{search}{input query used to extract a subset of jobs}
12 |
13 | \item{select}{character vector of columns to return}
14 | }
15 | \value{
16 | An object of class worbch_tbl. It is regular tibble with a slightly
17 | modified print method that ensures all rows are printed in the output
18 | }
19 | \description{
20 | View a list of all jobs
21 | }
22 | \details{
23 | The \code{job_list()} function is used to display a summary of the
24 | jobs known to workbch, shown as a tibble with one row per job. By default
25 | only those jobs with a \code{priority} value of 1 or 2 will be shown, and
26 | only if their \code{status} is "active" or "inactive". Jobs that do not have
27 | sufficient priority or whose status is "complete", "abandoned" or "masked"
28 | are not shown.
29 |
30 | The default behaviour can be overridden by specifying a \code{search} string (or
31 | object that can be coerced to a string). If the user specifies a value to
32 | \code{search} then \code{job_list()} attempts to match the search string with a parameter
33 | value. For instance \code{job_list("active")} will return all jobs that have status
34 | \code{active} and \code{job_list(1)} will return all jobs that have priority 1. At
35 | present this functionality requires that the \code{search} string be an exact value
36 | (e.g., \code{search = "Dani"} would not match a job owned by \code{"Danielle"}),
37 | though this may be extended in the future.
38 |
39 | The output is returned to the user as a tibble, and by default the columns
40 | displayed are \code{jobname}, \code{owner}, \code{priority}, \code{status},
41 | and \code{description}. The user can directly specify which columns to be
42 | included using the \code{select} argument, which should be a character vector
43 | specifying the names of the columns to include. In addition to the five
44 | columns made available by default, the output can include the \code{path},
45 | \code{tags} and \code{urls} associated with the job. For convenience, if you
46 | set \code{select = NULL} then all columns will be returned.
47 | }
48 |
--------------------------------------------------------------------------------
/man/job_modify.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/job_modify.R
3 | \name{job_modify}
4 | \alias{job_modify}
5 | \title{Modify the properties of a job}
6 | \usage{
7 | job_modify(jobname = NULL, newname = NULL, description = NULL,
8 | owner = NULL, status = NULL, priority = NULL, path = NULL,
9 | tags = NULL, url = NULL, delete = FALSE)
10 | }
11 | \arguments{
12 | \item{jobname}{the current name for the job}
13 |
14 | \item{newname}{the new name}
15 |
16 | \item{description}{the new description}
17 |
18 | \item{owner}{nick name for the new owner}
19 |
20 | \item{status}{the new status}
21 |
22 | \item{priority}{the new priority}
23 |
24 | \item{path}{the new path to the job folder}
25 |
26 | \item{tags}{string with tags (uses | as separator)}
27 |
28 | \item{url}{string specifying url}
29 |
30 | \item{delete}{should this job be deleted (default = FALSE)}
31 | }
32 | \description{
33 | Modify the properties of a job
34 | }
35 | \details{
36 | The role of the \code{job_modify()} function is to change one or more
37 | parameters of an existing workbch job. It can be called in two ways, interactively
38 | or programmatically. To call the function interactively, R must be in interactive
39 | mode and the function should be called specifying either the \code{jobname} argument
40 | only, or no arguments specified. If no \code{jobname} is specified the
41 | \code{job_modify()} function will attempt to guess the
42 | current job by looking at any open RStudio projects. If no project is open
43 | or the RStudio API is not available it attempts to guess by looking at the
44 | working directory
45 |
46 | When called interactiely, the user
47 | will be presented with a sequence of prompts, asking them to specify each
48 | of the parameters that define a job (e.g., a character string for \code{descripton},
49 | a number for \code{priority}). When used interactively, you do not need to include
50 | quote marks when entering a string: \code{job_modify()} will coerce the input to
51 | the appropriate format, and then append the created job to the job file.
52 |
53 | When called programmatically, the user must specify the arguments in the
54 | call to \code{job_modify()}. Onlt the \code{jobname} argument is mandatory.
55 | To rename an existing job the \code{newname} argument should be specified.
56 | To modify \code{description}, \code{owner}, \code{status}, \code{priority},
57 | \code{path}, \code{tags} or \code{urls} the relevant argument shoul be
58 | specified.
59 |
60 | The \code{status} of a job should be \code{"active"}, \code{"inactive"},
61 | \code{"complete"}, \code{"abandoned"} or \code{"masked"}. The \code{priority} for
62 | a job should be a positive integer: the intent is that priority 1 is the highest
63 | priority, followed by priority 2, and so one. The \code{tags} for a job can be
64 | specified as a single string, using \code{|} as a separator character (e.g.,
65 | \code{tags = "research | statistics"} would create two tags for the job).
66 | The \code{path} should specify the location of a folder containing the project
67 | files. The format for \code{urls} is the same as for tags. For example to
68 | specify a GitHub link one might write \code{urls = "github \
69 | https://github.com/djnavarro/workbch"}. Multiple URLs can be specified by
70 | extending this syntax using \code{|} as the separator. For example:
71 | \code{urls = "github \ https://github.com/djnavarro/workbch | docs |
72 | https://djnavarro.github.io/workbch"}.
73 |
74 | Setting \code{delete = TRUE} will delete the job.
75 | }
76 |
--------------------------------------------------------------------------------
/man/job_open.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/job_open.R
3 | \name{job_open}
4 | \alias{job_open}
5 | \title{Navigate to a job}
6 | \usage{
7 | job_open(jobname = NULL)
8 | }
9 | \arguments{
10 | \item{jobname}{name of job to open}
11 | }
12 | \description{
13 | Navigate to a job
14 | }
15 | \details{
16 | The \code{job_open()} function opens a workbch job. The meaning of
17 | "open" here depends on context. If there is an RStudio project linked to the
18 | job and the RStudio API is available, then \code{job_open()} will switch the
19 | to the RStudio project that \code{jobname} is linked to. If this is not
20 | possible an there is a path associated with the job, then \code{job_open()}
21 | will change the working directory to that path. If neither option is possible
22 | then this function does nothing.
23 |
24 | Note that when working interactively, \code{job_open()} can be called without
25 | specfying the \code{jobname}. In this case the user will be presented with
26 | prompts to select the desired job.
27 | }
28 |
--------------------------------------------------------------------------------
/man/job_openurl.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/job_openurl.R
3 | \name{job_openurl}
4 | \alias{job_openurl}
5 | \title{Navigate to a URL associated with a job}
6 | \usage{
7 | job_openurl(site, jobname = NULL)
8 | }
9 | \arguments{
10 | \item{site}{label denoting the site (e.g., "github")}
11 |
12 | \item{jobname}{name of the job}
13 | }
14 | \description{
15 | Navigate to a URL associated with a job
16 | }
17 | \details{
18 | The \code{job_openurl()} function opens a URL associated with a
19 | job in a browser window. The \code{site} argument is the site nickname
20 | (e.g. "github", "homepage", etc) and the \code{jobname} argument specifies
21 | the job to use.
22 |
23 | If no argument is specified \code{job_openurl()} will attempt to guess the
24 | current job by looking at any open RStudio projects. If no project is open
25 | or the RStudio API is not available it attempts to guess by looking at the
26 | working directory.
27 | }
28 |
--------------------------------------------------------------------------------
/man/job_seek.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/job_seek.R
3 | \name{job_seek}
4 | \alias{job_seek}
5 | \title{Scans for jobs}
6 | \usage{
7 | job_seek(dirs = getOption("workbch.search"), seek = c("workbch", "git",
8 | "Rproj"), nesting = FALSE, owner = "", priority = 1,
9 | status = "active", tags = character(0))
10 | }
11 | \arguments{
12 | \item{dirs}{directories to scan}
13 |
14 | \item{seek}{search criterion}
15 |
16 | \item{nesting}{allow nested jobs (default = FALSE)}
17 |
18 | \item{owner}{default owner for a created job}
19 |
20 | \item{priority}{default priority for a created job}
21 |
22 | \item{status}{default status for a created job}
23 |
24 | \item{tags}{default tags for a created job}
25 | }
26 | \description{
27 | Scans for jobs
28 | }
29 | \details{
30 | The \code{job_seek()} searches the folders listed in \code{dirs}
31 | to find possible candidates that could be added as workbch jobs, or to
32 | recover the location of any such jobs that may have moved. When candidate
33 | folders are found, the user is presented with prompts asking if they would
34 | like to add the folder as a workbch job (or pair it with an existing job
35 | if a match is discovered).
36 |
37 | The search process uses a heuristic to discover possible jobs. A folder
38 | is considered a possible candidate if it has a \code{.Rproj} file, a
39 | \code{.workbch} file, or a git repository. If \code{nesting = FALSE} (the
40 | default), a directory that is contained within another directory that meets
41 | one of these criteria is not considered a candidate.
42 |
43 | As much as possible the \code{job_seek()} function attempts to guess values
44 | for the various parameters. For instance, if there is a git repository that
45 | has an upstream remote (on gitbub, bitbucket or gitlab), it attempts to guess
46 | an appropriate URL for the remote. Similarly, if there is a \code{.workbch}
47 | sentinel file, it uses the contents of the file to try to match the folder
48 | against a known job and takes the jobname from the sentinel file. Otherwise
49 | it guesses a default value using the folder name.
50 | For parameter values that cannot be guessed from the folder itself, default
51 | values are specified using the \code{owner}, \code{priority}, \code{status}
52 | and \code{tags} arguments.
53 |
54 | Regardless of the values guessed, the user is prompted either to confirm
55 | the guessed value (by hitting enter) or overriding the guess by supplying
56 | the value manually.
57 | }
58 |
--------------------------------------------------------------------------------
/tests/testthat.R:
--------------------------------------------------------------------------------
1 | library(testthat)
2 | library(workbch)
3 |
4 | wbh <- getOption("workbch.home")
5 |
6 | test_check("workbch")
7 |
8 | options(workbch.home = wbh)
9 |
10 |
--------------------------------------------------------------------------------
/tests/testthat/test-job_create.R:
--------------------------------------------------------------------------------
1 |
2 | # set up
3 | loc <- tempdir()
4 | options(workbch.home = loc)
5 |
6 | # delete the job file if for some reason it exists
7 | if(file.exists(job_file())) {
8 | file.remove(job_file())
9 | }
10 |
11 | # create path
12 | jobdir <- file.path(loc, "hitmebaby")
13 | jobdir2 <- file.path(loc, "slave4u")
14 | if(!dir.exists(jobdir)) dir.create(jobdir)
15 | sentinel <- file.path(jobdir, ".workbch")
16 |
17 | test_that("job_create works", {
18 |
19 | # create the job manually, no sentinel file, write nothing
20 | jobs <- list()
21 | jobs[["hitmebaby"]] <- new_job(
22 | jobname = "hitmebaby",
23 | description = "a song",
24 | owner = "britney",
25 | path = jobdir,
26 | sentinel = FALSE
27 | )
28 |
29 | expect_false(file.exists(sentinel))
30 | expect_false(file.exists(job_file()))
31 |
32 | # create the job
33 | job_create(
34 | jobname = "hitmebaby",
35 | description = "a song",
36 | owner = "britney",
37 | path = jobdir
38 | )
39 |
40 | expect_true(file.exists(sentinel))
41 | expect_true(file.exists(job_file()))
42 |
43 | # read the job file
44 | jobs2 <- job_read()
45 | jobs[["hitmebaby"]]$idstring <- jobs2[["hitmebaby"]]$idstring
46 |
47 | # expect equal in every respect except idstring
48 | expect_equal(jobs, jobs2)
49 |
50 | # expect errors when given insufficent input
51 | expect_error(job_create())
52 | expect_error(job_create("hitmebaby"))
53 | expect_error(job_create("toxic"))
54 | expect_error(job_create("toxic", "a song"))
55 |
56 | # expect success when given minimal input and maximal input
57 | expect_silent(job_create("toxic", "a song", "britney"))
58 | expect_silent(
59 | job_create(
60 | jobname = "slave4u",
61 | description = "another song",
62 | owner = "britney",
63 | status = "active",
64 | priority = 3,
65 | tags = "aaa | bbb",
66 | path = jobdir2
67 | )
68 | )
69 |
70 | # expect that newly created jobs are appended
71 | jobs3 <- job_read()
72 | expect_length(jobs3, 3)
73 | expect_named(jobs3, c("hitmebaby", "toxic", "slave4u"))
74 |
75 | })
76 |
--------------------------------------------------------------------------------
/tests/testthat/test-job_glimpse.R:
--------------------------------------------------------------------------------
1 | # set up
2 | loc <- tempdir()
3 | options(workbch.home = loc)
4 |
5 | # delete the job file if for some reason it exists
6 | if(file.exists(job_file())) {
7 | file.remove(job_file())
8 | }
9 |
10 | # create path
11 | jobdir <- file.path(loc, "hitmebaby")
12 | if(!dir.exists(jobdir)) dir.create(jobdir)
13 |
14 | # create a job
15 | job_create(
16 | jobname = "hitmebaby",
17 | description = "a song",
18 | owner = "britney",
19 | status = "masked",
20 | priority = 2,
21 | path = jobdir,
22 | tags = "awesome"
23 | )
24 | jb <- job_read()[[1]]
25 |
26 | test_that("job_glimpse works", {
27 |
28 | # check that job_glimpse returns the job
29 | jb2 <- job_glimpse("hitmebaby")
30 | expect_equal(jb, jb2)
31 |
32 | # check that job_glimpse throws errors
33 | expect_error(job_glimpse(), "Could not detect current")
34 | expect_error(job_glimpse(1), "character and length 1")
35 | expect_error(job_glimpse("toxic"), "No job exists with")
36 |
37 | # check it defaults to current job if one exists
38 | wd <- setwd(jobdir)
39 | jb3 <- job_glimpse()
40 | expect_equal(jb, jb3)
41 | setwd(wd)
42 |
43 | # add a url and check
44 | job_modify("hitmebaby", url = "github | nopenope")
45 | jb4 <- job_glimpse("hitmebaby")
46 | expect_equal(job_read()[["hitmebaby"]], jb4)
47 |
48 |
49 | })
50 |
--------------------------------------------------------------------------------
/tests/testthat/test-job_home.R:
--------------------------------------------------------------------------------
1 | # set up
2 | loc <- tempdir()
3 | options(workbch.home = loc)
4 |
5 | # delete the job file if for some reason it exists
6 | if(file.exists(job_file())) {
7 | file.remove(job_file())
8 | }
9 |
10 | # create path
11 | jobdir <- file.path(loc, "hitmebaby")
12 | if(!dir.exists(jobdir)) dir.create(jobdir)
13 |
14 | # create jobs, one with a path
15 | job_create(
16 | jobname = "hitmebaby",
17 | description = "a song",
18 | owner = "britney",
19 | path = jobdir
20 | )
21 | job_create(
22 | jobname = "toxic",
23 | description = "a song",
24 | owner = "britney"
25 | )
26 |
27 | test_that("job_home works", {
28 |
29 | # the three scenarios when a string is given
30 | expect_equal(job_home("hitmebaby"), jobdir)
31 | expect_error(job_home("toxic"), "No path known for")
32 | expect_error(job_home("dfasdfsdgdf"), "No job exists with")
33 |
34 | # make sure we're hitting verify_onestring
35 | expect_error(job_home(1), "must be character and length 1")
36 |
37 | # make sure we're hitting job_getcurrent
38 | expect_error(job_home(), "Could not detect current job")
39 | wd <-setwd(jobdir)
40 | expect_equal(job_home(), jobdir)
41 | setwd(wd)
42 |
43 | })
44 |
--------------------------------------------------------------------------------
/tests/testthat/test-job_list.R:
--------------------------------------------------------------------------------
1 | # set up
2 | loc <- tempdir()
3 | options(workbch.home = loc)
4 |
5 | # delete the job file if for some reason it exists
6 | if(file.exists(job_file())) {
7 | file.remove(job_file())
8 | }
9 |
10 | # create path
11 | jobdir <- file.path(loc, "hitmebaby")
12 | if(!dir.exists(jobdir)) dir.create(jobdir)
13 |
14 | # create jobs
15 | job_create(
16 | jobname = "hitmebaby",
17 | description = "a song",
18 | owner = "britney",
19 | status = "inactive",
20 | priority = 2,
21 | path = jobdir,
22 | tags = "awesome"
23 | )
24 | job_create(
25 | jobname = "toxic",
26 | description = "another song",
27 | owner = "britney",
28 | status = "active",
29 | priority = 1,
30 | tags = "awesome | fun"
31 | )
32 |
33 | test_that("job_list works", {
34 |
35 | # make sure we have a jobs file
36 | expect_length(job_read(), 2)
37 |
38 | # by default it should return both jobs
39 | expect_equal(nrow(job_list()), 2)
40 | expect_named(
41 | job_list(),
42 | c("jobname", "owner", "priority", "status", "description")
43 | )
44 | expect_equal(job_list()$jobname, c("toxic", "hitmebaby"))
45 |
46 | # now give some queries
47 | expect_equal(job_list("active")$jobname, "toxic")
48 | expect_equal(job_list(1)$jobname, "toxic")
49 | expect_null(job_list("masked"))
50 | expect_named(job_list(select = c("tags")), "tags")
51 | expect_named(
52 | job_list(select = NULL),
53 | c("jobname", "owner", "priority", "status",
54 | "description", "path", "tags", "urls")
55 | )
56 |
57 | })
58 |
--------------------------------------------------------------------------------
/tests/testthat/test-job_modify.R:
--------------------------------------------------------------------------------
1 | # set up
2 | loc <- tempdir()
3 | options(workbch.home = loc)
4 |
5 | # delete the job file if for some reason it exists
6 | if(file.exists(job_file())) {
7 | file.remove(job_file())
8 | }
9 |
10 | # create path
11 | jobdir <- file.path(loc, "hitmebaby")
12 | if(!dir.exists(jobdir)) dir.create(jobdir)
13 |
14 | # create a job object directly
15 | job1 <- list()
16 | job1[["hitmebaby"]] <- new_job(
17 | jobname = "hitmebaby",
18 | description = "a song",
19 | owner = "britney",
20 | status = "masked",
21 | priority = 2,
22 | path = jobdir,
23 | tags = "awesome",
24 | sentinel = FALSE
25 | )
26 |
27 | # write a different entity to file
28 | job_create(
29 | jobname = "toxic",
30 | description = "another song",
31 | owner = "not britney"
32 | )
33 |
34 | test_that("job_modify works", {
35 |
36 | # try modifying everything at once to transform toxic
37 | # into hitmebaby
38 | job_modify(
39 | jobname = "toxic",
40 | newname = "hitmebaby",
41 | description = "a song",
42 | owner = "britney",
43 | status = "masked",
44 | priority = 2,
45 | path = jobdir,
46 | tags = "awesome"
47 | )
48 |
49 | # the idstring will be different, overwrite
50 | job2 <- job_read()
51 | job1[[1]]$idstring <- job2[[1]]$idstring
52 |
53 | # check identical
54 | expect_equal(job2, job1)
55 |
56 | # add a url
57 | job_modify(
58 | jobname = "hitmebaby",
59 | url = "github | http://nope.com"
60 | )
61 |
62 | # check that the correct information is written
63 | job3 <- job_read()
64 | expect_equal(job3[["hitmebaby"]]$urls$site, "github")
65 | expect_equal(job3[["hitmebaby"]]$urls$link, "http://nope.com")
66 |
67 | # SOMETHING WEIRD HERE
68 |
69 | # # delete a url
70 | # job_modify(
71 | # jobname = "hitmebaby",
72 | # url = "github"
73 | # )
74 | #
75 | # # chech that it is deleted
76 | # job3 <- job_read()
77 | # expect_length(job3[["hitmebaby"]]$urls$site, 0)
78 | # expect_length(job3[["hitmebaby"]]$urls$link, 0)
79 |
80 |
81 | # delete the job
82 | expect_equal(job_home("hitmebaby"), jobdir)
83 | job_modify("hitmebaby", delete = TRUE)
84 | expect_error(job_home("hitmebaby"), "No job exists with name")
85 |
86 | })
87 |
--------------------------------------------------------------------------------
/tests/testthat/test-miscellaneous.R:
--------------------------------------------------------------------------------
1 | test_that("empty_url works", {
2 | expect_equal(
3 | empty_url(),
4 | new_url(
5 | site = character(0),
6 | link = character(0),
7 | verify = FALSE
8 | )
9 | )
10 | })
11 |
12 | test_that("idstring works", {
13 | set.seed(1)
14 | expect_equal(idstring(), "dMaHwQnrYG")
15 | })
16 |
17 | test_that("print method works", {
18 |
19 | tbl1 <- tibble::tibble(
20 | x = rnorm(50),
21 | y = rnorm(50)
22 | )
23 |
24 | tbl2 <- as_wkbch_tbl(tbl1)
25 |
26 | # same values different class
27 | expect_equivalent(tbl2, tbl1)
28 | expect_s3_class(tbl2, c("wkbch_tbl", class(tbl1)))
29 |
30 | # print method for wkbch_tbl fixes the output row
31 | out1 <- capture.output(print(tbl1, n = 100))
32 | out2 <- capture.output(print(tbl2))
33 | expect_identical(out1, out2)
34 |
35 | tbl3 <- tibble::tibble(
36 | x = rnorm(150),
37 | y = rnorm(150)
38 | )
39 |
40 | tbl4 <- as_wkbch_tbl(tbl3)
41 |
42 | # print method for wkbch_tbl fixes the output row
43 | out3 <- capture.output(print(tbl3, n = 100))
44 | out4 <- capture.output(print(tbl4))
45 | expect_identical(out3, out4)
46 |
47 |
48 | })
49 |
50 | test_that("split_url and split_tag work", {
51 |
52 | # make sure it calls verify_onestring
53 | expect_error(split_tags(1), "must be character and length 1")
54 | expect_error(split_url(1), "must be character and length 1")
55 | expect_error(split_tags(character(0)), "must be character and length 1")
56 | expect_error(split_url(character(0)), "must be character and length 1")
57 | expect_error(split_tags(c("a", "b")), "must be character and length 1")
58 | expect_error(split_url(c("a", "b")), "must be character and length 1")
59 |
60 | # make sure it splits
61 | expect_equal(split_tags(""), character(0))
62 | expect_equal(split_tags("|"), character(0))
63 | expect_equal(split_tags("aaa bbb"), "aaa bbb")
64 | expect_equal(split_tags("aaa | bbb"), c("aaa", "bbb"))
65 | expect_equal(split_tags(" aaa| "), "aaa")
66 | expect_equal(split_tags(" |bbb| "), "bbb")
67 | expect_equal(split_tags(" |aaa|||| bbb "), c("aaa", "bbb"))
68 |
69 | # make sure it splits
70 | expect_equal(split_url(""), character(0))
71 | expect_equal(split_url("|"), character(0))
72 | expect_equal(split_url("aaa bbb"), "aaa bbb")
73 | expect_equal(split_url("aaa | bbb"), c("aaa", "bbb"))
74 | expect_equal(split_url(" aaa| "), "aaa")
75 | expect_equal(split_url(" |bbb| "), "bbb")
76 | expect_equal(split_url(" |aaa|||| bbb "), c("aaa", "bbb"))
77 |
78 |
79 | })
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/tests/testthat/test-pull.R:
--------------------------------------------------------------------------------
1 |
2 | # reset home to a tempory directory
3 | loc <- tempdir()
4 | options(workbch.home = loc)
5 |
6 | test_that("pull functions work", {
7 |
8 | jobs <- NULL
9 |
10 | # pull from empty jobnames and paths
11 | expect_equal(pull_jobnames(jobs), character(0))
12 | expect_equal(pull_jobpaths(jobs), character(0))
13 | expect_equal(pull_jobinfo(jobs), tibble::tibble())
14 |
15 | jobs <- list()
16 | jobs[["toxic"]] <- workbch:::new_job(
17 | jobname = "toxic",
18 | description = "a song",
19 | owner = "britney",
20 | sentinel = FALSE)
21 |
22 | # check job names and paths: named character vectors
23 | expect_equal(pull_jobnames(jobs), c(toxic = "toxic"))
24 | expect_equal(pull_jobpaths(jobs), c(toxic = NA_character_))
25 | expect_named(pull_jobinfo(jobs), c("jobname", "path", "idstring"))
26 | expect_equal(nrow(pull_jobinfo(jobs)), 0)
27 |
28 | # add a second job that does have a path
29 | jobs[["hitmebaby"]] <- new_job(
30 | jobname = "hitmebaby",
31 | description = "another song",
32 | owner = "britney",
33 | sentinel = FALSE,
34 | path = loc
35 | )
36 |
37 | # check job names and paths: named character vectors
38 | expect_equal(pull_jobnames(jobs), c(toxic = "toxic", hitmebaby = "hitmebaby"))
39 | expect_equal(pull_jobpaths(jobs), c(toxic = NA_character_, hitmebaby = loc))
40 | expect_named(pull_jobinfo(jobs), c("jobname", "path", "idstring"))
41 | expect_equal(nrow(pull_jobinfo(jobs)), 1)
42 | expect_equal(pull_jobinfo(jobs)$jobname, "hitmebaby")
43 | expect_equal(pull_jobinfo(jobs)$path, loc)
44 | expect_equal(pull_jobinfo(jobs)$idstring, jobs[["hitmebaby"]]$idstring)
45 |
46 |
47 | })
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/tests/testthat/test-readwrite.R:
--------------------------------------------------------------------------------
1 |
2 | # reset home to a tempory directory
3 | loc <- tempdir()
4 | options(workbch.home = loc)
5 |
6 | test_that("job_file returns the correct path", {
7 | expect_equal(job_file(), file.path(loc, "workbch_jobs.json"))
8 | })
9 |
10 | test_that("reading and writing jobs works", {
11 |
12 | # delete the job file if for some reason it exists
13 | if(file.exists(job_file())) {
14 | file.remove(job_file())
15 | }
16 |
17 | # check that job_read returns NULL for an empty file
18 | jobs <- job_read()
19 | expect_null(jobs)
20 |
21 | # create a list of jobs directly from the constructor
22 | jobs <- suppressWarnings(list(toxic = new_job(
23 | jobname = "toxic", description = "a song", owner = "britney"
24 | )))
25 | job_write(jobs)
26 |
27 | # check job read has the correct info
28 | expect_equal(job_read(), jobs)
29 |
30 | # add a second job that does have a path
31 | jobs[["hitmebaby"]] <- suppressWarnings(new_job(
32 | jobname = "hitmebaby",
33 | description = "another song",
34 | owner = "britney",
35 | path = loc
36 | ))
37 | job_write(jobs)
38 |
39 | # check job read has the correct info
40 | expect_equal(job_read(), jobs)
41 |
42 | })
43 |
44 |
--------------------------------------------------------------------------------
/tests/testthat/test-sentinel.R:
--------------------------------------------------------------------------------
1 |
2 | loc <- tempdir()
3 | options(workbch.home = loc)
4 |
5 | test_that("sentinel_write works", {
6 |
7 | s <- file.path(loc, ".workbch")
8 | if(file.exists(s)) { file.remove(s) }
9 |
10 | sentinel_write(dir = loc, jobname = "toxic", idstring = "abcdeABCDE")
11 |
12 | expect_true(file.exists(s))
13 | expect_equal(readLines(s), c("toxic", "abcdeABCDE"))
14 |
15 | })
16 |
17 |
18 | test_that("sentinel_missing works", {
19 |
20 | # create path
21 | jobdir <- file.path(loc, "hitmebaby")
22 | if(!dir.exists(jobdir)) dir.create(jobdir)
23 |
24 | # write the job with no sentinel file
25 | jobs <- list()
26 | jobs[["hitmebaby"]] <- new_job(
27 | jobname = "hitmebaby",
28 | description = "a song",
29 | owner = "britney",
30 | path = jobdir,
31 | sentinel = FALSE
32 | )
33 | job_write(jobs)
34 |
35 | # expect it to detect the missing sentinel
36 | expect_equal(sentinel_missing(), "hitmebaby")
37 |
38 | # now write the sentinel
39 | sentinel_write(dir = jobdir, jobname = "hitmebaby",
40 | idstring = jobs[["hitmebaby"]]$idstring)
41 |
42 | # expect nothing missing
43 | expect_length(sentinel_missing(), 0)
44 |
45 | })
46 |
--------------------------------------------------------------------------------
/tests/testthat/test-verify.R:
--------------------------------------------------------------------------------
1 | test_that("verify_onestring works", {
2 | msg <- "must be character and length 1"
3 |
4 | # should fail
5 | expect_error(verify_onestring(1), msg)
6 | expect_error(verify_onestring(character(0L)), msg)
7 | expect_error(verify_onestring(NA), msg)
8 | expect_error(verify_onestring(NULL), msg)
9 | expect_error(verify_onestring(c("a", "b")), msg)
10 | expect_error(verify_onestring(list("a")), msg)
11 | expect_error(verify_onestring(matrix("a")), msg)
12 | expect_error(verify_onestring(matrix(character(0L))), msg)
13 | expect_error(verify_onestring(TRUE), msg)
14 |
15 | # should succeed
16 | expect_true(verify_onestring("asdf ^asf"))
17 | })
18 |
19 | test_that("verify_character works", {
20 | msg <- "must be character"
21 |
22 | # should fail
23 | expect_error(verify_character(1), msg)
24 | expect_error(verify_character(NA), msg)
25 | expect_error(verify_character(NULL), msg)
26 | expect_error(verify_character(list("a")), msg)
27 | expect_error(verify_character(matrix("a")), msg)
28 | expect_error(verify_character(matrix(character(0L))), msg)
29 | expect_error(verify_character(matrix(c("a","b"))), msg)
30 | expect_error(verify_character(TRUE), msg)
31 |
32 | # should succeed
33 | expect_true(verify_character(character(0L)))
34 | expect_true(verify_character(NA_character_))
35 | expect_true(verify_character("aasdfasdf"))
36 | expect_true(verify_character(c("asdfasdf", "a")))
37 | })
38 |
39 |
40 | test_that("verify_status works", {
41 |
42 | # cursory check that verify_onestring is called
43 | msg <- "must be character and length 1"
44 | expect_error(verify_status(1), msg)
45 | expect_error(verify_status(c("active", "inactive")), msg)
46 |
47 | # check that invalid status string are not accepted
48 | msg <- "must be 'active', 'inactive'"
49 | expect_error(verify_status("blarhg"), msg)
50 | expect_error(verify_status("nactive"), msg)
51 | expect_error(verify_status("Active"), msg)
52 | expect_error(verify_status(" active"), msg)
53 | expect_error(verify_status("active "), msg)
54 | expect_error(verify_status("ac tive"), msg)
55 |
56 | # should succeed
57 | expect_true(verify_status("active"))
58 | expect_true(verify_status("inactive"))
59 | expect_true(verify_status("complete"))
60 | expect_true(verify_status("abandoned"))
61 | expect_true(verify_status("masked"))
62 |
63 | })
64 |
65 |
66 | test_that("verify_priority works", {
67 |
68 | # check that invalid priorities throw errors
69 | msg <- "job priority must be a positive integer"
70 | expect_error(verify_priority(0), msg)
71 | expect_error(verify_priority(-1), msg)
72 | expect_error(verify_priority(NaN), msg)
73 | expect_error(verify_priority(1.2), msg)
74 | expect_error(verify_priority("a"), msg)
75 | expect_error(verify_priority(1:2), msg)
76 | expect_error(verify_priority(NULL), msg)
77 | expect_error(verify_priority(Inf), msg)
78 | expect_error(verify_priority(NA_integer_), msg)
79 | expect_error(verify_priority(NA), msg)
80 |
81 | # should succeed
82 | expect_true(verify_priority(1))
83 | expect_true(verify_priority(2))
84 | expect_true(verify_priority(3))
85 |
86 | })
87 |
88 | test_that("verify_description works", {
89 |
90 | # cursory check that verify_onestring is called
91 | msg <- "must be character and length 1"
92 | expect_error(verify_description(1), msg)
93 | expect_error(verify_description(c("blah blah", "blah")), msg)
94 |
95 | # expect success
96 | expect_true(verify_description("a job to do something"))
97 |
98 | })
99 |
100 | test_that("verify_site works", {
101 |
102 | # cursory check that verify_onestring is called
103 | msg <- "must be character and length 1"
104 | expect_error(verify_site(1), msg)
105 | expect_error(verify_site(c("blah blah", "blah")), msg)
106 |
107 | # expect success
108 | expect_true(verify_site("gitblah"))
109 |
110 | })
111 |
112 | test_that("verify_link works", {
113 |
114 | # cursory check that verify_onestring is called
115 | msg <- "must be character and length 1"
116 | expect_error(verify_link(1), msg)
117 | expect_error(verify_link(c("blah blah", "blah")), msg)
118 |
119 | # expect success
120 | expect_true(verify_link("https://gitblub.com/fuser/depot"))
121 |
122 | })
123 |
124 | test_that("verify_owner works", {
125 |
126 | # cursory check that verify_onestring is called
127 | msg <- "must be character and length 1"
128 | expect_error(verify_owner(1), msg)
129 | expect_error(verify_owner(c("blah blah", "blah")), msg)
130 |
131 | # expect success
132 | expect_true(verify_owner("britney"))
133 |
134 | })
135 |
136 |
137 | test_that("verify_jobname works", {
138 |
139 | # cursory check that verify_onestring is called
140 | msg <- "must be character and length 1"
141 | expect_error(verify_jobname(1), msg)
142 | expect_error(verify_jobname(c("blah blah", "blah")), msg)
143 |
144 | # expect success
145 | expect_true(verify_jobname("toxic"))
146 |
147 | })
148 |
149 |
150 | test_that("verify_path works", {
151 |
152 | # cursory check that verify_onestring is called
153 | msg <- "must be character and length 1"
154 | expect_error(verify_path(1), msg)
155 | expect_error(verify_path(c("blah blah", "blah")), msg)
156 |
157 | # expect success
158 | expect_true(verify_path("~/GitHub/"))
159 |
160 | })
161 |
162 |
163 | test_that("verify_jobexists / verify_jobmissing work", {
164 |
165 | loc <- tempdir()
166 | options(workbch.home = loc)
167 |
168 | # delete the job file if for some reason it exists
169 | if(file.exists(job_file())) {
170 | file.remove(job_file())
171 | }
172 | jobs <- job_read()
173 |
174 | # verification tests (here because that was the original file structure)
175 | expect_true(verify_jobmissing("toxic", jobs, strict = FALSE))
176 | expect_true(verify_jobmissing("hitmebaby", jobs, strict = FALSE))
177 |
178 | # create a list of jobs directly from the constructor
179 | jobs <- suppressWarnings(list(toxic = new_job(
180 | jobname = "toxic", description = "a song", owner = "britney"
181 | )))
182 | job_write(jobs)
183 |
184 | # verification tests (here because that was the original file structure)
185 | expect_true(verify_jobexists("toxic", jobs, strict = FALSE))
186 | expect_true(verify_jobmissing("hitmebaby", jobs, strict = FALSE))
187 |
188 | # add a second job that does have a path
189 | jobs[["hitmebaby"]] <- suppressWarnings(new_job(
190 | jobname = "hitmebaby",
191 | description = "another song",
192 | owner = "britney",
193 | path = loc
194 | ))
195 | job_write(jobs)
196 |
197 | # verification tests (here because that was the original file structure)
198 | expect_true(verify_jobexists("toxic", jobs, strict = FALSE))
199 | expect_true(verify_jobexists("hitmebaby", jobs, strict = FALSE))
200 |
201 | })
202 |
203 |
204 |
--------------------------------------------------------------------------------
/vignettes/.gitignore:
--------------------------------------------------------------------------------
1 | *.html
2 | *.R
3 |
--------------------------------------------------------------------------------
/vignettes/setup.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Setting up your work bench"
3 | ---
4 |
5 | ```{r, include = FALSE}
6 | knitr::opts_chunk$set(
7 | collapse = TRUE,
8 | comment = "#>"
9 | )
10 | ```
11 |
12 |
13 | ```{r, include = FALSE}
14 | knitr::opts_chunk$set(
15 | collapse = TRUE,
16 | comment = "#>"
17 | )
18 | ```
19 |
20 | The workbch ("work bench") package provides simple utility functions to help the R user keep track of projects and navigate between them. The package is designed around the concept of *jobs*, where a job might correspond to an RStudio project, a git repository, a research project or indeed all of the above. Jobs are assumed to be stored in a single folder, but can be associated with URLs (e.g., on GitHub, Overleaf, OSF, or elsewhere). The package is intended to be used interactively, though most functions can be called from scripts if needed.
21 |
22 | The package consists of nine functions. Three functions are used to create, modify, and delete jobs
23 |
24 | - `job_create()`. Create a new job
25 | - `job_modify()`. Modify or delete an existing job
26 | - `job_seek()`. Scans a directory recursively to find jobs
27 |
28 | There are three functions that are useful for navigation:
29 |
30 | - `job_open()`. Opens an RStudio project or changes working directory
31 | - `job_openurl()`. Opens a URL associated with a job in a browser window
32 | - `job_home()`. Returns the path to the job folder
33 |
34 | There are three functions that are useful for keeping track of projects:
35 |
36 | - `job_gitreport()`. Shows the git status of all jobs
37 | - `job_glimpse()`. Shows all information stored about a job
38 | - `job_list()`. Displays a table summarising all jobs, or a subset of them.
39 |
40 |
41 |
42 | ## Set up
43 |
44 | The easiest way to get started with workbch is to use `job_seek()` to scan for jobs to track. However, before you do this, the workbch package needs to know two things: the "home" folder where it should save its own files, and the top level "search" folder (or folders) where it should look for jobs. The simplest way to do this is to add a few lines to your .Rprofile file, using `usethis::edit_r_profile()` or simply using a text editor. To keep this vignette simple, I'll set it up so that the workbch package only scans my "fun" GitHub folder:
45 |
46 | ```{r}
47 | # workbch options to add to .Rprofile
48 | options(workbch.home = "/home/danielle/GitHub/fun")
49 | options(workbch.search = "/home/danielle/GitHub/fun")
50 | suppressMessages(require(workbch))
51 | ```
52 |
53 | Once you have saved this to the .Rprofile and restarted the R session, you're ready to start adding jobs.
54 |
55 | ## Adding jobs
56 |
57 | The simplest way to add jobs is to call `job_seek()`. To make things a little easier, when I do this I'll set a default value for the `owner` of created jobs:
58 |
59 | ```{r, eval=FALSE}
60 | job_seek(owner = "Danielle")
61 | ```
62 |
63 | When I do this, I am shown a message indicating that `job_seek()` has discovered five folders that might correspond to jobs. After agreeing to continue, it shows me what it has found, one job at a time. Here is the first one:
64 |
65 | ```
66 | Suggested values:
67 |
68 | Path: /home/danielle/GitHub/fun/rainbowr
69 | Job name: rainbowr
70 | Description: rainbowr
71 | Owner: Danielle
72 | Status: active
73 | Priority: 1
74 | Tags:
75 | Git remote (site): github
76 | Git remote (url): https://github.com/djnavarro/rainbowr/
77 |
78 | Track this folder with workbch? [y/n]
79 | ```
80 |
81 | As this is a job I wish to track, I type `y`, and then R will prompt me either to accept each of these suggested values (by pressing enter) or to type in the value I would like worbch to store:
82 |
83 | ```
84 | Type new values or press enter to use the suggested value:
85 |
86 | Job name......
87 | Description... generates LGBT hex stickers
88 | Owner.........
89 | Status........ inactive
90 | Priority......
91 | Tags..........
92 | ```
93 |
94 | In this example I have retained the suggested value for `jobname` ("rainbowr"), `owner` ("Danielle"), `priority` (1) and `tags` (no tags), but chosen to overwrite the `description` (almost always a good idea) and the `status`. This process repeats a few times, and the end result is a JSON file (`workbch_jobs.json`) in the "home" folder. Note also that this will write a file called `.workbch` inside the folder for every tracked job. This file contains almost no information: it lists the job name along with a random identification string, and is only used to make it possible for the workbch package to recover the locations of projects if they are moved.
95 |
96 | At this point I'm ready to go!
97 |
98 | ## Listing jobs
99 |
100 | ```{r eval=FALSE}
101 | job_list()
102 | ```
103 |
104 | ```
105 | # A tibble: 4 x 5
106 | jobname owner priority status description
107 |
108 | 1 asciify Danielle 1 active make ASCII art from images
109 | 2 rainbowr Danielle 1 inactive generates LGBT hex stickers
110 | 3 brownianbridge Danielle 2 inactive generate Brownian bridge animations
111 | 4 skyliner Danielle 2 inactive create gifs of the Sydney skyline
112 | ```
113 |
114 | By default, the `job_list()` function will only show jobs that have `priority` 1 or 2, and whose `status` is listed as `active` or `inactive` (i.e., `abandoned`, `masked` and `complete` jobs are not displayed). However it is easy to customise the output by entering a search query. At present, the behaviour of this search is somewhat limited: it will return every job for which at least one of the fields is an exact match to the query string. So for example:
115 |
116 | ```{r, eval=FALSE}
117 | job_list("inactive")
118 | ```
119 |
120 | would return all the jobs with an "inactive" status:
121 |
122 | ```
123 | # A tibble: 3 x 5
124 | jobname owner priority status description
125 |
126 | 1 rainbowr Danielle 1 inactive generates LGBT hex stickers
127 | 2 brownianbridge Danielle 2 inactive generate Brownian bridge animations
128 | 3 skyliner Danielle 2 inactive create gifs of the Sydney skyline
129 | ```
130 |
131 | whereas:
132 |
133 | ```{r, eval=FALSE}
134 | job_list(1)
135 | ```
136 |
137 | returns jobs that have priority 1:
138 |
139 | ```
140 | # A tibble: 2 x 5
141 | jobname owner priority status description
142 |
143 | 1 asciify Danielle 1 active make ASCII art from images
144 | 2 rainbowr Danielle 1 inactive generates LGBT hex stickers
145 | ```
146 |
147 | This can also be used to select those jobs that match a tag, or are owned by a particular person, and so on.
148 |
149 | ## Screencast
150 |
151 |
155 |
--------------------------------------------------------------------------------
/vignettes/setup.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/djnavarro/workbch/6cc7a28e92a24acee1f61ad60c124f701108a96a/vignettes/setup.mp4
--------------------------------------------------------------------------------
/vignettes/usage.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Using the workbch package"
3 | ---
4 |
5 | ```{r, include = FALSE}
6 | knitr::opts_chunk$set(
7 | collapse = TRUE,
8 | comment = "#>"
9 | )
10 | ```
11 |
12 | ```{r setup}
13 | library(workbch)
14 | ```
15 |
16 | ## Navigation
17 |
18 | One function of the workbch package is to make navigation a little easier: `job_open()` allows you to switch between jobs, and `job_openurl()` opens a URL linked to the job in a browser window. The screencast below illustrates this:
19 |
20 |
24 |
25 | ## Git report
26 |
27 | A second function of workbch is to keep track of the git status of various projects. A common workflow problem (for me, at least) is that I sometimes forget to commit changes or push them upstream, and then forget which projects I've left in this "unclean" state. The `job_gitreport()` function aims to make this easier by checking the git status for all jobs, and reporting those jobs that are not in a clean state. For example:
28 |
29 | ```{r, eval=FALSE}
30 | job_gitreport()
31 | ```
32 | ```
33 | # A tibble: 3 x 6
34 | jobname staged unstaged untracked ahead behind
35 |
36 | 1 conjunction 0 1 1 3 0
37 | 2 psychtheory 0 0 1 0 0
38 | 3 tidylsrbook 0 24 12 0 0
39 | ```
40 |
41 | Screencast illustrating how `job_gitreport()` works:
42 |
43 |
47 |
48 |
49 | ## Moving jobs
50 |
51 | A third function of the workbch package is keeping track of job locations when they move around on the local machine, as long as they stay somewhere on the workbch search path (i.e., the "workbch.search" option). It does this by matching information stored in the ".workbch" sentinel file to entries in the "workbch_jobs.json" file. There are two functions that are useful for this:
52 |
53 | - `job_list()` throws a warning if a job folder has moved
54 | - `job_seek()` will ask if you want to update the location
55 |
56 | This is illustrated in the screencast below:
57 |
58 |
62 |
63 |
64 | ## Modifying jobs
65 |
66 | A common task is to update the information associated with a job. The priority may change, it may be assigned a new owner or acquire a new URL, etc. The `job_modify()` function can be used for this, as illustrated below:
67 |
68 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/workbch.Rproj:
--------------------------------------------------------------------------------
1 | Version: 1.0
2 |
3 | RestoreWorkspace: No
4 | SaveWorkspace: No
5 | AlwaysSaveHistory: Default
6 |
7 | EnableCodeIndexing: Yes
8 | UseSpacesForTab: Yes
9 | NumSpacesForTab: 2
10 | Encoding: UTF-8
11 |
12 | RnwWeave: Sweave
13 | LaTeX: pdfLaTeX
14 |
15 | AutoAppendNewline: Yes
16 | StripTrailingWhitespace: Yes
17 |
18 | BuildType: Package
19 | PackageUseDevtools: Yes
20 | PackageInstallArgs: --no-multiarch --with-keep.source
21 | PackageRoxygenize: rd,collate,namespace
22 |
--------------------------------------------------------------------------------