Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| A project is an app or a library: libraries show their package and how to ship a release, not production | 1 | /** |
| 2 | * Words and links for a project that is a library or a tool rather than an | |
| 3 | * app: which of its repository's packages to show, and how to publish a | |
| 4 | * first one. Whether a project is one is decided by the projects service | |
| 5 | * (`Project.kind`); this only says it on the pages. | |
| 6 | */ | |
| 7 | import type { DeploysSetting, Ecosystem, PackageSummary, ProjectEcosystem } from "@g1t/contracts"; | |
| 8 | ||
| 9 | /** As lib/packages.ts names each registry; repeated so this module stands alone in tests. */ | |
| Packages pages: Maven, NuGet and RubyGems, routed to the packages service | 10 | const REGISTRY: Record<Ecosystem, string> = { |
| 11 | container: "Container", | |
| 12 | npm: "npm", | |
| 13 | composer: "Composer", | |
| 14 | cargo: "Cargo", | |
| 15 | go: "Go", | |
| 16 | maven: "Maven", | |
| 17 | nuget: "NuGet", | |
| 18 | rubygems: "RubyGems", | |
| 19 | }; | |
| A project is an app or a library: libraries show their package and how to ship a release, not production | 20 | |
| 21 | const DOCS = "https://docs.g1t.sh"; | |
| 22 | ||
| 23 | /** The choices for "Deployments for this project" in a project's settings. */ | |
| 24 | export const DEPLOYS_CHOICES: { value: DeploysSetting; label: string; hint: string }[] = [ | |
| 25 | { value: "auto", label: "Detect automatically", hint: "From whether Deployments are on, the packages it publishes and the files at its root." }, | |
| 26 | { value: "yes", label: "Deploys", hint: "An app: its overview shows production, previews and domains." }, | |
| 27 | { value: "no", label: "Doesn't deploy", hint: "A library or a tool: its overview shows its packages and releases, and offers no deploying." }, | |
| 28 | ]; | |
| 29 | ||
| 30 | /** A registry's guide, and the command that publishes a first version there. */ | |
| 31 | export type PublishGuide = { label: string; guide: string; start: string | null }; | |
| 32 | ||
| 33 | /** The registries with a guide, for a library whose files do not say which it is. */ | |
| 34 | export const PUBLISH_GUIDES: PublishGuide[] = [ | |
| 35 | { label: "Composer", guide: `${DOCS}/guides/composer/`, start: "git tag v1.0.0 && git push --tags" }, | |
| 36 | { label: "npm", guide: `${DOCS}/guides/npm/`, start: "npm publish" }, | |
| 37 | { label: "Go", guide: `${DOCS}/guides/go/`, start: "git tag v1.0.0 && git push --tags" }, | |
| 38 | { label: "Containers", guide: `${DOCS}/guides/containers/`, start: null }, | |
| 39 | ]; | |
| 40 | ||
| 41 | /** How a library of `ecosystem` publishes its first version; null when its files do not say. */ | |
| 42 | export function publishGuide(ecosystem: ProjectEcosystem | null): PublishGuide | null { | |
| 43 | switch (ecosystem) { | |
| 44 | case "composer": | |
| 45 | return PUBLISH_GUIDES[0]!; | |
| 46 | case "npm": | |
| 47 | return PUBLISH_GUIDES[1]!; | |
| 48 | case "go": | |
| 49 | return PUBLISH_GUIDES[2]!; | |
| 50 | case "cargo": | |
| 51 | return { label: "Cargo", guide: `${DOCS}/guides/packages/`, start: null }; | |
| 52 | case "python": | |
| 53 | return { label: "Python", guide: `${DOCS}/guides/packages/`, start: null }; | |
| 54 | default: | |
| 55 | return null; | |
| 56 | } | |
| 57 | } | |
| 58 | ||
| 59 | /** A package as its own tool names it: `@acme/ui` for npm, the name otherwise. */ | |
| 60 | export function packageName(pkg: Pick<PackageSummary, "ecosystem" | "name" | "workspace">): string { | |
| 61 | return pkg.ecosystem === "npm" ? `@${pkg.workspace}/${pkg.name}` : pkg.name; | |
| 62 | } | |
| 63 | ||
| 64 | /** `Composer · psr/log 3.0.2`, for a project's card. */ | |
| 65 | export function packageLine(pkg: Pick<PackageSummary, "ecosystem" | "name" | "workspace" | "latest">): string { | |
| 66 | return `${REGISTRY[pkg.ecosystem]} · ${packageName(pkg)}${pkg.latest ? ` ${pkg.latest}` : ""}`; | |
| 67 | } | |
| 68 | ||
| 69 | /** The package's page. */ | |
| 70 | export function packagePath(pkg: Pick<PackageSummary, "ecosystem" | "name" | "workspace">): string { | |
| 71 | return `/${pkg.workspace}/-/packages/${pkg.ecosystem}/${pkg.name}`; | |
| 72 | } | |
| 73 | ||
| 74 | /** | |
| 75 | * The packages a library's overview shows, from its repository's: what it | |
| 76 | * publishes for others to install first, a container image last, as an | |
| 77 | * image is how apps ship too. | |
| 78 | */ | |
| 79 | export function libraryPackages<T extends Pick<PackageSummary, "ecosystem" | "versions" | "updated_at">>(list: T[]): T[] { | |
| 80 | return [...list].sort( | |
| 81 | (a, b) => | |
| 82 | Number(a.ecosystem === "container") - Number(b.ecosystem === "container") || | |
| 83 | Number(b.versions > 0) - Number(a.versions > 0) || | |
| 84 | b.updated_at.localeCompare(a.updated_at), | |
| 85 | ); | |
| 86 | } | |
| 87 | ||
| 88 | /** Whether any of the packages has a version: a release is out. */ | |
| 89 | export function hasRelease(list: Pick<PackageSummary, "versions">[]): boolean { | |
| 90 | return list.some((pkg) => pkg.versions > 0); | |
| 91 | } |