mirror of
https://github.com/webinstall/webi-installers.git
synced 2026-04-04 17:36:57 +00:00
feat(monorel): add installer for monorepo release tool
Adds releases.js, install.sh, install.ps1, and README.md for monorel, a Go monorepo release tool from therootcompany/golib. Filters monorepo releases by tools/monorel/ prefix and auto-installs prerequisites (git, gh, goreleaser).
This commit is contained in:
165
monorel/README.md
Normal file
165
monorel/README.md
Normal file
@@ -0,0 +1,165 @@
|
||||
---
|
||||
title: monorel
|
||||
homepage: https://github.com/therootcompany/golib/tree/main/tools/monorel
|
||||
tagline: |
|
||||
monorel: Monorepo Release Tool for Go binaries.
|
||||
---
|
||||
|
||||
To update or switch versions, run `webi monorel@stable` (or `@v0.6`, `@beta`,
|
||||
etc).
|
||||
|
||||
### Files
|
||||
|
||||
These are the files that are created and/or modified with this installer:
|
||||
|
||||
```text
|
||||
~/.config/envman/PATH.env
|
||||
~/.local/bin/monorel
|
||||
~/.local/opt/monorel-VERSION/bin/monorel
|
||||
```
|
||||
|
||||
These are the files that monorel creates and/or modifies in your project:
|
||||
|
||||
```text
|
||||
<module>/.goreleaser.yaml
|
||||
.git/refs/tags/<module>/v*
|
||||
```
|
||||
|
||||
## Cheat Sheet
|
||||
|
||||
> `monorel` manages independently-versioned Go modules and releases in a single
|
||||
> repository — initializing goreleaser configs, bumping versions, and publishing
|
||||
> multi-arch releases.
|
||||
|
||||
### How to use monorel
|
||||
|
||||
```sh
|
||||
# Generate .goreleaser.yaml for all modules
|
||||
monorel init --recursive ./
|
||||
|
||||
# Tag the next patch version for all modules with new commits
|
||||
monorel bump --recursive ./
|
||||
|
||||
# Build, package, and publish GitHub releases for all binaries of a module
|
||||
monorel release --recursive ./tools/monorel
|
||||
```
|
||||
|
||||
### How monorepo versioning works
|
||||
|
||||
Each `go.mod` is an independently-versioned module. Tags use the module's path
|
||||
as a prefix, and each module with binaries gets a `.goreleaser.yaml`:
|
||||
|
||||
```text
|
||||
./
|
||||
├── go.mod # v0.1.1 (library-only)
|
||||
├── io/
|
||||
│ └── transform/
|
||||
│ └── gsheet2csv/
|
||||
│ ├── go.mod # io/transform/gsheet2csv/v1.0.5
|
||||
│ ├── .goreleaser.yaml
|
||||
│ └── cmd/
|
||||
│ ├── gsheet2csv/
|
||||
│ ├── gsheet2env/
|
||||
│ └── gsheet2tsv/
|
||||
└── tools/
|
||||
└── monorel/
|
||||
├── go.mod # tools/monorel/v1.0.0
|
||||
└── .goreleaser.yaml
|
||||
```
|
||||
|
||||
### `monorel init` vs `goreleaser init`
|
||||
|
||||
`goreleaser init` generates a config that assumes one module per repo and
|
||||
derives names and versions from the git tag. That breaks in a monorepo with
|
||||
prefixed tags. `monorel init` fixes this:
|
||||
|
||||
| | `goreleaser init` | `monorel init` |
|
||||
| ------------- | --------------------------- | --------------------------------------- |
|
||||
| Project name | `{{ .ProjectName }}` | Hard-coded binary name |
|
||||
| Version | Derived from git tag | `{{ .Env.VERSION }}` (plain semver) |
|
||||
| Publishing | goreleaser's built-in | Disabled; uses `gh release` instead |
|
||||
| Multiple bins | Manual config | Auto-discovered, shared via YAML anchor |
|
||||
| Monorepo tags | (requires Pro subscription) | Prefix-aware (`cmd/foo/v1.2.3`) |
|
||||
|
||||
### Generated `.goreleaser.yaml`: single binary
|
||||
|
||||
For a module with one binary (like `tools/monorel/`), the generated config has a
|
||||
single build entry:
|
||||
|
||||
```yaml
|
||||
builds:
|
||||
- id: monorel
|
||||
binary: monorel
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
ldflags:
|
||||
- >-
|
||||
-s -w -X main.version={{.Env.VERSION}} -X main.commit={{.Commit}} -X
|
||||
main.date={{.Date}}
|
||||
goos:
|
||||
- darwin
|
||||
- linux
|
||||
- windows
|
||||
# ... and more
|
||||
|
||||
archives:
|
||||
- id: monorel
|
||||
ids: [monorel]
|
||||
# Hard-coded name instead of {{ .ProjectName }} — goreleaser derives
|
||||
# ProjectName from the prefixed tag, which would produce messy filenames.
|
||||
# {{ .Env.VERSION }} for the same reason — the raw tag version includes
|
||||
# the module path prefix.
|
||||
name_template: >-
|
||||
monorel_{{ .Env.VERSION }}_{{ title .Os }}_{{ .Arch }}
|
||||
|
||||
# goreleaser Pro would be needed to publish from a prefixed tag,
|
||||
# so monorel disables goreleaser's publisher and uses 'gh release' instead.
|
||||
release:
|
||||
disable: true
|
||||
```
|
||||
|
||||
### Generated `.goreleaser.yaml`: multiple binaries
|
||||
|
||||
When a module has several commands under `cmd/`, monorel generates a build entry
|
||||
per binary with shared settings via a YAML anchor:
|
||||
|
||||
```yaml
|
||||
builds:
|
||||
- id: gsheet2csv
|
||||
binary: gsheet2csv
|
||||
main: ./cmd/gsheet2csv
|
||||
<<: &build_defaults
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
ldflags:
|
||||
- >-
|
||||
-s -w -X main.version={{.Env.VERSION}}
|
||||
goos:
|
||||
- darwin
|
||||
- linux
|
||||
- windows
|
||||
# ...
|
||||
- id: gsheet2env
|
||||
binary: gsheet2env
|
||||
main: ./cmd/gsheet2env
|
||||
<<: *build_defaults
|
||||
- id: gsheet2tsv
|
||||
binary: gsheet2tsv
|
||||
main: ./cmd/gsheet2tsv
|
||||
<<: *build_defaults
|
||||
|
||||
archives:
|
||||
- id: gsheet2csv
|
||||
# All binaries are bundled into one archive per platform.
|
||||
ids: [gsheet2csv, gsheet2env, gsheet2tsv]
|
||||
# Same hard-coded name and {{ .Env.VERSION }} to avoid prefixed tag leaking.
|
||||
name_template: >-
|
||||
gsheet2csv_{{ .Env.VERSION }}_{{ title .Os }}_{{ .Arch }}
|
||||
|
||||
# Same as single binary — disable goreleaser's publisher for monorepo tags.
|
||||
release:
|
||||
disable: true
|
||||
```
|
||||
|
||||
All three binaries share one version tag (`io/transform/gsheet2csv/v1.0.5`) and
|
||||
one GitHub release.
|
||||
48
monorel/install.ps1
Normal file
48
monorel/install.ps1
Normal file
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env pwsh
|
||||
|
||||
$pkg_cmd_name = "monorel"
|
||||
|
||||
$pkg_dst_cmd = "$Env:USERPROFILE\.local\bin\monorel.exe"
|
||||
$pkg_dst = "$pkg_dst_cmd"
|
||||
|
||||
$pkg_src_cmd = "$Env:USERPROFILE\.local\opt\monorel-v$Env:WEBI_VERSION\bin\monorel.exe"
|
||||
$pkg_src_bin = "$Env:USERPROFILE\.local\opt\monorel-v$Env:WEBI_VERSION\bin"
|
||||
$pkg_src_dir = "$Env:USERPROFILE\.local\opt\monorel-v$Env:WEBI_VERSION"
|
||||
$pkg_src = "$pkg_src_cmd"
|
||||
|
||||
New-Item "$Env:USERPROFILE\Downloads\webi" -ItemType Directory -Force | Out-Null
|
||||
$pkg_download = "$Env:USERPROFILE\Downloads\webi\$Env:WEBI_PKG_FILE"
|
||||
|
||||
# Fetch archive
|
||||
IF (!(Test-Path -Path "$Env:USERPROFILE\Downloads\webi\$Env:WEBI_PKG_FILE")) {
|
||||
Write-Output "Downloading monorel from $Env:WEBI_PKG_URL to $pkg_download"
|
||||
& curl.exe -A "$Env:WEBI_UA" -fsSL "$Env:WEBI_PKG_URL" -o "$pkg_download.part"
|
||||
& Move-Item "$pkg_download.part" "$pkg_download"
|
||||
}
|
||||
|
||||
IF (!(Test-Path -Path "$pkg_src_cmd")) {
|
||||
Write-Output "Installing monorel"
|
||||
|
||||
# Enter tmp
|
||||
Push-Location .local\tmp
|
||||
|
||||
# Remove any leftover tmp cruft
|
||||
Remove-Item -Path ".\monorel-v*" -Recurse -ErrorAction Ignore
|
||||
Remove-Item -Path ".\monorel.exe" -Recurse -ErrorAction Ignore
|
||||
|
||||
# Unpack archive
|
||||
Write-Output "Unpacking $pkg_download"
|
||||
& tar xf "$pkg_download"
|
||||
|
||||
# Settle unpacked archive into place
|
||||
Write-Output "Install Location: $pkg_src_cmd"
|
||||
New-Item "$pkg_src_bin" -ItemType Directory -Force | Out-Null
|
||||
Move-Item -Path ".\monorel.exe" -Destination "$pkg_src_bin"
|
||||
|
||||
# Exit tmp
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
Write-Output "Copying into '$pkg_dst_cmd' from '$pkg_src_cmd'"
|
||||
Remove-Item -Path "$pkg_dst_cmd" -Recurse -ErrorAction Ignore | Out-Null
|
||||
Copy-Item -Path "$pkg_src" -Destination "$pkg_dst" -Recurse
|
||||
57
monorel/install.sh
Normal file
57
monorel/install.sh
Normal file
@@ -0,0 +1,57 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC2034
|
||||
|
||||
set -e
|
||||
set -u
|
||||
|
||||
__init_monorel() {
|
||||
pkg_cmd_name="monorel"
|
||||
|
||||
pkg_src_dir="$HOME/.local/opt/monorel-v$WEBI_VERSION"
|
||||
pkg_src_cmd="$pkg_src_dir/bin/monorel"
|
||||
pkg_src="$pkg_src_cmd"
|
||||
|
||||
pkg_dst_cmd="$HOME/.local/bin/monorel"
|
||||
pkg_dst="$pkg_dst_cmd"
|
||||
|
||||
# pkg_install must be defined by every package
|
||||
pkg_install() {
|
||||
# ~/.local/opt/monorel-v0.6.5/bin
|
||||
mkdir -p "$(dirname "$pkg_src_cmd")"
|
||||
|
||||
# mv monorel ~/.local/opt/monorel-v0.6.5/bin/monorel
|
||||
mv ./monorel "$pkg_src_cmd"
|
||||
}
|
||||
|
||||
pkg_post_install() {
|
||||
b_old_path="${PATH}"
|
||||
export PATH="$HOME/.local/bin:${PATH}"
|
||||
|
||||
if ! command -v git > /dev/null; then
|
||||
"$HOME/.local/bin/webi" git
|
||||
fi
|
||||
|
||||
if ! command -v gh > /dev/null; then
|
||||
"$HOME/.local/bin/webi" gh
|
||||
fi
|
||||
|
||||
if ! command -v goreleaser > /dev/null; then
|
||||
"$HOME/.local/bin/webi" goreleaser
|
||||
fi
|
||||
|
||||
export PATH="${b_old_path}"
|
||||
}
|
||||
|
||||
pkg_get_current_version() {
|
||||
# 'monorel --version' has output in this format:
|
||||
# monorel v0.6.6 ba674a6 (2026-03-08T23:24:03Z)
|
||||
# This trims it down to just the version number:
|
||||
# 0.6.6
|
||||
monorel --version 2> /dev/null |
|
||||
head -n 1 |
|
||||
cut -d' ' -f2 |
|
||||
cut -c 2-
|
||||
}
|
||||
}
|
||||
|
||||
__init_monorel
|
||||
37
monorel/releases.js
Normal file
37
monorel/releases.js
Normal file
@@ -0,0 +1,37 @@
|
||||
'use strict';
|
||||
|
||||
var github = require('../_common/github.js');
|
||||
var owner = 'therootcompany';
|
||||
var repo = 'golib';
|
||||
|
||||
let Releases = module.exports;
|
||||
|
||||
Releases.latest = async function () {
|
||||
let all = await github(null, owner, repo);
|
||||
|
||||
// This is a monorepo — keep only monorel releases and strip the
|
||||
// path prefix from the version so normalize.js sees plain semver.
|
||||
all.releases = all.releases.filter(function (rel) {
|
||||
return rel.version.startsWith('tools/monorel/');
|
||||
});
|
||||
all.releases.forEach(function (rel) {
|
||||
rel.version = rel.version.replace(/^tools\/monorel\//, '');
|
||||
});
|
||||
|
||||
return all;
|
||||
};
|
||||
|
||||
Releases.sample = async function () {
|
||||
let normalize = require('../_webi/normalize.js');
|
||||
let all = await Releases.latest();
|
||||
all = normalize(all);
|
||||
all.releases = all.releases.slice(0, 5);
|
||||
return all;
|
||||
};
|
||||
|
||||
if (module === require.main) {
|
||||
(async function () {
|
||||
let samples = await Releases.sample();
|
||||
console.info(JSON.stringify(samples, null, 2));
|
||||
})();
|
||||
}
|
||||
Reference in New Issue
Block a user