Skip to content

Add badges for repo status - #42

Merged
kescobo merged 1 commit into
BioJulia:mainfrom
rasmushenningsson:badges
Aug 18, 2026
Merged

Add badges for repo status#42
kescobo merged 1 commit into
BioJulia:mainfrom
rasmushenningsson:badges

Conversation

@rasmushenningsson

Copy link
Copy Markdown
Contributor

These badges are meant to be used by other BioJulia repos to signal the status of the repo. See #41.

I've just added them to a badges folder here. But if there's any better place to host that gives a better URL to link to, I'm happy to upload them somewhere else.

These badges are meant to be used by other BioJulia repos to signal the status of the repo.
@rasmushenningsson

Copy link
Copy Markdown
Contributor Author

Here's the code used to generate the badges (I've used Claude to generate the code), just so that we can redo it in case we want to update the badges.

// Generates the BioJulia status badges with the helix logo inline.
//
// badge-maker's public API (`makeBadge` from 'badge-maker') rejects `logoWidth`,
// and defaults the logo box to 14x14. The helix is ~2.66:1, so in a square box
// it would letterbox down to ~5px tall. We import the internal renderer directly
// to pass an aspect-correct logoWidth instead.
import { readFileSync, writeFileSync } from 'node:fs'
import makeBadge from '/usr/lib/node_modules/badge-maker/lib/make-badge.js'

const LOGO_HEIGHT = 14 // badge-maker's fixed logo height

const logoSvg = readFileSync(new URL('./assets/biojulia-helix.svg', import.meta.url), 'utf8')
const [, w, h] = logoSvg.match(/viewBox="0 0 ([\d.]+) ([\d.]+)"/)
const [vbW, vbH] = [Number(w), Number(h)]
const logoWidth = Math.round(LOGO_HEIGHT * (vbW / vbH))

// The helix drawing itself: the source file's root <svg> wrapper and XML
// declaration stripped, ids dropped so several badges can coexist in one
// document (nothing in the logo references them via url(#...)), whitespace
// collapsed to match badge-maker's own output.
const logoBody = logoSvg
  .replace(/<\?xml[^>]*\?>/, '')
  .replace(/^\s*<svg\b[^>]*>/, '')
  .replace(/<\/svg>\s*$/, '')
  .replace(/\s+id="[^"]*"/g, '')
  .replace(/\s+/g, ' ') // the source puts each attribute on its own line
  .replace(/>\s+</g, '><')
  .trim()

// badge-maker can only embed a logo as a data URI. Swap that <image> for the
// logo's own elements wrapped in a <g transform>, which renders in contexts
// where data URIs are stripped or unsupported. A nested <svg> would express
// the same geometry more directly, but sanitizers (GitHub's among them) drop
// nested <svg> nodes, so the transform is computed by hand instead: a uniform
// scale, centered in the box, reproducing preserveAspectRatio="xMidYMid meet".
function inlineLogo(svg) {
  const replaced = svg.replace(
    /<image\s+x="([\d.]+)"\s+y="([\d.]+)"\s+width="([\d.]+)"\s+height="([\d.]+)"\s+href="data:[^"]*"\s*\/>/,
    (_, x, y, width, height) => {
      const scale = Math.min(width / vbW, height / vbH)
      const tx = Number(x) + (width - vbW * scale) / 2
      const ty = Number(y) + (height - vbH * scale) / 2
      const round = n => +n.toFixed(4)
      return `<g transform="translate(${round(tx)},${round(ty)}) scale(${round(scale)})">${logoBody}</g>`
    },
  )
  if (replaced === svg) throw new Error('logo <image> element not found — badge-maker output changed?')
  if (replaced.includes('data:')) throw new Error('a data URI survived inlining')
  return replaced
}

// Shields' named colors, so the badges read the same way as every other
// status badge in a README.
const badges = [
  { message: 'maintained', color: 'brightgreen', file: 'biojulia-maintained.svg' },
  {
    message: 'functional; maintainer needed',
    color: 'yellow',
    file: 'biojulia-functional-maintainer-needed.svg',
  },
  { message: 'deprecated', color: 'red', file: 'biojulia-deprecated.svg' },
]

for (const { message, color, file } of badges) {
  const svg = inlineLogo(
    makeBadge({
      label: 'BioJulia',
      message,
      labelColor: '#555',
      color,
      style: 'flat',
      logo: 'data:image/svg+xml;base64,PLACEHOLDER', // swapped out by inlineLogo
      logoWidth,
    }),
  )
  writeFileSync(new URL(`./${file}`, import.meta.url), svg + '\n')
  console.log(`${file.padEnd(34)} ${svg.match(/width="(\d+)"/)[1]}px  ${svg.length}b`)
}

@kescobo

kescobo commented Aug 17, 2026

Copy link
Copy Markdown
Member

Is there a reason not to use shields.io. I think they have a way we can use custom svgs for the icons...

@rasmushenningsson

Copy link
Copy Markdown
Contributor Author

It's possible, but the custom icon is inserted as a binary blob in the url, which makes it long and ugly.
Look at the markdown of this post to see the >2k chars needed for a badge.
So I rendered them to proper svg instead, because it seems easier for someone editing the README.md to understand what's going on.

That said, whichever solution works for me.

BioJulia: maintained

@rasmushenningsson

Copy link
Copy Markdown
Contributor Author

Here's the markdown (it became weird if I quote for some reason).

![BioJulia: maintained](https://img.shields.io/badge/BioJulia-maintained-brightgreen?labelColor=555&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB2aWV3Qm94PSIwIDAgMTM2LjUyMzcyIDUxLjM4NjQiIHZlcnNpb249IjEuMSIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjEzNi41MjM3MSIgaGVpZ2h0PSI1MS4zODY0MDIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI%2BPGcgdHJhbnNmb3JtPSJtYXRyaXgoMC45OTk5OTcyMiwwLjAwMjM1Nzc1LDAuMDAyMzU3NzUsLTAuOTk5OTk3MjIsLTAuMDQ3ODQ3MzMsNTEuMjI4MzE4KSI%2BPGNpcmNsZSBjeD0iNS45NzkxOTk5IiBjeT0iMjAuMjk5OTk5IiByPSI1Ljk3OTE5OTkiIGZpbGw9IiM5NDViYjAiIC8%2BPGNpcmNsZSBjeD0iMjEuMzE2OTk5IiBjeT0iMzkuNSIgcj0iNC45MzkzMDAxIiBmaWxsPSIjNDI2NmQ1IiAvPjxjaXJjbGUgY3g9IjE2LjM3OCIgY3k9IjExLjciIHI9IjQuOTM5MzAwMSIgZmlsbD0iI2M5M2QzOSIgLz48Y2lyY2xlIGN4PSIzNS4wOTUwMDEiIGN5PSIzNS45MDAwMDIiIHI9IjUuOTc5MTk5OSIgZmlsbD0iIzk0NWJiMCIgLz48Y2lyY2xlIGN4PSI0Ny4xODM5OTgiIGN5PSIyMy43OTk5OTkiIHI9IjcuNDA4OTk5OSIgZmlsbD0iIzQyNjZkNSIgLz48Y2lyY2xlIGN4PSIyOC45ODYiIGN5PSI5LjY5OTk5OTgiIHI9IjQuNTQ5Mzk5OSIgZmlsbD0iIzNiOTcyZSIgLz48Y2lyY2xlIGN4PSI4OS40MjgwMDEiIGN5PSI0Ni41IiByPSI0LjkzOTMwMDEiIGZpbGw9IiNjOTNkMzkiIC8%2BPGNpcmNsZSBjeD0iNzEuNjIwMDAzIiBjeT0iNS41OTk5OTk5IiByPSI1LjU4OTIiIGZpbGw9IiM5NDViYjAiIC8%2BPGNpcmNsZSBjeD0iMTIxLjAxIiBjeT0iMTUuNSIgcj0iNS41ODkyIiBmaWxsPSIjYzkzZDM5IiAvPjxjaXJjbGUgY3g9IjU5LjY2MTk5OSIgY3k9IjMwLjI5OTk5OSIgcj0iMi40Njk3MDAxIiBmaWxsPSIjNDI2NmQ1IiAvPjxjaXJjbGUgY3g9IjEwMy42IiBjeT0iMTkuOSIgcj0iMy4yNDk1OTk5IiBmaWxsPSIjYzkzZDM5IiAvPjxjaXJjbGUgY3g9IjEyMy42MSIgY3k9IjM2LjUiIHI9IjIuNzI5NiIgZmlsbD0iIzQyNjZkNSIgLz48Y2lyY2xlIGN4PSIxMjcuNjQiIGN5PSI1LjE5OTk5OTgiIHI9IjMuODk5NDk5OSIgZmlsbD0iIzNiOTcyZSIgLz48Y2lyY2xlIGN4PSIxMzIuNTgiIGN5PSIzOS4yMDAwMDEiIHI9IjMuODk5NDk5OSIgZmlsbD0iIzk0NWJiMCIgLz48Y2lyY2xlIGN4PSI2Ny41OTEwMDMiIGN5PSIzNy40MDAwMDIiIHI9IjMuMzc5NDk5OSIgZmlsbD0iIzNiOTcyZSIgLz48Y2lyY2xlIGN4PSI5NS4wMTY5OTgiIGN5PSIxMy45IiByPSI0LjI4OTQwMDEiIGZpbGw9IiM0MjY2ZDUiIC8%2BPGNpcmNsZSBjeD0iNzcuNzI4OTk2IiBjeT0iNDIuOTAwMDAyIiByPSIzLjg5OTQ5OTkiIGZpbGw9IiM5NDViYjAiIC8%2BPGNpcmNsZSBjeD0iMTAyLjU2IiBjeT0iNDIiIHI9IjUuODQ5MTk5OCIgZmlsbD0iIzQyNjZkNSIgLz48Y2lyY2xlIGN4PSIxMTMuNiIgY3k9IjI4Ljc5OTk5OSIgcj0iNi43NTkxIiBmaWxsPSIjM2I5NzJlIiAvPjxjaXJjbGUgY3g9IjU3LjU4MjAwMSIgY3k9IjExIiByPSI2LjM2OTEwMDEiIGZpbGw9IiNjOTNkMzkiIC8%2BPGNpcmNsZSBjeD0iMzguNzM1MDAxIiBjeT0iMTQuOCIgcj0iMy4zNzk0OTk5IiBmaWxsPSIjYzkzZDM5IiAvPjxjaXJjbGUgY3g9Ijg0LjYxNzk5NiIgY3k9IjcuOTAwMDAwMSIgcj0iNS4zMjkyOTk5IiBmaWxsPSIjM2I5NzJlIiAvPjwvZz48L3N2Zz4%3D)

@kescobo

kescobo commented Aug 17, 2026

Copy link
Copy Markdown
Member

Oh no - I agree that's gross. I thought you could just use a link to the asset. I like the larger icons in your SVG icons better anyway.

We should also come up with and codify

  1. Definitions for each of these statuses
  2. Guidelines for adding them to your readme
  3. A procedure (or at least heuristic) for when we would remove or change them.

@rasmushenningsson

rasmushenningsson commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

Oh no - I agree that's gross. I thought you could just use a link to the asset. I like the larger icons in your SVG icons better anyway.

We should also come up with and codify

  1. Definitions for each of these statuses
  2. Guidelines for adding them to your readme
  3. A procedure (or at least heuristic) for when we would remove or change them.

Good points. I guess we can write this down in https://github.com/BioJulia/Contributing. And maybe refer to that from relevant pages on biojulia.dev and perhaps https://github.com/BioJulia/BioJuliaTemplate.jl.

Here are my thoughts. The wording etc. can be improved.

"Maintained": At least one person consider themselves an active maintainer. A user can expect answers to opened issues/PRs.

"Functional; Maintainer needed": The package is expected to work, but we are searching for a maintainer. A user cannot be sure that issues/PRs will be answered, in particular not more technical ones. If it's not possible to reach any maintainer for ~1 month, the package status can be changed to this.

"Deprecated": The package is no longer modern, either because it doesn't work on recent Julia releases or because it has been superseded by other Julia packages. If it's not possible to reach any maintainer for ~1 month, the package status can be changed to this.

The repo must be in BioJulia, JuliaHealth, EcoJulia (or other relevant GitHub organizations, such as lab orgs, we should include an exhaustive list) to be eligible for a badge. This is to ensure that we can change the badge to another one in case the maintainer is unreachable for whatever reason.

This is always a bit tricky, because it's impossible to encode exact rules that always work. But the community should try to work it out given the descriptions above. If there are disagreements, a decision taken by the admins of the organization (together with BioJulia admins if outside) should be followed.

@kescobo

kescobo commented Aug 17, 2026

Copy link
Copy Markdown
Member

Agree with this - we can work out specific language in a PR to Contributing.

Regarding (3), I agree it's difficult, and in the absence of specific conflict, I think we can keep it fairly vague at first. If there's no response from a maintainer for a month or more, and there's a compelling reason, we can change it. If there's no response for 6 months or more, we don't even need a compelling reason. If the maintainer pops back up, we can always change it back.

@kescobo

kescobo commented Aug 18, 2026

Copy link
Copy Markdown
Member

It doesn't seem like anything here should cause the build to fail. But in any case, I think we're going to re-work this back to a Franklin/Xranklin site, the failures look like a node/vitepress problem

@kescobo
kescobo merged commit fdc8e92 into BioJulia:main Aug 18, 2026
1 of 2 checks passed
@kescobo kescobo mentioned this pull request Aug 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants