Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/testing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ jobs:
shell: julia --project=docs --color=yes {0}
run: |
using Pkg
Pkg.develop(PackageSpec(path=pwd()))
Pkg.instantiate()
- uses: julia-actions/julia-buildpkg@v1
- uses: julia-actions/julia-docdeploy@v1
Expand Down
13 changes: 12 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# NEWS

- v0.4.0
- Breaking changes
- Licensing now changes only when asked: a license in Project.toml that disagrees with codemeta.json, a license file holding another license, or a source file marked with an undeclared license stops the crosswalk and changes nothing, where these were logged, partly applied or rewritten. Use `update = true`, the new `license` argument or `relicense!()` to change a license, and `additional_licenses` in [rsmd] for files deliberately under another one
- Existing metadata changes once on the next crosswalk: README links become blob/HEAD so that they follow the default branch, macOS runners are reported as macOS, and default keywords and development status are written into [rsmd]
- `crosswalk()` no longer changes the working directory
- Add `relicense!()` to move a whole package to a new license, and a clear error suggesting licenses when a package has none or one that is not an SPDX identifier
- Leave alone a license file the crosswalk did not write, provided it holds the declared license (uses LicenseCheck.jl)
- Read operating systems and the CI workflow from the jobs that run the tests, including reusable workflows
- Cope with SSH remotes, tags that are not releases, empty source files and unreadable metadata files
- Settle everything in a single crosswalk on first use; use UTC dates, and keep the dates of an unreleased version on branches other than the default
- Mark the entry points as public (not exported)
- v0.3.1
- Dependency fix to avoid updating other packages
- v0.3.0
Expand All @@ -13,7 +24,7 @@
- Handle missing ORCID and ROR records without crashing
- Fail on connection errors and unexpected HTTP statuses, writing no files so everything is left in its original state
- Add optional top-level Project.toml keys description, keywords, category, development_status and publications as the source for codemeta.json and .zenodo.json, backfilling them from codemeta.json when absent
- Split the source into separate files and export crosswalk, increase_patch, increase_minor, increase_major
- Split the source into separate files
- Construct a missing author_details section in Project.toml from the authors field and codemeta.json or .zenodo.json when consistent with authors
- v0.1.7
- Bump compat and fix workflows
Expand Down
6 changes: 5 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
name = "ResearchSoftwareMetadata"
uuid = "58378933-4625-47fa-851e-05ee27d397bd"
license = "MIT"
version = "0.3.1"
version = "0.4.0"
authors = ["Richard Reeve <richard.reeve@glasgow.ac.uk>"]

[deps]
Compat = "34da2185-b29b-5c13-b0c7-acf172513d20"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Git = "d7ba0133-e1db-5d97-8f8c-041e4b3a1eb2"
HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
LicenseCheck = "726dbf0d-6eb6-41af-b36c-cd770e0f00cc"
TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6"

[compat]
Compat = "4.10"
DataStructures = "0.17,0.18,0.19"
Dates = "1.6"
Git = "1"
HTTP = "1,2"
JSON = "1"
JuliaFormatter = "2"
LicenseCheck = "0.2"
Logging = "1"
TOML = "1"
YAML = "0.4"
Expand Down
87 changes: 63 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,50 @@ 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.3.0
[58378933] + ResearchSoftwareMetadata v0.4.0
Updating `~/.julia/environments/v1.12/Manifest.toml`

(@v1.12) pkg>
```

## Usage

First you need to add a small amount of additional metadata into your `Project.toml` file.

To capture the license you are using and propagate it throughout the metadata files and through your julia code, add an [SPDX license identifier](https://spdx.org/licenses/) to the file:
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](https://spdx.org/licenses/) to your `Project.toml` file:

```toml
license = "BSD-2-Clause"
```

All of the other metadata that this package uses lives in a single `[rsmd]` table. To supplement the metadata on the authors of the package, add the [ORCID](https://orcid.org) for each author and the [ROR](https://ror.org) 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.
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:

```toml
[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:

```julia
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](https://orcid.org) for each author and the [ROR](https://ror.org) 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.

```toml
[rsmd]
Expand All @@ -50,7 +77,7 @@ All of the other metadata that this package uses lives in a single `[rsmd]` tabl
ror = "00vtgdb53"
```

You can also optionally add a `description` of the package, `keywords` associated with it, the software `category` it belongs to, its [repostatus.org](https://www.repostatus.org) `development_status`, and the DOIs of any `publications` associated with the package. 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]`:
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](https://www.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]`:

```toml
[rsmd]
Expand All @@ -61,40 +88,52 @@ development_status = "active"
publications = ["10.5281/zenodo.12789179"]
```

Then, from the root of your package, you can just run a crosswalk:

```julia
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 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 you want to increase the package version during the crosswalk, you can do that as follows:
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:

```julia
# 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)
```

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.
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:

```julia
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!`:

```julia
# 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:

```julia
Pkg.add("JuliaFormatter")
Pkg.develop("MyPackage")
using JuliaFormatter
using MyPackage
format(MyPackage)
format(".")
```

## Automated checking
Expand Down
10 changes: 5 additions & 5 deletions codemeta.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@
"codeRepository": "https://github.com/boydorr/ResearchSoftwareMetadata.jl",
"name": "ResearchSoftwareMetadata.jl",
"issueTracker": "https://github.com/boydorr/ResearchSoftwareMetadata.jl/issues",
"readme": "https://github.com/boydorr/ResearchSoftwareMetadata.jl/blob/main/README.md",
"buildInstructions": "https://github.com/boydorr/ResearchSoftwareMetadata.jl/blob/main/README.md",
"readme": "https://github.com/boydorr/ResearchSoftwareMetadata.jl/blob/HEAD/README.md",
"buildInstructions": "https://github.com/boydorr/ResearchSoftwareMetadata.jl/blob/HEAD/README.md",
"dateCreated": "2024-07-17",
"operatingSystem": [
"Linux",
"macOS"
],
"version": "v0.3.1",
"dateModified": "2026-07-09",
"version": "v0.4.0",
"dateModified": "2026-10-04",
"datePublished": "2024-07-18",
"downloadUrl": "https://github.com/boydorr/ResearchSoftwareMetadata.jl/archive/refs/tags/v0.3.1.tar.gz",
"downloadUrl": "https://github.com/boydorr/ResearchSoftwareMetadata.jl/archive/refs/tags/v0.4.0.tar.gz",
"license": "https://spdx.org/licenses/MIT",
"author": [
{
Expand Down
3 changes: 3 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
ResearchSoftwareMetadata = "58378933-4625-47fa-851e-05ee27d397bd"

[sources]
ResearchSoftwareMetadata = {path = ".."}
16 changes: 4 additions & 12 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,27 +1,19 @@
# SPDX-License-Identifier: MIT

using Pkg
"ResearchSoftwareMetadata" ∈ [p.name for p in values(Pkg.dependencies())] &&
Pkg.rm("ResearchSoftwareMetadata")
Pkg.develop(url = "https://github.com/boydorr/ResearchSoftwareMetadata.jl.git")

using ResearchSoftwareMetadata
using Documenter

DocMeta.setdocmeta!(ResearchSoftwareMetadata, :DocTestSetup,
:(using ResearchSoftwareMetadata); recursive = true)
:(using ResearchSoftwareMetadata), recursive = true)

makedocs(;
modules = [ResearchSoftwareMetadata],
makedocs(modules = [ResearchSoftwareMetadata],
authors = "Richard Reeve <richard.reeve@glasgow.ac.uk>",
sitename = "ResearchSoftwareMetadata.jl",
format = Documenter.HTML(;
canonical = "https://boydorr.github.io/ResearchSoftwareMetadata.jl",
format = Documenter.HTML(canonical = "https://boydorr.github.io/ResearchSoftwareMetadata.jl",
edit_link = "main",
assets = String[]),
pages = ["Home" => "index.md",
"Automated package checks" => "testing.md"])

deploydocs(;
repo = "github.com/boydorr/ResearchSoftwareMetadata.jl",
deploydocs(repo = "github.com/boydorr/ResearchSoftwareMetadata.jl",
devbranch = "main")
5 changes: 1 addition & 4 deletions docs/metadata.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

using Pkg

# Update Phylo folder packages
# Update the package's own dependencies
Pkg.activate(".")
Pkg.update()

Expand All @@ -21,9 +21,6 @@ end
# Update docs folder packages
Pkg.activate("docs")
Pkg.update()
"ResearchSoftwareMetadata" ∈ [p.name for p in values(Pkg.dependencies())] &&
Pkg.rm("ResearchSoftwareMetadata")
Pkg.develop(path = ".")

# Reformat files in package
using JuliaFormatter
Expand Down
Loading
Loading