Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
101 changes: 101 additions & 0 deletions .github/workflows/dependents.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Dependents: test the packages that depend on this one with this branch in its place, so that a release that would break them is seen before it's registered.
# Called from the repository's own workflow, on pull requests into the main branch, and by hand:
#
# on:
# pull_request:
# branches: [main]
# workflow_dispatch:
# jobs:
# dependents:
# uses: BioJulia/Workflows/.github/workflows/dependents.yml@v1
# permissions:
# contents: read
# with:
# dependents: |
# BioJulia/BED.jl
# BioJulia/GFF3.jl
#
# Each dependent is checked out at its default branch, this branch's package takes the place of the registered one in the dependent's project, and the dependent's tests run, as the check "dependents / <repository>".
# A breaking release is expected to break its dependents until they adapt, so the checks report rather than block, unless a ruleset requires them.
name: "Reusable: Dependents"

on:
workflow_call:
inputs:
dependents:
description: The repositories of the packages that depend on this one, such as `BioJulia/BED.jl`, one per line or separated by commas.
type: string
required: true
project:
description: The package's directory, relative to the repository's root, for a package in a subdirectory.
type: string
default: ''
julia-version:
description: The version of Julia to test with.
type: string
default: '1'

permissions: {}

jobs:
list:
name: Dependents
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.list.outputs.matrix }}
steps:
- name: List the dependents
id: list
env:
DEPENDENTS: ${{ inputs.dependents }}
run: |
set -euo pipefail
# One repository per line or separated by commas, each `owner/name`, without duplicates.
repositories=$(printf '%s\n' "$DEPENDENTS" | tr ',' '\n' | sed 's/^[[:space:]]*//; s/[[:space:]]*$//' | { grep -v '^$' || true; } | sort -u)
if [ -z "$repositories" ]; then
echo "::error title=Dependents::The input dependents names no repository."
exit 1
fi
while IFS= read -r repository; do
if ! [[ "$repository" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]]; then
echo "::error title=Dependents::$repository isn't a repository, owner/name."
exit 1
fi
done <<< "$repositories"
matrix=$(printf '%s\n' "$repositories" | python3 -c 'import json, sys; print(json.dumps([line.strip() for line in sys.stdin if line.strip()]))')
echo "matrix=$matrix" >> "$GITHUB_OUTPUT"
echo "Testing the dependents $matrix."

test:
name: ${{ matrix.dependent }}
needs: list
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
dependent: ${{ fromJSON(needs.list.outputs.matrix) }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: package
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: ${{ matrix.dependent }}
path: dependent
persist-credentials: false
- uses: julia-actions/setup-julia@da908477b5db94c10ffce8cfea9f2b3b9d5db687 # v3.0.3
with:
version: ${{ inputs.julia-version }}
- uses: julia-actions/cache@9353db09a0f2bbbdec6f41791918c75d37391b36 # v3.5.0
- name: Test the dependent with this package
env:
RELEASEFLOW_PROJECT: ${{ inputs.project }}
run: |
julia --startup-file=no --project=dependent -e '
using Pkg
# This branch takes the place of the registered package, in the dependent'"'"'s project and the projects of its workspace.
Pkg.develop(path = joinpath("package", ENV["RELEASEFLOW_PROJECT"]))
Pkg.instantiate()
Pkg.test()'
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,30 @@ jobs:
RELEASEFLOW_TOKEN: ${{ secrets.RELEASEFLOW_TOKEN }}
```

And the dependents' tests, in `.github/workflows/Dependents.yml`, which run the tests of the packages that depend on this one with the pull request's branch in its place:

```yaml
name: Dependents
on:
pull_request:
branches: [main]
workflow_dispatch:
permissions: {}
jobs:
dependents:
uses: BioJulia/Workflows/.github/workflows/dependents.yml@v1
permissions:
contents: read
with:
dependents: |
BioJulia/BED.jl
BioJulia/GFF3.jl
```

Each dependent is checked out at its default branch, and its tests run as the check `dependents / <repository>`, with `julia-version`, `1` unless given.
A breaking release is expected to break its dependents until they adapt, so whether a ruleset requires these checks is the maintainers' choice; without that, they report what a release would break before it's registered.
A dependent whose project takes the package from a local path, through `[sources]`, tests against that path instead.

OneFlow and trunk, in `.github/workflows/OneFlow.yml` or `.github/workflows/Trunk.yml`:

```yaml
Expand Down Expand Up @@ -121,8 +145,10 @@ A package can follow the major tag, `v1`, or pin a release, such as `v1.0.0`; De
| `skip-label` | `skip changelog` | gitflow, oneflow, trunk | The label that exempts a pull request from the changelog entry. |
| `check-links` | `true` | gitflow, oneflow, trunk | Whether to check the changelog's comparison links. |
| `require-entry` | `true` | trunk | Whether a pull request that isn't a release must add a changelog entry, for a changelog without an unreleased section. |
| `project` | the root | gitflow, back-merge, oneflow, trunk | The package's directory, for a package in a subdirectory, such as `lib/Toy`. |
| `project` | the root | gitflow, back-merge, oneflow, trunk, dependents | The package's directory, for a package in a subdirectory, such as `lib/Toy`. |
| `registry` | `General` | gitflow, oneflow, trunk | The registry of the package's releases. |
| `dependents` | none | dependents | The repositories of the packages that depend on this one, one per line or separated by commas. |
| `julia-version` | `1` | dependents | The version of Julia that the dependents' tests run on. |

For example, `with: { main-branch: master }` for a repository whose main branch is `master`.

Expand Down
1 change: 1 addition & 0 deletions ReleaseFlow/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

- The reusable workflow `tag.yml`, which moves each major tag, such as `v1`, to the newest release of its major version, `vX.Y.Z`, whichever made the tag, TagBot or a maintainer, and whenever, for a repository that callers follow by its major tag; it never moves a major tag backwards, leaves pre-releases out, and reports what it did for each major tag as a notice on the run and a line of the job's summary.
- This repository moves `v1` with it, through `Self-Tag.yml`, once TagBot tags a release `vX.Y.Z`, with `tag_prefix: NO_PREFIX`, in place of `ReleaseFlow-vX.Y.Z`, and with the ReleaseFlow app's token, which the ruleset on `v*` tags lets through; so the workflows' callers get a release once ReleaseFlow's is registered.
- The reusable workflow `dependents.yml`, which runs the tests of the packages that depend on this one, each checked out at its default branch, with the pull request's branch in its place, as the checks `dependents / <repository>`.

## [1.0.1] - 2026-10-20

Expand Down
22 changes: 22 additions & 0 deletions ReleaseFlow/test/dependents.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# The dependents workflow
# -----------------------

@testset "Dependents" begin
directory = mktempdir()
script = joinpath(directory, "step.sh")
write(script, workflow_step("dependents.yml", "List the dependents"))
function list(dependents)
outputs = joinpath(directory, "outputs")
write(outputs, "")
output = IOBuffer()
process = run(pipeline(Cmd(addenv(`bash $(script)`, "DEPENDENTS" => dependents, "GITHUB_OUTPUT" => outputs); ignorestatus = true); stdout = output, stderr = output))
return (code = process.exitcode, output = String(take!(output)), matrix = readchomp(outputs))
end
# One per line or separated by commas, with spaces and duplicates, in order.
result = list("BioJulia/GFF3.jl\n BioJulia/BED.jl, BioJulia/XAM.jl,\n\nBioJulia/BED.jl\n")
@test result.code == 0
@test result.matrix == """matrix=["BioJulia/BED.jl", "BioJulia/GFF3.jl", "BioJulia/XAM.jl"]"""
@test list("Example/Toy.jl").matrix == """matrix=["Example/Toy.jl"]"""
@test fails(list("BioJulia/BED.jl, not a repository"), "not a repository isn't a repository")
@test fails(list(" , \n"), "names no repository")
end
5 changes: 4 additions & 1 deletion ReleaseFlow/test/helpers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,10 @@ end
passes(result) = result.code == 0
fails(result, message) = result.code == 1 && occursin(message, result.output)

# The shell of the step `name` of the workflow `file`: the block after its `run: |`, without its indentation.
# Workflows
# ---------

# The shell of the step `name` of the workflow `file`, in .github/workflows: the block after its `run: |`, without its indentation.
function workflow_step(file, name)
lines = readlines(normpath(joinpath(@__DIR__, "..", "..", ".github", "workflows", file)))
named = findfirst(line -> strip(line) == "- name: $(name)", lines)
Expand Down
1 change: 1 addition & 0 deletions ReleaseFlow/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ include("initial.jl")
include("subdirectory.jl")
include("back_merge.jl")
include("tag.jl")
include("dependents.jl")
Loading