ResearchSoftwareMetadata is a Julia package that
provides a crosswalk between Project.toml, codemeta.json, .zenodo.json and the package LICENSE file, giving a consistent way of providing metadata for research software, so that the Julia General Registry, GitHub and Zenodo all pick up the same metadata, following the Research Software MetaData guidelines.
The package is registered in the General registry so can be
built and installed with add. For example:
(@v1.12) pkg> add ResearchSoftwareMetadata
Resolving package versions...
Updating `~/.julia/environments/v1.12/Project.toml`
[58378933] + ResearchSoftwareMetadata v0.4.0
Updating `~/.julia/environments/v1.12/Manifest.toml`
(@v1.12) pkg>The crosswalk runs on a package that is a git repository with a remote. The one piece of metadata it cannot do without is a license. To capture the license you are using and propagate it throughout the metadata files and through your julia code, add an SPDX license identifier to your Project.toml file:
license = "BSD-2-Clause"A package has to have a license: the crosswalk stops with an error if it finds none, or one that is not an identifier from that list. You can also set the license when you run the crosswalk, as shown below.
If the package has no license file, the crosswalk writes a LICENSE for that license, naming the people in the authors field of Project.toml as the copyright holders, so make sure authors is right first. A license file you already have is left exactly as it is, provided it holds that license.
The crosswalk records the license on the first line of every julia file, as # SPDX-License-Identifier: BSD-2-Clause. If some files are deliberately under a different license, give each of them its own first line naming that license, and list those licenses in the [rsmd] table described below, so that the crosswalk knows they are intended and leaves them alone:
[rsmd]
additional_licenses = ["MIT"]A file marked with a license that is neither the package's nor in that list stops the crosswalk with an error.
Then, from the root of your package, you can just run a crosswalk:
using Pkg
# Create a new project with ResearchSoftwareMetadata in it
Pkg.activate(temp = true)
Pkg.add("ResearchSoftwareMetadata")
# Carry out a crosswalk between the different metadata formats
using ResearchSoftwareMetadata
ResearchSoftwareMetadata.crosswalk()The first crosswalk writes codemeta.json and .zenodo.json, and creates an [rsmd] table in Project.toml, which is where all of the other metadata that this package uses lives. It warns about whatever it still needs for a complete record: work through those warnings as described below, running the crosswalk again until there are none.
The crosswalk makes an [[rsmd.author_details]] block for each person in the authors field. To supplement the metadata on the authors of the package, add to those blocks the ORCID for each author and the ROR for the organisation(s) they are affiliated with. You can add as many authors and as much or as little information as you like about each one by adding additional [[rsmd.author_details]] blocks.
[rsmd]
[[rsmd.author_details]]
name = "Richard Reeve"
orcid = "0000-0003-2589-8091"
[[rsmd.author_details.affiliation]]
ror = "00vtgdb53"The crosswalk warns until the package has a description and the software category it belongs to. You can also add keywords associated with the package, its repostatus.org development_status, and the DOIs of any publications associated with it; if you do not, the keywords start as ["julia"] and the development status as "active". All of these are propagated into codemeta.json and .zenodo.json, and any values already in codemeta.json but missing from Project.toml will be backfilled into it. Any of these keys found at the top level of Project.toml (the old layout) are automatically migrated into [rsmd]:
[rsmd]
keywords = ["julia", "metadata"]
category = "metadata"
description = "A package that does things"
development_status = "active"
publications = ["10.5281/zenodo.12789179"]The crosswalk also warns until it has been told where the build instructions for the package are, which you do once, when you run it: build = true if they are in the README, or their address if they are somewhere else.
If you want to pass in some additional metadata (the category of the software or the keywords associated with it, both of which are written back into [rsmd] in Project.toml, or its license), or you want to increase the package version during the crosswalk, you can do that as follows:
# Say that the build instructions are in the README
ResearchSoftwareMetadata.crosswalk(build = true)
# Add in additional metadata
ResearchSoftwareMetadata.crosswalk(category = "metadata", keywords = ["julia", "metadata", "research software", "RSMD"])
# Set the license, or change it
ResearchSoftwareMetadata.crosswalk(license = "BSD-2-Clause")
# Increase version number during crosswalk
ResearchSoftwareMetadata.increase_patch() # Bump patch version (e.g. 0.4.1 -> 0.4.2)
ResearchSoftwareMetadata.increase_minor() # Bump minor version (e.g. 0.4.2 -> 0.5.0)
ResearchSoftwareMetadata.increase_major() # Bump major version (e.g. 0.5.0 -> 1.0.0)If you later change the metadata in Project.toml on purpose (a new description or keywords, a removed author, a different license), run the crosswalk with update = true so that it knows the change is intended:
ResearchSoftwareMetadata.crosswalk(update = true)The change is then carried into the other files and reported as information. Without update = true the crosswalk treats a disagreement between Project.toml and the other files as a possible mistake: it still brings the other files into line, but reports each change as a warning or an error, and it refuses a changed license altogether, rewriting nothing, because a license should never change by accident. The increase_patch(), increase_minor() and increase_major() functions run the crosswalk with update = true themselves.
To move a package to a different license, or to start again when its licensing has got into a tangle, use relicense!:
# Move the package to a new license
ResearchSoftwareMetadata.relicense!("MIT")
# Put everything under the new license, whatever it was under before
ResearchSoftwareMetadata.relicense!("MIT", overwrite_all = true)The first form is the same as crosswalk(license = "MIT"): files listed under additional_licenses keep their own license, and a file marked with a license you have not declared still stops it. The second form overrides all of that: it removes additional_licenses, replaces every license file with a newly written LICENSE, and marks every julia file with the new license. It relabels files whoever wrote them, so make sure you are entitled to relicense them first.
You might also consider reformatting all of your julia code to a consistent format. A .JuliaFormatter.toml file in the package root defines what the formatting standard should be. From the root of your package:
Pkg.add("JuliaFormatter")
using JuliaFormatter
format(".")You can also make your package's own test suite check automatically that the metadata crosswalk is clean and the code is well formatted, by copying a few files from this package's test/ directory into your own. See Automated package checks in the documentation for instructions.