Contributions to manynet, whether in the form of issue identification, bug fixes, new code or documentation are encouraged and welcome.
Please note that the manynet project is released with a Contributor Code of Conduct. By contributing to this project, you agree to abide by its terms.
Each entry says when to read the section. Update this list whenever a heading below is added, renamed, or moved.
stocnet object model: before you read or write the components of a stocnet, or its missing dataAUDIT
NEWS.md conventions: before you write a NEWS.md entry or a commit messagePlease use the issues tracker on GitHub to identify any function-related issues. You can use these issues to track progress on the issue and to comment or continue a conversation on that issue. The most useful issues are ones that precisely identify an error, or propose a test that should pass but instead fails. Examples for documentation are also most welcome.
manynet is an R package (part of the stocnet ecosystem) providing the data layer for network analysis: tools to make, manipulate, and modify many kinds of networks — one-mode/two-mode, directed/undirected, weighted, signed, multiplex, multimodal, and longitudinal/dynamic. Functions work across representations (matrices, edgelists, igraph, network, tidygraph) via a lossless coercion layer, so most functions call as_igraph()/as_tidygraph() etc. internally rather than assuming a single class. Division of labour to keep in mind when adding functions:
as_*()), making and reading networks, manipulating and modifying nodes, ties and attributes, and network-level logical tests (e.g. is_directed(), is_twomode()).Where a function computes how alike two nodes are, the line between manynet and netrics runs as follows. Arithmetic over a network’s own cells — comparing two nodes’ profiles of ties or affiliations, as to_mode1() and to_proximity() do — is a transformation of the data, and belongs here as a to_*() function. Algorithms that iterate or recurse to a fixed point — RoleSim, REGE, CONCOR — are analytic, and belong in netrics, which calls into this package’s to_*() functions for the profile arithmetic they need.
All stocnet packages aim for the same three things: declarative simplicity, pleasant predictability, and graceful inclusivity. The principles are shared across the packages; the rules and examples below are those of manynet. ### Declarative simplicity
Functions should do one clearly named thing with few arguments. This helps users orient themselves in the package and develop expectations that are not tied to having to read deep into the documentation.
generate_smallworld() and generate_scalefree() rather than names built on Watts and Strogatz or Barabási and Albert.is_twomode() and is_directed() are called inside most to_*() functions, and branch how the function handles the data. Functions use as much data as they are given, so if there is a weighted version, then this will be detected and used unless declared otherwise.to_undirected(), to_unweighted(), or to_unsigned(). Where a variant only adjusts the same operation, keep it as an argument and reuse the name the package already has for that idea, e.g. similarity in to_mode1(), or rule, or connectivity.rule, not method, which already means an S3 method and a statistical method. “mode” means the mode of a two-mode or multimodal network, so the most frequent value is "modal", and the weak or strong components of a network are chosen with connectivity. Functions that assert or count connectedness default to "strong" (e.g. is_connected()), and functions that scope or split a network to "weak" (e.g. to_giant(), to_components()). Before adding an option, look for an existing signature that carries the same idea, and reuse its name and, where possible, its values.mutate_nodes() and mutate_ties() say which table they change.Users should be able to guess a function’s behaviour from its family.
read_*() and write_*() import and export, collect_*() gathers a network from a source, as_*() converts class, to_*() transforms within class, and is_*() returns a single logical. See File organization for the full set.create_*() always yields the same network, generate_*() draws a random one, and play_*() simulates a process on one..data. The making functions take n first, then p, directed, and width, wherever a function has them. Example: create_ring(n, directed, width) and generate_random(n, p, directed). Document shared arguments once, as a man-roxygen/param_*.R template (e.g. param_n, param_p, param_directed, param_width, param_groups, param_degree, and return_make for what the making functions return), with the detail of a page given by @templateVar.to_*() function returns the class it was given, so that it can be dropped into an existing workflow.Functions should accept whatever network users bring and return something they can use.
igraph, network, tidygraph, stocnet, and siena objects, and each class has its as_*() function for when another package requires it. Conversion is lossless wherever the target class can hold the information.to_undirected() on an undirected network and to_mode1() on a one-mode network both return the network as it was. Where a function really cannot proceed, the error says why, and where possible suggests a conversion that would make it work (see Console messaging).stocnet conventions, at the verbosity the user has chosen.stocnet object records its metadata, including its name, source, DOI, date, and how it has been transformed since it was collected, and prints a description built from this rather than a dump of its contents. Example: describe_transformations(to_undirected(ison_southern_women)). The record of transformations follows section 4 of the GRAND guidelines.This is a standard R package developed with devtools/roxygen2. Run these from an R console with the working directory set to the package root (or via Rscript -e).
devtools::load_all()
devtools::document()
devtools::test()
devtools::test(filter = "coercion") (matches test-coercion.R), or testthat::test_file("tests/testthat/test-make_create.R")
devtools::check() or rcmdcheck::rcmdcheck()
lintr::lint_package()
spelling::spell_check_package()
covr::package_coverage()
pkgdown::build_site()
There is no non-R build system — no package.json/Makefile.
Run R in a UTF-8 locale, e.g. LANG=en_US.UTF-8 Rscript -e "devtools::document()". Under the C locale, devtools::document() writes byte escapes into man/ in place of quotation marks and accented letters, and tibbles print differently.
Some files are generated rather than edited directly — README.md, the tutorial articles in vignettes/articles/, and the cheatsheet. See README and Website below for which source each is built from.
R/ files are prefixed by the verb-family of the functions they contain, not by data structure. When looking for a function, search by what it does:
| Prefix | Contains |
|---|---|
make_*.R |
creating/reading/generating networks: create_*() (deterministic structures), generate_*() (stochastic mechanisms), read_*()/write_*() (import/export), collect_*() (gathering a network from a source, make_collect.R), play_*() (diffusion/learning simulations) |
data_*.R |
documentation of the bundled datasets: ison_* classic/instructional, fict_* fictional, irps_* international-relations (see Datasets) |
coerce_graph.R, coerce_list.R, coerce_matrix.R
|
the as_*() translation layer between representations (as_igraph(), as_tidygraph(), as_network(), as_matrix(), as_edgelist(), as_siena(), as_diffnet(), …), implemented as S3 methods dispatching on input class |
class_*.R |
the network classes themselves (class_stocnet.R: make_stocnet(), print.stocnet(), the info/nodes/ties/changes/global data model; class_networks.R: the legacy mnet class, print.mnet, $/$<- accessors), related result classes (class_measures.R, class_members.R, class_motifs.R, class_models.R), the snet_*() CLI layer (class_interface.R), input validation (class_validate.R: validate_stocnet() and its component validators), and the describe_*() helpers behind the print methods (class_describe.R) |
manip_*.R |
dplyr-style verbs for manipulating nodes/ties/attributes (manip_nodes.R, manip_ties.R, manip_globals.R, manip_info.R, manip_changes.R) |
mark_*.R |
logical/predicate functions returning TRUE/FALSE or marks about a network, e.g. the is_*() family (mark_classes.R, mark_features.R, mark_format.R, mark_changes.R) |
modif_*.R |
structural transformations/reformatting: direction, weighting, projection, splitting (to_*(), modif_split.R) and joining (from_*(), modif_from.R), path/level operations, missing data (modif_direction.R, modif_project.R, modif_miss.R, …) |
measure_*.R |
descriptive/attribute measures (measure_attributes.R, measure_properties.R); heavier network-analytic measures live in netrics
|
reexports_classes.R |
re-exports of classes/generics from igraph/tidygraph/network so users need not load those packages directly |
manynet-utils.R, manynet-glossary.R, manynet-defunct.R
|
shared internal helpers, the gloss()/glossary system used in tutorials and docs, and defunct-function shims |
Shared roxygen documentation blocks live in man-roxygen/ as @template fragments — reuse these via @template tags instead of re-writing standard @param/@returns docs.
stocnet object modelstocnet is the package’s native class for richer networks (see R/class_stocnet.R), constructed with make_stocnet() or coerced to with as_stocnet(). It is not layered on top of igraph/tbl_graph; it is a plain list of tibbles plus metadata, with six components — info, nodes, ties, changes, globals, and missings — any of which may be NULL. Every component but info is a table, which is what the plural name signifies. This is what allows multimodal, multiplex, longitudinal/dynamic and modelling-oriented networks (e.g. round-tripping RSiena sienadata objects) to live in one object. Conventions to preserve when writing or editing functions:
info: a list of network-level metadata. The reserved elements are listed in .stocnet_info_fields (see R/manip_info.R), and include name, modes, layers, directed (logical, optionally named per layer), signed (logical, optionally named per layer: the sign of a tie is the sign of its weight, so this says a network is signed where no tie is negative), sender and receiver (the modes a two-mode layer runs from and to), observation ("cross-sectional", "panel", "event", "egocentric", or "cognitive", optionally named per layer), update ("replace" or "increment": how a record of a tie relates to the one before it), focal (dependent variables), centered, the provenance fields source, method, boundary, location, date, and doi, and transformations, the record of what has been done to the network since it was collected. siena holds metadata specific to RSiena. The provenance fields and the transformations follow the GRAND project’s FAIR-aligned metadata standards. See ?add_info for the values each takes, and Datasets for which to complete. A time column alone does not make a panel: update decides whether the moments of a network are the waves of a panel or a stream of events.nodes: one row per node. The label column is label (not name); reserved columns are mode (multimodal/two-mode), active/present (changing networks), and na.ties: one row per tie. from and to are required (even for undirected networks) and are stored as integer indices into nodes, not labels — make_stocnet() matches labels to indices on construction. Reserved columns are layer (multiplex), weight (negative weights mean a signed network, a missing weight a tie of unknown value), length (a distance, such as the length of a road; a larger length is a further tie, where a larger weight is a stronger one, so a tie can have both and neither stands in for the other: see tie_lengths()), time (longitudinal), by (the node that reported a tie, as in a cognitive social structure or an egocentric network), and about (the node a tie is about, as in gossip), and fixed (a logical marking a tie that is present by design and so not free to vary, which as_siena() writes as SIENA’s structural one, 11; a fixed tie is never missing or imputed away, and structural zeros are not held yet, see #195). by and about are integer indices into nodes too, and may hold NA for a layer that no node reported or that is about no node. Anything that renumbers or drops nodes must renumber them as well: use .tie_node_cols and .remap_tie_nodes() (see R/class_stocnet.R) rather than remapping from and to by hand. A broker (“tertius”) is neither. A hyperedge, a tie among any number of nodes, is one row too: it lists its members in the list column with, also as indices into nodes, and holds NA in from and to, while a tie between two nodes holds NULL in with. A list column whose name begins with_ holds a value for each member, in the same order (with_weight, with_direction). A layer holds dyads or hyperedges, never both, and info$hyperedges names what the hyperedges are. Code that reads from and to therefore keeps their type, but meets NA: use .hyper_rows() to tell the two kinds of row apart, .hyper_to_twomode() for the incidence form that other classes hold a hypergraph in, and .needs_dyads() where a function cannot take hyperedges. Every row is a tie: the ties a network records as missing are held elsewhere (below). make_stocnet() does accept an na column marking which rows are missing ties, since that is how the data often arrives, but it splits those rows out rather than storing them.changes: a nodal changelog, held as its own component rather than as extra rows in nodes/ties, with columns time, node, var, and value, plus an optional layer where a change applies to one layer and not others. value is stored as a list-column so changes of any class/length can be logged, but prints as a value plus a type label. A change states what the variable becomes from that moment on, so it is carried forward until another change says otherwise — a node that stops reporting and starts again therefore holds two changes.globals: network-level variables over time, with columns var, value, and optionally time.missings: the ties the network could have observed and did not, with the same columns as ties — usually NULL, see below.nodes$na where a node reports at no point, and a change of the na variable where it varies over time. Every tie such a node would report is then missing — those it sends where the layer is directed, both directions where it is undirected. The missings component holds only the residual, for ties no node’s nonresponse implies. as_missinglist() derives the whole set, and everything else goes through it. See ?make_stocnet for the four states a tie can be in, and keep them apart: a tie to an inactive node is not missing, and a tie of NA weight is present but unvalued. Missing ties are not ties, so nothing counts, returns, draws, or measures them unless it asks for them by name.validate_stocnet() (see R/class_validate.R), which make_stocnet() calls on construction. It checks required columns, coerces reserved columns to their expected classes, and renames common aliases (e.g. name/id → label, sender/ego → from) with an informative message. Extend the validators there rather than re-checking structure inside individual functions.stocnet is a list rather than an igraph, do not reach for igraph primitives on it. Either write an S3 method operating on the tibbles directly (.data$nodes, .data$ties, …), or coerce with as_igraph()/as_tidygraph() where the operation is genuinely graph-theoretic. Return a stocnet when you were given one: rebuild with make_stocnet() so validation and indexing re-run.The older mnet class (R/class_networks.R) — a thin class over igraph/tbl_graph, with name-first nodes, type/wave/sign tie attributes, and changes stored as a graph attribute — is being progressively deprecated in favour of stocnet. Keep its methods working, but write new functionality against stocnet.
Many create_*()/generate_*() functions take an n argument that can be a single integer (one-mode network) or a length-2 integer vector (two-mode network, the sizes of each mode). A stocnet holds the mode of each node in nodes$mode and names the modes in info$modes; the logical type vertex attribute is how igraph and tidygraph hold it, and the coercion functions translate between the two, detecting two-mode structure or taking it from the twomode argument. A two-mode network can be directed: info$sender and info$receiver say which mode its ties run from and to, and is_directed() reports what the object holds.
All user-facing messages go through the snet_*() wrappers in R/class_interface.R, rather than base message()/stop()/warning() or cli calls directly:
| Wrapper | Use for |
|---|---|
snet_abort() |
errors: the function cannot proceed |
snet_warn() |
the function proceeds, but the user should not trust the result without knowing something; raises a real warning condition |
snet_info() |
notable information about what was done, e.g. a defaulted argument |
snet_minor_info() |
incidental detail, e.g. tidying node attributes to stocnet conventions |
snet_success() |
confirmation that a requested operation completed |
snet_prompt() |
interactive questions to the user |
snet_unavailable() |
not-yet-implemented features; aborts, as snet_abort() does |
snet_progress_step(), snet_progress_along(), snet_progress_seq(), snet_progress_nodes()
|
progress reporting in longer-running loops |
One rule decides what the verbosity silences: a call that changes control flow or tells the user not to trust a result always fires, and a call that only reports is silenced. So snet_abort(), snet_unavailable(), snet_warn(), and snet_prompt() fire whatever the verbosity, and the rest depend on options(snet_verbosity = ), which takes one of four levels:
| Level | Adds |
|---|---|
"quiet" (the default) |
nothing |
"normal" |
snet_info(), snet_success()
|
"verbose" |
snet_progress_*() |
"debug" |
snet_minor_info() |
Users opt in with e.g. options(snet_verbosity = "verbose"). Informational output must therefore never be load-bearing, and errors and warnings must carry everything the user needs to act. In tests, expect a snet_warn() with expect_warning(), not expect_message().
These wrappers pass their input to cli, so:
paste(): snet_abort("{.val {unknown}} could not be found on CRAN.").{.fn} for functions, {.arg}/{.var} for arguments and variables, {.val} for values, {.url} for links — so that styling stays consistent across the ecosystem.snet_abort("Node{?s} {.val {missing}} {?was/were} not found in the network.").Messages, warnings, and errors should be written in a way that is useful for new and advanced users alike. This might include listing likely causes, mentioning objects or variables explicitly, and indicating next actions clearly. Prefer “{.arg n} must be a single integer or a length-2 vector for a two-mode network” over “invalid input”.
This package uses the testthat package for testing functions. Please see the testthat website for more details.
Tests in tests/testthat/ mostly mirror the R/ files (e.g. test-make_create.R, test-modif_project.R), alongside test-functional_*.R harnesses that sweep whole function families. Some test files keep an older name than the file they test: test-manip_split.R tests R/modif_split.R, test-model_play.R tests R/make_play.R, and test-coercion.R tests all three R/coerce_*.R files. tests/testthat/helper-manynet.R defines the shared fixtures and helpers used across tests, and tests/testthat/helper-functional.R the family-sweeping machinery. Test fixtures (Pajek, UCINET, GraphML, xlsx, etc.) live under tests/testthat/sheets/.
testthat edition 3 with parallel execution is configured in DESCRIPTION (Config/testthat/parallel: true); Config/testthat/start-first prioritises tutorials_manynet, mark_is.
The harnesses find the exported functions of a family by their prefix (alive_functions(), which leaves out defunct shims), and run each across a grid of fixtures (func_fixtures: directed, two-mode, weighted, signed, multiplex, longitudinal, …) and classes. A new exported function is therefore tested without a new test: that it takes .data first, has a default method, returns what its name implies, and agrees across classes. A combination that does not conform is skipped rather than failed, with a message of the form AUDIT [fn x fixture]: ..., so search the test output for AUDIT to find gaps in an implementation. Where a function needs further arguments to run, add an entry to to_argmakers or meas_argmakers; where a to_*() function implies a property of its result, add one to to_invariants. Extend these maps rather than writing a one-off test.
The bundled datasets are built by scripts in data-raw/, saved with usethis::use_data(<name>, overwrite = TRUE, compress = "bzip2"), and documented in R/data_ison.R, R/data_fict.R, or R/data_irps.R. data-raw/stocnet_conversion.R is the worked example.
stocnet object. Some older datasets are still mnet objects, or lists of them, because a released downstream package relies on their class or attribute names; see issues #185 and #186 for which, and for what each waits on.info, with add_info(): name, modes, layers, and directed (named per layer where the layers differ); observation, and update where the ties hold moments; sender and receiver for a two-mode layer; and the provenance fields source, method, boundary, location, date, and doi. date is when the data was collected or what it describes, not when it was published.is_directed(), is_twomode(), is_signed(), …).\doi{} where there is one. The @format block prints the object itself, so it needs no description by hand.A function that is renamed, superseded, or moved keeps working under its old name for a time, through a shim in R/manynet-defunct.R:
#' @describeIn defunct Deprecated on <date>. and export it..Deprecated("<new>", package = "manynet", old = "<old>") and then the new function, so that the old name still returns a result.fn_moved(), which tells the user where it went and how to install that package.... and .former_args() (see R/make_generate.R).Renamed ... to ... or Moved ... in NEWS.md.Older shims are cleared at a minor release. The functional test harnesses leave shims out, so they need no tests of their own beyond one that the old name warns and still works.
The README offers a landing page for new users, both on the Github repository as well as on the website. As such, it should make a compelling case for the value added of the package, and not drift out of date. Note that README.md is generated from README.Rmd — edit README.Rmd and re-knit (devtools::build_readme()), never edit README.md directly.
The website is created by pkgdown from pkgdown/_pkgdown.yml, and is deployed automatically when changes reach main. Please make sure that the pkgdown website will build correctly: run pkgdown::build_site() locally before opening a PR. The most common failure is a new exported function that is not picked up under the function overview (the reference: section of _pkgdown.yml) — pkgdown requires every exported topic to appear there exactly once, or it will not build. Where possible, add functions to an existing subtitle’s starts_with() pattern (e.g. a new to_*() function needs no change), and only list the topic explicitly where it does not fit a pattern. These reference: titles are also the headings used in NEWS.md (see below), so keep the two in step.
Two further sets of files are generated rather than edited directly:
vignettes/articles/*.Rmd, the static pkgdown versions of the learnr tutorials, are built from inst/tutorials/*/*.Rmd by data-raw/build_tutorial_articles.R. After editing a tutorial, re-run that script and commit the regenerated articles; CI checks that the two are in sync. New tutorials also need an entry under articles: and in the navbar’s tutorials menu in _pkgdown.yml.man/figures/cheatsheet.png and inst/figures/cheatsheet.pdf. It might not cover all functionality as the package develops, but should at least not use deprecated or renamed function names.NEWS.md conventionsNEWS.md groups each version’s changes under ## headings that mirror the website function overview (pkgdown/_pkgdown.yml reference: titles). Lead with ## Package (package-wide/website/infrastructure changes), then the function families in overview order: ## Making, ## Classes, ## Coercion, ## Manipulating, ## Modifying, ## Describing, ## Practicing. ## Classes is not a website title, but collects changes to the stocnet object itself (its components, validate_*(), and the description and print methods). Where a release changes what downstream packages report, ## Marking, ## Measuring, and ## Learning follow the same pattern after ## Modifying. Put ## Glossary and ## Tutorials near the end, with ## Tutorials immediately before any ## Data section, so that tutorials and data usually close the list. Each heading appears at most once per version. Spell the coercion heading ## Coercion, not ## Coercing. ## Manipulating covers the manip_* verbs (nodes/ties/attributes/changes/info/globals); ## Modifying covers the modif_* transformations (to_*(), projection, splits, etc.). Keep the two distinct, as the website does.
Start each bullet with a verb matching the change type:
Added ... — new functionalityFixed ... — bug fixes; if it relates to a GitHub issue, suffix with (closes #123). Note that GitHub closes the issue only where the same phrase is in a commit message or the pull request descriptionRenamed ... to ... — function or data name migrationsImproved ... — functional updates to existing behaviourAccelerated ... — the same behaviour, made faster; give the speed-up in a sub-bullet (see below)Updated ... — documentation changesRemoved ... / Dropped ... — functionality or dependencies taken outMoved ... / Migrated ... — functionality relocated to another package or fileSplit ... — one function or file divided into severalAny of these verbs can also lead a sub-bullet.
An Accelerated ... bullet says how the function was made faster, and a sub-bullet says by how much and for what input, e.g.:
- Accelerated `to_correlation()` by correlating reciprocal and complex networks at once
- ~40x faster for a directed network of 400 nodes
Time the old and the new version on the same input, and give a rounded figure as ~40x, a range as ~40-140x, or a lower bound as >1000x. Name the input the figure was measured on, since the speed-up usually grows with the size of the network.
Name a function by the generic, e.g. net_modes(), where the change reaches every class it dispatches on. Where it reaches only one method, spell that method out in full, e.g. net_modes.igraph(), so that a reader knows which classes the change applies to.
Keep every bullet to one line of fewer than 81 characters ideally (a few more or less is fine). If a bullet wraps, it holds too much: shorten it, or split it into a lead bullet and sub-bullets. Each bullet stands on its own, and states what changed, not why or how unless there is space for context. Explanation belongs in the function documentation or the vignettes.
Where several bullets describe parallel changes, reuse the sentence structure, so that a reader sees the parallelism at a glance. Use one word for one thing throughout a version’s entries, rather than varying the wording for effect.
If a cited GitHub issue was not authored by @jhollway, thank the author with an @-tag in the bullet. Cluster related changes (e.g. several fixes to the same function, or sub-points of one feature) as indented sub-bullets under a lead bullet, to improve readability. Where several changes concern one function, lead with an Improved ... bullet that names the function, and put the individual Fixed .../Added ... points beneath it, so the cluster groups by function rather than by change type. Under an Improved ... lead bullet, do not name the function again in the sub-bullets, since the lead bullet already carries it. Sub-bullets indent by two spaces, and nest at most one level further (four spaces). A sub-bullet does not need a verb: it can state the consequence, the previous behaviour, or an example call. The more entries a version holds, the more this structure matters, so group first and only then write the bullets.
main is the release branch; develop is the working branch (clone/work on develop).breaking runs alongside develop and holds the changes that must wait. Put a change on breaking, not develop, where it would break a released downstream package (netrics, autograph, migraph), e.g. a change to the class or contents of shipped data or to what a function returns. Record it under the heading for the version it waits for in NEWS.md on breaking, which is the first patch or minor release after the downstream packages can take it, and say there which release of which package it waits for. Bug fixes and other non-breaking changes still go on develop, which is merged into breaking regularly to keep the two in step.main trigger prchecks.yml: R CMD check (macOS/Windows/Linux), binary build, codecov, lintr, spell check, a reverse-dependency check, a check that the tutorial articles are in sync with the tutorials, and PR metadata checks (DESCRIPTION version bump, PR title/description conventions).main trigger pushrelease.yml: check, auto-bump version tag, GitHub release with binaries, then pkgdown site deploy.manynet is the data layer under netrics, autograph, and migraph, so a change here can strand their users until their own next release. Before committing a change to shipped data, to a class, or to what a function returns:
R CMD INSTALL --library=<lib> manynet_<version>.tar.gz.R_LIBS=<lib> Rscript -e "devtools::test('<path to netrics>', stop_on_failure = FALSE)", and their examples and tutorials, since those are checked on CRAN too.develop, so that a failure that was already there is not taken for a new one.R/ code is a real break: the change waits on breaking until that package is fixed and released. A failure in its tests/ is usually an expectation to update there.The Reverse dependencies job in prchecks.yml only checks that the CRAN releases still find every manynet object they use. It does not run their tests or examples, so it does not replace this check.
Once the pull request into main passes its checks:
Version in DESCRIPTION equals the newest heading in NEWS.md, and that every bullet under it describes something a user can see.R CMD check --as-cran --run-donttest on it. Read every note.R CMD check on each with the new manynet first in the library path. CRAN runs the same check, and a failure there stops the submission.manynet (>= x.y.z)), so that CRAN never pairs it with an older one.cran-comments.md from the results of these checks, not from the last release: the environments that were really tested, the counts of errors, warnings, and notes, the full text of each note with a sentence on why it is acceptable, and the result for each reverse dependency.devtools::submit_cran(), and tag the release only once CRAN has accepted it, since the version may have to move if CRAN asks for changes.stocnet projects are maintained using the git version control system. A plain-English introduction to git can be found here, and a more recent motivation here. They explain the basics of git version control: committing and repos, pulling and pushing, branching and merging.
Using git from the command line can be intimidating, so I recommend Fork software for Mac and Windows, which allows mostly visual management of commits, diffs, and branches.
develop branch.NEWS.md bullet (see above), with the issue it relates to.