Files

134 lines
5.9 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { phrase } from '@hanzo/i18n'
import { T } from '@hanzo/i18n/react'
import { Page, PageHero, Prose, Section, CardGrid, Cta } from '@/components/marketing/page-kit'
import { Earn, Mine } from '@/components/rewards/contribute'
import { BOUNTY } from '@/components/rewards/words'
import { ours } from '@/lib/hanzo/orgs'
import { SNAPSHOT, kind, tier } from '@/lib/hanzo/rewards'
import open from '@/lib/data/bounties.json'
/**
* /bounty — contributions earn points. What earns, the bounty tiers and the
* daily cap are the rewards rules (the build's snapshot of GET /v1/rewards/rules);
* the open bounties are the issues GitHub lists, at build, with the rules'
* bounty label in a public repository of Hanzo's orgs (scripts/sync-bounties.ts),
* each with the tier its `bounty:<tier>` label names and what that tier earns.
* The points themselves are the cloud's: a merge or a maintainer's label on
* GitHub reaches it, and nothing on this page counts anything.
*/
const rules = SNAPSHOT
const orgs = rules.github.orgs.filter(ours)
const labels = rules.github.labels.bounty ?? []
const cap = rules.caps.find((c) => c.source === 'contributions' && c.window === 'day')
const security = kind(rules, 'security')
/** How each org asks to be contributed to: its own CONTRIBUTING, in the org's .github repository. */
const guide = (org: string) => `https://github.com/${org}/.github/blob/main/CONTRIBUTING.md`
/** Every open issue in those orgs, on GitHub, for when no issue carries a bounty label. */
const issues = `https://github.com/search?type=issues&q=${encodeURIComponent(['is:issue', 'is:open', 'is:public', ...orgs.map((o) => `org:${o}`)].join(' '))}`
/** An issue's tier and what it earns: the tier its label names, or the ordinary award for the work. */
const worth = (labels: string[]) => {
const k = tier(rules, labels)
return k ? `${k.title} · +${k.points}` : null
}
export default function Bounty() {
return (
<Page>
<PageHero eyebrow={phrase('Bounties')} title={BOUNTY.title} lede={BOUNTY.line} />
<Section title={phrase('What earns')}>
<Earn />
</Section>
<Section title={phrase('Open bounties')}>
{open.issues.length ? (
<CardGrid
columns={2}
items={open.issues.slice(0, 24).map((i) => ({
title: i.title,
description: [`${i.repo}#${i.number}`, worth(i.labels)].filter(Boolean).join(' · '),
href: i.url,
}))}
/>
) : (
<Prose>
<p>
<T values={{ labels: labels.join(' or '), orgs: orgs.join(', ') }}>
{'No open issue in {orgs} is labelled {labels} right now. Every open issue there is fair game: a merged fix earns the same points.'}
</T>
</p>
</Prose>
)}
<Cta href={issues}>
<T>Browse the open issues on GitHub</T>
</Cta>
</Section>
<Section title={phrase('Claim a bounty in four steps')}>
<CardGrid
columns={2}
items={[
{ title: phrase('1. Pick an issue'), description: phrase('An open bounty below, or any open issue in a public Hanzo repository. Say on the issue that you are taking it, so two people do not do the same work.') },
{ title: phrase('2. Link GitHub'), description: phrase('Link the GitHub account you work from to your Hanzo account, so the merge counts for you.') },
{ title: phrase('3. Open a pull request'), description: phrase('Follow the org’s contributing guide and name the issue in the pull request. A maintainer reviews it.') },
{ title: phrase('4. Merged, then awarded'), description: phrase('The points come when a maintainer merges it, never when it opens. A bounty’s tier replaces the ordinary award for the same work.') },
]}
/>
</Section>
<Section title={phrase('How each org takes contributions')}>
<Prose>
<ul>
{orgs.map((o) => (
<li key={o}>
<a href={guide(o)}>{`${o}/.github/CONTRIBUTING.md`}</a>
</li>
))}
</ul>
</Prose>
</Section>
<Section title={phrase('My contributions')}>
<Mine rules={rules} />
</Section>
<Section title={phrase('The rules')}>
<Prose>
<ul>
<li>
<T>Maintainers decide. Points come only after a maintainer merges your pull request or labels your issue.</T>
</li>
<li>
<T>Each pull request and each issue earns once: a bug fix, docs, a translation or a bounty counts in place of the merge, not beside it. A pull request you merge yourself earns nothing.</T>
</li>
{cap ? (
<li>
<T values={{ n: cap.limit }}>{'At most {n} contribution points per person per UTC day. An exceptional award beyond it is made by hand, after review.'}</T>
</li>
) : null}
<li>
{security ? (
<T values={{ email: <a href="mailto:[email protected]">security@hanzo.ai</a>, n: security.points }}>
{'Report a security issue to {email} only, never in a public issue or pull request. A valid report earns +{n}, awarded by the security team after review, and it never shows on the public board.'}
</T>
) : (
<T values={{ email: <a href="mailto:[email protected]">security@hanzo.ai</a> }}>{'Report a security issue to {email} only, never in a public issue or pull request.'}</T>
)}
</li>
<li>
<T>Work done before you link GitHub is held for your GitHub account and joins your points when you link it.</T>
</li>
{rules.excluded.map((x) => (
<li key={x}>{x}</li>
))}
</ul>
</Prose>
<Cta href="/leaderboard">
<T>See the leaderboard</T>
</Cta>
</Section>
</Page>
)
}