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
140 changes: 140 additions & 0 deletions packages/std/extra/live_update/from_gitea_releases.bri
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import * as std from "/core";
import {
DEFAULT_LIVE_UPDATE_REGEX_VERSION_MATCH,
validateMatchTag,
} from "./index.bri";
import type {} from "nushell";

// HACK: The `import type` line above is a workaround for this issue:
// https://github.com/brioche-dev/brioche/issues/242

/**
* Additional options for the project to update.
*
* @param versionDash - The version of the project (converted in dash format).
* @param versionUnderscore - The version of the project (converted in underscore format).
*/
interface LiveUpdateFromGiteaReleasesProjectExtraOptions {
versionDash?: string;
versionUnderscore?: string;
[key: string]: unknown; // Ignore unknown properties
}

/**
* Options for the live update from Gitea releases.
*
* @param project - The project export that should be updated. Must include a
* `repository` property containing a Gitea repository URL.
* @param matchTag - A regex value (`/.../`) to extract the version number from
* a tag name. The regex must include a group named "version". If not
* provided, an optional "v" prefix will be stripped and the rest of the
* tag will be checked if it's a semver or semver-like version number.
* @param normalizeVersion - Whether to normalize the version number to
* a semver-like version number. When enabled, the dashes and underscores
* will be replaced with dots.
*/
interface LiveUpdateFromGiteaReleasesOptions {
project: {
version: string;
readonly repository: string;
extra?: LiveUpdateFromGiteaReleasesProjectExtraOptions;
};
readonly matchTag?: RegExp;
readonly normalizeVersion?: boolean;
}

/**
* Return a runnable recipe to live-update a project based on the latest release
* tag from a Gitea repository. The project's version will be set based on a
* regex match against the latest tag name. The repository is inferred from the
* `repository` field of the project.
*
* @param options - Options for the live update from Gitea releases.
*
* @returns A runnable recipe to live-update the project
*
* @example
* ```typescript
* export const project = {
* name: "gitea_docs",
* version: "0.1.0",
* repository: "https://gitea.com/gitea/docs.git",
* };
*
* export function liveUpdate(): std.Recipe<std.Directory> {
* return std.liveUpdateFromGiteaReleases({
* project,
* matchTag: /^v(?<version>.+)$/, // Strip "v" prefix from tags
* });
* }
* ```
*/
export function liveUpdateFromGiteaReleases(
options: LiveUpdateFromGiteaReleasesOptions,
): std.Recipe<std.Directory> {
const { repoOwner, repoName } = parseGiteaRepo(options.project.repository);
const matchTag = options.matchTag ?? DEFAULT_LIVE_UPDATE_REGEX_VERSION_MATCH;
const normalizeVersion = options.normalizeVersion ?? false;

validateMatchTag(matchTag);

return std.recipe(async () => {
const { nushellRunnable } = await import("nushell");

return nushellRunnable(
Brioche.includeFile("./scripts/live_update_from_gitea_releases.nu"),
).env({
project: JSON.stringify(options.project),
repoOwner,
repoName,
matchTag: matchTag.source,
normalizeVersion: normalizeVersion.toString(),
});
});
}

/**
* Interface representing the parsed Gitea repository information.
*/
interface GiteaRepoInfo {
readonly repoOwner: string;
readonly repoName: string;
}

function tryParseGiteaRepo(repo: string): GiteaRepoInfo | null {
const match = repo.match(
/^(?:https?:\/\/)?(www\.)?(?:gitea\.com\/)?(?<repoOwner>[\w\.-]+)\/(?<repoName>[\w\.-]+)\/?$/,
);

const { repoOwner, repoName: matchedRepoName } = match?.groups ?? {};
if (repoOwner == null || matchedRepoName == null) {
return null;
}

let repoName = matchedRepoName;
if (repoName.endsWith(".git")) {
repoName = repoName.slice(0, -4);
}

return { repoOwner, repoName };
}

/**
* Parse a Gitea repository URL to extract the repository owner and name.
*
* @param repo - The Gitea repository URL to parse.
*
* @returns An object containing the repository owner and name.
*
* @throws If the repository URL cannot be parsed.
*/
function parseGiteaRepo(repo: string): GiteaRepoInfo {
const info = tryParseGiteaRepo(repo);
if (info == null) {
throw new Error(
`Could not parse repo name and owner from ${JSON.stringify(repo)}`,
);
}

return info;
}
1 change: 1 addition & 0 deletions packages/std/extra/live_update/index.bri
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./from_gitea_releases.bri";
export * from "./from_github_releases.bri";
export * from "./from_github_tags.bri";
export * from "./from_gitlab_releases.bri";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Get project metadata
mut project = $env.project
| from json

# Retrieve the latest release information from Gitea
let releases = http get $'https://gitea.com/api/v1/repos/($env.repoOwner)/($env.repoName)/releases'

# Extract the version(s)
let releasesInfo = $releases
| each {|release|
let parsedTag = $release.tag_name
| parse --regex $env.matchTag

# If no tag is matched, a nil value will be returned
# and this value will be ignored by 'each'
if ($parsedTag | length) != 0 {
{ version: $parsedTag.0.version }
}
}
| sort-by --natural version

if ($releasesInfo | length) == 0 {
error make { msg: $'No tag did match regex ($env.matchTag)' }
}

let latestReleaseInfo = $releasesInfo
| last

mut version = $latestReleaseInfo.version

if $env.normalizeVersion == "true" {
$version = $version
| str replace --all --regex "(-|_)" "."
}

$project = $project
| update version $version

if ($project | get extra?.versionDash?) != null {
let $versionDash = $version
| str replace --all "." "-"

$project = $project
| update extra.versionDash $versionDash
}

if ($project | get extra?.versionUnderscore?) != null {
let $versionUnderscore = $version
| str replace --all "." "_"

$project = $project
| update extra.versionUnderscore $versionUnderscore
}

# Return back the project metadata encoded as JSON
$project
| to json