badges/shields

Change to GitHub workflow badge routes

chris48s opened this issue ยท 54 comments

๐Ÿฅฑ TL;DR

If you have a github workflow .github/workflows/test.yml

name: Run Tests
...

You need to update your badge URL from

https://img.shields.io/github/workflow/status/<user>/<repo>/Run%20Tests
to
https://img.shields.io/github/actions/workflow/status/<user>/<repo>/test.yml?branch=main

  • The key change here is that the workflow parameter is now the workflow filename, not the name: defined in yaml
  • We also recommend specifying the branch param in most cases, although it is not required.

If a branch param is not supplied the badge will look first for builds on your default branch and then fall back to the latest build on any branch or ref if none are found on the default branch. This is mainly useful for "branchless" worfklows (like workflows that runs against a tags or release).

If your workflow is in a subdirectory under .github/workflows, include the subdir in the route.

https://img.shields.io/github/actions/workflow/status/<user>/<repo>/sub_directory/test.yml?branch=main

Note that the workflow filename/path is case sensitive.

โ“ Why are we making this change?

This change resolves the problem reported in #8146 Some users were reporting that our badges were reporting incorrect or unexpected values in some situations.

After consulting with GitHub support, it transpired that identifying workflows using the name in the yaml file can be ambiguous in some situations and defaults to finding workflows on any branch when a branch param is not specified, rather than the default branch. Switching to identifying workflows by the workflow filename and making branch a required parameter resolves these problems. Two workflows can have the same name string in yaml, but filename is unique on a given branch. GitHub themselves have quietly switched their own native badges to using this method.

We decided that dropping the old badges (using the workflow name) and requiring users to switch to the new URLs (rather than keeping the old ones "working") was the right choice for our users because in some cases the old badges were serving data which was inaccurate or unexpected in subtle ways. Serving accurate data is the most important thing for us to prioritise.

๐Ÿ˜ญ You made a breaking change! Waa

We know. We try never to do this and it is not a decision we took lightly, especially given this is one of our highest traffic badges. In general, our philosophy is: If you embedded a shields badge in your README in 2013 and the upstream service is still online, that badge should still work today. We achieve this with almost no exceptions.

Occasionally we do need to change badge routes for various reasons, but usually we keep old URLs working using redirects. In this case, it was not possible to provide a transition because the new badge route uses a different parameter.

One of the reasons we try to never do this is because we don't really have a great way to communicate a breaking change to our users or provide warning before it happens. We have no idea who uses our service. We don't ask anyone to sign up, we don't track you. Hopefully given that constraint we have done a reasonable job of this.

๐Ÿ“š Further Reading

I got the same issue with a worflow.yml

You need to update your badge URL from

https://img.shields.io/github/workflow/status/<user>/<repo>/Run%20Tests to http://img.shields.io/github/actions/workflow/status/<user>/<repo>/test.yml?branch=main
...
If your workflow is in a subdirectory under .github, include the subdir in the route.

http://img.shields.io/github/actions/workflow/status/<user>/<repo>/sub_directory/test.yml?branch=main

@chris48s change http to https

jshor commented

I can't seem to get the badge URL to work for Datebook. The workflow file is under .github/workflows/merge.yml and I specified the URL to include the workflows subdirectory, but it shows with "Repo or workflow not found." Even after excluding /workflows from the URL, the issue persists.

The URLs I've tried:

https://img.shields.io/github/actions/workflow/status/jshor/datebook/workflows/merge.yml?branch=main
https://img.shields.io/github/actions/workflow/status/jshor/datebook/merge.yml?branch=main

Same issue as @jshor for https://github.com/pftf/RPi4.

We do have a .github/workflows/linux_edk2.yml on the master branch, yet the URL https://img.shields.io/github/actions/workflow/status/pftf/RPi4/linux_edk2.yml?branch=master (the exact URL we use for the image below) produces Repo or workflow not found:

badge

The only thing I can see that might have had an impact is that we forced a commit and deleted the build run that was associated with the commit that was overridden, but the old badge URL scheme seemed to have no issue with that.

@jshor @pbatard - you're both seeing that badge because GitHub's API is reporting that there are no runs for either of your respective branches

https://api.github.com/repos/jshor/datebook/actions/workflows/merge.yml/runs?branch=main
https://api.github.com/repos/pftf/RPi4/actions/workflows/linux_edk2.yml/runs?branch=master

Would encourage you both to double check your repos and re-run the respective workflow for your target branches, or consider using a different branch filter in your badge url

@calebcartwright,

Thanks for replying, but I'm afraid the GitHub web UI does report plenty of runs for the relevant branch:
https://github.com/pftf/RPi4/actions/workflows/linux_edk2.yml

I really have no clue why https://api.github.com/repos/pftf/RPi4/actions/workflows/linux_edk2.yml/runs?branch=master reports no runs whereas https://github.com/pftf/RPi4/actions/workflows/linux_edk2.yml does report runs, and these runs are being enacted on the master branch.

I've also found quite a few more repos with the same issue, and again, these are repos that worked fine with the previous badge scheme:

  • https://img.shields.io/github/actions/workflow/status/pftf/RPi3/linux_edk2.yml?branch=master
  • https://img.shields.io/github/actions/workflow/status/pbatard/UEFI-Shell/linux_gcc_edk2.yml?branch=main

I asked a similar question at #8719. After looking at my workflows, is it possible this status is being returned due to the workflow not having a branch filter? I know that the badges that GitHub provides return nothing for workflows that have no branch filters if a branch parameter is passed in the URL.

@pbatard is my above comment relevant? Perhaps both Github and Shields.io require a branch filter in the workflow to recognize the branch parameters?

@StormFX, in that case I would say that it's api.github.com that needs to be fixed, because it should report runs for the default branch even if the branch was not explicitly specified.

Otherwise, not only do we have to update the badges URLs, but we also have to update the workflows themselves and run them again? Talk about double, if not triple stabbing...

I'm just saying if the badge API requires a branch parameter and the workflows don't specify a branch, that could be why we're seeing that status. Github badges correctly assume the default branch if no branch parameter is specified in the URL and no branch filter is used, but return no status if one is specified in the URL, but not the workflow. So perhaps Shields.io needs a similar fallback. Otherwise, all workflows will be required to have a branch filter.

FWIW: Not even sure if this is the issue. Just throwing it out there.

Okay. I guess we agree that whatever we're experiencing here looks like a bug/regression that either GitHub or Shields.io should fix, and not the project owners.

GitHub is working correctly. I'm not sure if it's part of some "best practices" to always use a branch filter. If Shields.io requires a branch parameter, users will be required to include a branch filter in their workflows. That is, of course, assuming that this is the issue. I haven't tested it yet.

Though ideally, Shields.io would function in the same way that GitHub does, since that seems to be the direction it's gone anyhow.

Edit: I forgot to mention, I'm using reusable workflows, though I don't think that's relevant since GitHub badges work correctly.

Well it looks to me like GitHub needs to have a https://api.github.com/repos/pftf/RPi4/actions/workflows/linux_edk2.yml/runs?branch=(default) that will return the same runs I can see from https://github.com/pftf/RPi4/actions/workflows/linux_edk2.yml, so that Shields.io, and its downstream users, can use the same scheme and get the badge working without being forced to modify all their workflows and re-run them just to get the badge not to display an error.

Would it be possible to remove the branch parameter requirement? I've got a workflow that triggers on tags and it now permanently shows failed. Directly querying the badge.svg url without the branch parameter displays a passing status though.

Edit: Scrolling back up, I see that there was a potential issue with the API. I was able to query the workflow runs on the latest version of the API (2022-11-28) without specifying a branch. Example

@pbatard Ah. I wasn't aware that this was a restriction in GitHub's API.

For anyone else stumbling upon this, I have a quick and dirty sed command that seems to work reasonably well:

find . \
  -type f -name '*md' ! -path "./.*" \
    | xargs sed -i -E 's/https:\/\/img.shields.io\/github\/workflow\/status\/([a-zA-Z0-9_-]+)\/([a-zA-Z0-9_-]+)\/([a-zA-Z0-9_-]+)\/([a-zA-Z0-9_-]+)\?(.*)/http:\/\/img.shields.io\/github\/actions\/workflow\/status\/\1\/\2\/\3.yaml\?branch=\4\&\5/g'

Note this requires that your url fits the format:

# captures groups:
# 1: user
# 2: repo
# 3: job name
# 4: branch name
# 5: rest
https://img.shields.io/github/workflow/status/([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)?(.*)

And also assumes:

  • job name = file name
  • branch is explicitly listed

E.g.

# before
https://img.shields.io/github/workflow/status/user/repo/job/branchName?label=blah&labelColor=2f353c

# after
http://img.shields.io/github/actions/workflow/status/user/repo/job.yaml?branch=branchName&label=blah&labelColor=2f353c

I am certainly not a sed/bash wizard, so YMMV. Adapt as needed.

Looking into this further, I think the core of the issue is that the GitHub API is broken when it comes to identifying branches.

When looking at the first workflow run of https://api.github.com/repos/pftf/RPi4/actions/workflows/linux_edk2.yml/runs (for the problematic badge I mentioned above), the API returns head_branch "v1.34". Yet there exists no such git branch in the repository of https://github.com/pftf/RPi4 (there's only one branch, and that is the master one).

On the other hand, for projects where the badge is working, the API returns head_branch "main" or head_branch "master" as expected.

So, for some weird reason, the GitHub API misreports a git tag as a git branch, and this appears to be the root of the issue.

It therefore looks to me like GitHub need to fix their API to ensure that what it reports as a branch is actually a branch.

One of the reasons we try to never do this is because we don't really have a great way to communicate a breaking change to our users or provide warning before it happens. We have no idea who uses our service. We don't ask anyone to sign up, we don't track you. Hopefully given that constraint we have done a reasonable job of this.

You've done a great job and thank you for your work โค๏ธ

@calebcartwright,

Thanks for replying, but I'm afraid the GitHub web UI does report plenty of runs for the relevant branch:
https://github.com/pftf/RPi4/actions/workflows/linux_edk2.yml

@pbatard - perhaps I'm missing something, but as far as I can tell it definitely does not and this is ostensibly because you have structured your workflow to only run against tags:

https://github.com/pftf/RPi4/blob/cbdf29976acc3cff38093e61adcab6ab618ecc1b/.github/workflows/linux_edk2.yml#L6-L9
https://github.com/pftf/RPi4/actions/workflows/linux_edk2.yml?query=branch%3Amaster

image

Would it be possible to remove the branch parameter requirement?

We'll definitely discuss and consider adding a mechanism for folks to request a ref-less badge from us, assuming the GitHub API will cooperate

I also just want to add that we know it's frustrating to have to update badge URLs, and even more so when it's not quite working the way you want.

We didn't go down this route simply for fun nor to cause churn; Shields is completely reliant on upstream providers (GitHub in this instance) to get data, and in this case we discovered, and GitHub confirmed, that the endpoint we'd been previously using was unreliable, commonly producing specious results, and as such GitHub no longer supports/advertises it. We don't have any control nor influence over GitHub, so if anyone thinks changes are needed in GitHub's API surface that's best reported to them through the channels they monitor.

We'll definitely discuss and consider adding a mechanism for folks to request a ref-less badge from us, assuming the GitHub API will cooperate

Thanks! In my limited testing (running it through Insomnia), I was able to get it to return the workflow runs as expected.

image

@calebcartwright,

as far as I can tell it definitely does not

But how could it run against anything but the master branch when it's the only branch that exists?
I don't see how tags and branches are mutually exclusive here. If there's only one branch, it doesn't suddenly vanish because you created a tag.

The way I see it, logically, is that tagged commits are a subset of commits from a branch, therefore, when querying said branch, they should be listed.

Otherwise, this whole new naming scheme (as well as the GitHub API) look fundamentally broken, because suddenly, and as wasn't the case before, anyone who invokes Actions on tag must update their badge for each new tag (since I assume the "branch" name that should be passed to the Shields.io URL then is the tag name)...

because you have structured your workflow to only run against tags

Like many others, yes. With the logical assumption that a tag applies to a commit and that a commit belongs to a branch, therefore a tag does belong to a branch and the GitHub API or Shields.io should recognise that.

As you may appreciate, most of the people who run builds against tags are not going to be interested in a lengthy debate about whether a tagged commit should suddenly become its own individual standalone branch because X, Y and Z. Instead, they're going to go for the completely logical view that a tag applies to a commit and a commit belongs to a branch, and thus, a tagged build should be resolved by default as belonging to the branch, be it only in the limited view of resolving builds pertaining to a specific branch to produce a shield, even more so as we are talking about regressive behaviour that can be fixed:

  1. Query GitHub API for the branch and see if there were any builds. Store the timestamp of the most recent.
  2. Query GitHub API for tags and see if there were any that produced any builds. Store the timestamps of the most recent(s).
  3. If timestamp(s) from 2 is/are more recent than timestamp from 1 (or is there were no results from 1) look at the commit SHA from the most recent(s) and find out if it/any belong(s) to the branch specified by the user.
  4. If it/one is found to belong to the branch specified, and more recent than any timestamp found at 1, use this build for the shield. If not, use the build from 1 for the shield (or report no builds if there are no matches).

From where I stand, this regression can be resolved without forcing users to do some unexpected incantation magic if building on tags, especially if it's one that either needs to be changed for each tag, or requires updating the workflows. A tag does not make the association of a commit with a branch magically disappear.

PS: In case I sound a bit flippant, I will state that I don't have a problem with updating the shields URLs. As a matter of fact, I think Shields.io did handle it pretty well, by pointing straight to an issue that explained how one should go about changing the URL. What I do have a problem with is the regression that was introduced in the process because shields against workflows that only run on tagged releases are now broken even after updating the URL, and, from where I stand, I do believe this can be fixed without asking users to update anything else but the URL. I also don't have a problem with this fix taking time, as long as this can be resolved with a simple URL change that will persist between subsequent builds.

perhaps I'm missing something, but as far as I can tell it definitely does not and this is ostensibly because you have structured your workflow to only run against tags:

For what it's worth, it's not unheard of to use workflows that don't use a branch filter, especially in the case of repos with only a single branch. Using the above example, you can see that a GitHub badge shows correctly when no branch is specified:

https://github.com/pftf/RPi4/actions/workflows/linux_edk2.yml/badge.svg

Furthermore, the badge documentation's first example is of such a badge. Branch/event parameter examples are given as a way to further filter a specific workflow run. Even the workflow run documentation has examples of using only the push event to trigger a run with examples of filtering by branch, etc for fine tuning when the workflow runs. But such filtering is not always necessary and, if only for the sake of parity, it makes sense for Shields.io to behave similarly.

Thanks for all your hard work! <3

@calebcartwright,

as far as I can tell it definitely does not

But how could it run against anything but the master branch when it's the only branch that exists? I don't see how tags and branches are mutually exclusive here. If there's only one branch, it doesn't suddenly vanish because you created a tag.

The way I see it, logically, is that tagged commits are a subset of commits from a branch, therefore, when querying said branch, they should be listed.

Otherwise, this whole new naming scheme (as well as the GitHub API) look fundamentally broken, because suddenly, and as wasn't the case before, anyone who invokes Actions on tag must update their badge for each new tag (since I assume the "branch" name that should be passed to the Shields.io URL then is the tag name)...

because you have structured your workflow to only run against tags

Like many others, yes. With the logical assumption that a tag applies to a commit and that a commit belongs to a branch, therefore a tag does belong to a branch and the GitHub API or Shields.io should recognise that.

As you may appreciate, most of the people who run builds against tags are not going to be interested in a lengthy debate about whether a tagged commit should suddenly become its own individual standalone branch because X, Y and Z. Instead, they're going to go for the completely logical view that a tag applies to a commit and a commit belongs to a branch, and thus, a tagged build should be resolved by default as belonging to the branch, be it only in the limited view of resolving builds pertaining to a specific branch to produce a shield, even more so as we are talking about regressive behaviour that can be fixed:

1. Query GitHub API for the branch and see if there were any builds. Store the timestamp of the most recent.

2. Query GitHub API for tags and see if there were any that produced any builds. Store the timestamps of the most recent(s).

3. If timestamp(s) from 2 is/are more recent than timestamp from 1 (or is there were no results from 1) look at the commit SHA from the most recent(s) and find out if it/any belong(s) to the branch specified by the user.

4. If it/one is found to belong to the branch specified, and more recent than any timestamp found at 1, use this build for the shield. If not, use the build from 1 for the shield (or report no builds if there are no matches).

From where I stand, this regression can be resolved without forcing users to do some unexpected incantation magic if building on tags, especially if it's one that either needs to be changed for each tag, or requires updating the workflows. A tag does not make the association of a commit with a branch magically disappear.

PS: In case I sound a bit flippant, I will state that I don't have a problem with updating the shields URLs. As a matter of fact, I think Shields.io did handle it pretty well, by pointing straight to an issue that explained how one should go about changing the URL. What I do have a problem with is the regression that was introduced in the process because shields against workflows that only run on tagged releases are now broken even after updating the URL, and, from where I stand, I do believe this can be fixed without asking users to update anything else but the URL. I also don't have a problem with this fix taking time, as long as this can be resolved with a simple URL change that will persist between subsequent builds.

As already stated in #8671 (comment), the Shields team will have an internal discussion about how to support this use case, the resolution of which would give you what you want: a badge that reflects the most recent status of a workflow run independent of the git ref that workflow ran against (regardless of whether that ref was a tag or a branch, which GitHub Actions rightly recognizes as different entities).

These messages are indeed coming across a bit flippant, and I don't think any back and forth is going to be particularly constructive. There's multiple reasons why your proposed options aren't viable, but there are some other approaches that are and the end result is all that folks should really care about.

We'll post an update when we have one

So https://img.shields.io/github/workflow/status/trufflesuite/ganache/Commits/develop?event=push is breaking because in the future, there could be multiple Actions that subscribe to push events? I don't think this repo has multiple push events on the develop branch, so this badge really couldn't have been incorrect, right?

From what I can tell, this breaking change is a bit overreaching, as there are likely many repositories that were _veritably _ safe from this ambiguity. Or am I wrong?

It appears some things have happened while I was asleep/at work.

Just a quick post to acknowledge I've seen all this and will attempt to digest it all over the weekend.

Also thanks to all those who are keeping the conversation around this constructive โค๏ธ

I'll also just echo @calebcartwright 's comment

just want to add that we know it's frustrating to have to update badge URLs, and even more so when it's not quite working the way you want.
We didn't go down this route simply for fun nor to cause churn

QFT ๐Ÿ‘

Branch is now a required query param

rather than the default branch

@chris48s is there an explicit way to specify the default branch? That's actually what we want, since we update the default branch several times a year, and it will be pretty tedious to have to update the badge URL manually every time. I tried branch=default but that did not work.

@jshor - Looking at your repo, it looks like your workflow is set to run on pushes to master:
https://github.com/jshor/datebook/blob/main/.github/workflows/merge.yml#L3-L6
which is why calling https://img.shields.io/github/actions/workflow/status/jshor/datebook/merge.yml?branch=main (with branch=main) doesn't find anything.
Switching to https://img.shields.io/github/actions/workflow/status/jshor/datebook/merge.yml?branch=master should pick up your builds: https://github.com/jshor/datebook/actions/workflows/merge.yml

@StormFX and @pbatard
You've got workflows running on push to a tag, so filtering by branch doesn't make sense for this case. We're not 100% sure what the solution is for this case yet, but we're thinking about it and it is a legitimate issue. Just to make this easier to track, I've made an issue from @StormFX 's discussion over at #8736 . Lets continue to track this specific issue there. It is too hard to keep track of the conversation when the posts are buried in the middle of

Screenshot at 2022-12-16 21-53-04

If anyone else is watching for updates on that, follow #8736

it seems like now, it will show things like "build:in progress". is it possible to just show whether last completed build was green or failed?

@chris48s Unfortunately, it does not seem this fix is working in all cases. When you release via the GitHub UI, it creates a new tag for every release. Looking at the action log, every tag becomes a branch in the workflow actions.

So the badge does not work with the branch set to main. It creates an error branch or event not found. When replacing the branch with the version tag e.g. v00.19.00 it works but now the shield syntax is tied to one specific version tag and would need to be changed manually for every new release.

Example seen here: https://github.com/fxstein/GoProX

@fxstein - follow #8736 for discussion of this

Hi, I'm still having trouble with link. Here's the badge:

Build Status

The URL: https://img.shields.io/github/actions/workflow/status/diba-io/bitmask-core/.github/workflows/rust.yaml?branch=development&style=flat-square

The YAML file is here: https://github.com/diba-io/bitmask-core/blob/development/.github/workflows/rust.yaml

What am I doing wrong?

Hi, I'm still having trouble with link. Here's the badge:

The only thing I see that might be wrong is that you shouldn't have to use .github/ in the route, according to the information above. But your primary issue is related to #8736.

The red warning badge seems to break the README.md in old releases (where the contents of README.md is copied to i.e. the package repository landing page for that particular release).

Any chance we can revert this warning after a few weeks and unbreak these please? I feel like I've been egged.

I cannot figure out how to make it work. The ci/cd file is placed in the default place. Could any one help?

![](https://img.shields.io/github/actions/workflow/status/farag2/Sophia-Script-for-Windows/Sophia.yml?branch=master&label=GitHub%20Actions&logo=GitHub)

I cannot figure out how to make it work. The ci/cd file is placed in the default place. Could any one help?

You're having the same issue as others. See #8736. You have two options:

  1. Wait until #8736 is addressed (recommended, see below)
  2. Update your workflow to use a branch filter

Do note that if you go with 2, workflow runs executed without a filter (previous runs) may not be listed with runs executed with a filter (new runs), as the API filters them.

Just wanted to say: I admire the way you handled this! Having the URL for the issue in the broken badge is very clever.

Thanks for providing this service!

How do we now handle "branchless" workflows?

For example, if you have an action that triggers on:release it's associated with the release tag and not a specific branch, which means you can't use it, even if the release targets a specific branch, because it will change with every release.

e.g.

This works: This https://img.shields.io/github/actions/workflow/status/linuxserver-labs/docker-omada-controller/call-build-image.yml?branch=v5.7.4-ls34

But this doesn't: This https://img.shields.io/github/actions/workflow/status/linuxserver-labs/docker-omada-controller/call-build-image.yml?branch=main

  "tag_name": "v5.7.4-ls34",
  "target_commitish": "main",
  "name": "v5.7.4-ls34",

How do we now handle "branchless" workflows?

See #8736.

For the people in this thread who were affected by not being able to supply a branch param for their workflow, we've dropped the requirement that branch must be supplied. I've updated the guidance in the top post accordingly.

Thanks a lot, @chris48s!

After updating my badges to the new method, my sphinx documentation (Read the docs) fails to build the pdf version.

I get an error about unknown mimetype.

WARNING: unknown mimetype for _images/CI.yml, ignoring
WARNING: unknown mimetype for _images/localize.yml, ignoring

While, just a "warning" the pdf build completely fails.

@ReenigneArcher as a workaround: if you switch your URLs to use the optional .svg extension, does that solve your problem?

i.e: if you currently have

https://img.shields.io/github/actions/workflow/status/badges/shields/test-lint.yml
switch it to
https://img.shields.io/github/actions/workflow/status/badges/shields/test-lint.yml.svg

if you switch your URLs to use the optional .svg extension, does that solve your problem?

That appears to resolve the build error. Thank you!

just a note, if the workflow yml file is in the subdirectory workflows under .github, you do NOT need to indicate that subdirectory. yml files in that subdirectory will be found correctly.

tkem commented

just a note, if the workflow yml file is in the subdirectory workflows under .github, you do NOT need to indicate that subdirectory. yml files in that subdirectory will be found correctly.

Thanks to @JohnRDOrazio, may I suggest this comment is added to the issue's description...

I've made a couple of edits to the top post to clarify the latest point on subdirs

farag2 commented

@Skillnter, you have a typo in main,yml. You used a comma.

Here's the working code: https://img.shields.io/github/actions/workflow/status/skillnter/http-response-status-code/main.yml

Hmm now that the old url is not available anymore

I tried the new url but get an error
Old url (https://img.shields.io/github/workflow/status/spatie/image/run-tests?label=tests)
GitHub Workflow Status
New url (https://img.shields.io/github/actions/workflow/status/spatie/image/.github/workflows/run-tests?label=tests)
GitHub Workflow Status

Edit: ok got it, it was missing the yml extension (also removed the subdir)

GitHub Workflow Status

Hmm now that the old url is not available anymore

I tried the new url but get an error Old url (https://img.shields.io/github/workflow/status/spatie/image/run-tests?label=tests) GitHub Workflow Status New url (https://img.shields.io/github/actions/workflow/status/spatie/image/.github/workflows/run-tests?label=tests) GitHub Workflow Status

You aren't using the new url correctly

https://img.shields.io/github/actions/workflow/status/spatie/image/run-tests.yml?label=tests

As noted in the issue description, the new route uses the file name (including the extension), and the .github/workflows path is unnecessary and should be elided (all workflows have to be somewhere under there); pathing is only necessary if your workfile file resides in a subdirectory under .github/workflows

This can probably be closed. If people have noticed this in over a year, they're probably not going to.

Yeah it has probably done its job at this point