[Init] Initial commit - NetMesh terminal manager
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
This commit is contained in:
144
.github/scripts/bump-homebrew-cask.sh
vendored
Normal file
144
.github/scripts/bump-homebrew-cask.sh
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# bump-homebrew-cask.sh — push a new version of the Netcatty cask to the
|
||||
# binaricat/homebrew-netcatty tap.
|
||||
#
|
||||
# Called from the release pipeline (`build.yml` → `homebrew-tap` job) after
|
||||
# the GitHub Release has been published with the signed + notarized DMGs.
|
||||
# Computes SHA-256 of the arm64 and x64 DMGs, rewrites the cask file, and
|
||||
# pushes the bump back to the tap repository using HOMEBREW_TAP_TOKEN.
|
||||
#
|
||||
# Required env vars:
|
||||
# VERSION — semver without leading "v" (e.g. 1.1.6)
|
||||
# HOMEBREW_TAP_TOKEN — PAT with contents:write on the tap repo
|
||||
#
|
||||
# Optional env vars:
|
||||
# TAP_REPO — default: binaricat/homebrew-netcatty
|
||||
# ARTIFACTS_DIR — default: artifacts
|
||||
# CASK_PATH — default: Casks/netcatty.rb
|
||||
# MAX_PUSH_ATTEMPTS — default: 5
|
||||
set -euo pipefail
|
||||
|
||||
: "${VERSION:?VERSION env var required (no leading v)}"
|
||||
: "${HOMEBREW_TAP_TOKEN:?HOMEBREW_TAP_TOKEN env var required}"
|
||||
|
||||
TAP_REPO="${TAP_REPO:-binaricat/homebrew-netcatty}"
|
||||
ARTIFACTS_DIR="${ARTIFACTS_DIR:-artifacts}"
|
||||
CASK_PATH="${CASK_PATH:-Casks/netcatty.rb}"
|
||||
MAX_PUSH_ATTEMPTS="${MAX_PUSH_ATTEMPTS:-5}"
|
||||
|
||||
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "::error::VERSION must be a stable numeric semver: $VERSION"
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! "$MAX_PUSH_ATTEMPTS" =~ ^[1-9][0-9]*$ ]]; then
|
||||
echo "::error::MAX_PUSH_ATTEMPTS must be a positive integer."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
version_is_newer() {
|
||||
local candidate="$1"
|
||||
local baseline="$2"
|
||||
local index
|
||||
local -a candidate_parts baseline_parts
|
||||
IFS='.' read -r -a candidate_parts <<<"$candidate"
|
||||
IFS='.' read -r -a baseline_parts <<<"$baseline"
|
||||
for index in 0 1 2; do
|
||||
if (( 10#${candidate_parts[$index]} > 10#${baseline_parts[$index]} )); then
|
||||
return 0
|
||||
fi
|
||||
if (( 10#${candidate_parts[$index]} < 10#${baseline_parts[$index]} )); then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
ARM_DMG="${ARTIFACTS_DIR}/Netcatty-${VERSION}-mac-arm64.dmg"
|
||||
X64_DMG="${ARTIFACTS_DIR}/Netcatty-${VERSION}-mac-x64.dmg"
|
||||
|
||||
for f in "$ARM_DMG" "$X64_DMG"; do
|
||||
if [[ ! -f "$f" ]]; then
|
||||
echo "::error::Required DMG artifact not found: $f"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
ARM_SHA=$(shasum -a 256 "$ARM_DMG" | awk '{print $1}')
|
||||
X64_SHA=$(shasum -a 256 "$X64_DMG" | awk '{print $1}')
|
||||
|
||||
echo "Computed checksums:"
|
||||
echo " arm64: ${ARM_SHA}"
|
||||
echo " x64 : ${X64_SHA}"
|
||||
|
||||
TMP=$(mktemp -d)
|
||||
trap 'rm -rf "$TMP"' EXIT
|
||||
|
||||
git clone --depth 1 \
|
||||
"https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/${TAP_REPO}.git" \
|
||||
"$TMP/tap"
|
||||
cd "$TMP/tap"
|
||||
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config user.name "github-actions[bot]"
|
||||
|
||||
# The shared tap is a compare-and-retry boundary. Each attempt starts from the
|
||||
# latest main branch, refuses to replace a newer release, then retries only a
|
||||
# non-fast-forward race from another release workflow.
|
||||
for ((attempt=1; attempt<=MAX_PUSH_ATTEMPTS; attempt++)); do
|
||||
git fetch --depth=1 origin main
|
||||
git switch -C main origin/main
|
||||
|
||||
if [[ ! -f "$CASK_PATH" ]]; then
|
||||
echo "::error::Cask file not found in tap: $CASK_PATH"
|
||||
exit 1
|
||||
fi
|
||||
current_version="$(
|
||||
sed -nE 's/^[[:space:]]*version[[:space:]]+"([^"]+)".*$/\1/p' "$CASK_PATH" |
|
||||
head -n 1
|
||||
)"
|
||||
if [[ ! "$current_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "::error::Current Cask version is not a stable numeric semver: $current_version"
|
||||
exit 1
|
||||
fi
|
||||
if version_is_newer "$current_version" "$VERSION"; then
|
||||
echo "Tap already has newer version ${current_version}; skip ${VERSION} without downgrading it."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Patch the cask in place. The three lines are anchored so the architecture
|
||||
# declaration earlier in the file cannot be mistaken for the checksum line.
|
||||
sed -i -E 's|^(\s*version)\s+"[^"]+"|\1 "'"$VERSION"'"|' "$CASK_PATH"
|
||||
sed -i -E 's|(sha256\s+arm:\s+)"[^"]+"|\1"'"$ARM_SHA"'"|' "$CASK_PATH"
|
||||
sed -i -E 's|^(\s*intel:\s+)"[^"]+"|\1"'"$X64_SHA"'"|' "$CASK_PATH"
|
||||
|
||||
if command -v ruby >/dev/null 2>&1; then
|
||||
ruby -c "$CASK_PATH" >/dev/null
|
||||
fi
|
||||
if git diff --quiet; then
|
||||
echo "Cask already at ${VERSION} with matching checksums — nothing to push."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Cask diff (attempt ${attempt}/${MAX_PUSH_ATTEMPTS}):"
|
||||
git --no-pager diff "$CASK_PATH"
|
||||
git add "$CASK_PATH"
|
||||
git commit -m "Bump netcatty to ${VERSION}"
|
||||
|
||||
if push_output="$(git push origin HEAD:main 2>&1)"; then
|
||||
printf '%s\n' "$push_output"
|
||||
echo "Pushed bump for ${VERSION} to ${TAP_REPO}."
|
||||
exit 0
|
||||
fi
|
||||
printf '%s\n' "$push_output" >&2
|
||||
if ! grep -Eqi 'non-fast-forward|fetch first' <<<"$push_output"; then
|
||||
echo "::error::Homebrew tap push failed for a reason that cannot be retried safely."
|
||||
exit 1
|
||||
fi
|
||||
if (( attempt == MAX_PUSH_ATTEMPTS )); then
|
||||
echo "::error::Homebrew tap push kept racing with another release after ${MAX_PUSH_ATTEMPTS} attempts."
|
||||
exit 1
|
||||
fi
|
||||
echo "::notice::Push raced with another release; refresh the tap and retry."
|
||||
sleep "$attempt"
|
||||
done
|
||||
121
.github/scripts/generate-release-note.js
vendored
Normal file
121
.github/scripts/generate-release-note.js
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
// Determine version priority:
|
||||
// 1. VERSION env variable
|
||||
// 2. Valid version tag (v1.2.3 format)
|
||||
// 3. Short commit ID (first 7 chars of GITHUB_SHA)
|
||||
// 4. package.json version as fallback
|
||||
function getVersion() {
|
||||
if (process.env.VERSION) {
|
||||
return process.env.VERSION;
|
||||
}
|
||||
|
||||
const refName = process.env.GITHUB_REF_NAME;
|
||||
// Check if refName is a valid version tag (e.g., v1.2.3)
|
||||
if (refName && /^v\d+\.\d+\.\d+/.test(refName)) {
|
||||
return refName.replace(/^v/, '');
|
||||
}
|
||||
|
||||
// Use short commit ID
|
||||
const sha = process.env.GITHUB_SHA;
|
||||
if (sha) {
|
||||
return sha.substring(0, 7);
|
||||
}
|
||||
|
||||
// Fall back to package.json version
|
||||
try {
|
||||
const pkgPath = path.join(__dirname, '..', '..', 'package.json');
|
||||
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
||||
return pkg.version;
|
||||
} catch {
|
||||
return '0.0.0';
|
||||
}
|
||||
}
|
||||
|
||||
const version = getVersion();
|
||||
const repo = process.env.GITHUB_REPOSITORY || 'binaricat/netcatty';
|
||||
// For tag releases, use the tag; for workflow_dispatch, create a tag from version
|
||||
const tag = (process.env.GITHUB_REF_NAME && /^v\d+\.\d+\.\d+/.test(process.env.GITHUB_REF_NAME))
|
||||
? process.env.GITHUB_REF_NAME
|
||||
: `v${version}`;
|
||||
const baseUrl = `https://github.com/${repo}/releases/download/${tag}`;
|
||||
|
||||
// Filename patterns based on electron-builder.config.cjs artifactName: '${productName}-${version}-${os}-${arch}.${ext}'
|
||||
// Note: electron-builder uses different arch names for Linux packages:
|
||||
// - AppImage: x64 -> x86_64, arm64 -> arm64
|
||||
// - deb: x64 -> amd64, arm64 -> arm64
|
||||
// - rpm: x64 -> x86_64, arm64 -> aarch64
|
||||
// - pacman: x64 -> x64, arm64 -> aarch64
|
||||
const files = {
|
||||
mac: {
|
||||
arm64: `Netcatty-${version}-mac-arm64.dmg`,
|
||||
x64: `Netcatty-${version}-mac-x64.dmg`
|
||||
},
|
||||
win: {
|
||||
x64: `Netcatty-${version}-win-x64.exe`
|
||||
},
|
||||
linux: {
|
||||
appimage: {
|
||||
x64: `Netcatty-${version}-linux-x86_64.AppImage`,
|
||||
arm64: `Netcatty-${version}-linux-arm64.AppImage`
|
||||
},
|
||||
deb: {
|
||||
x64: `Netcatty-${version}-linux-amd64.deb`,
|
||||
arm64: `Netcatty-${version}-linux-arm64.deb`
|
||||
},
|
||||
rpm: {
|
||||
x64: `Netcatty-${version}-linux-x86_64.rpm`,
|
||||
arm64: `Netcatty-${version}-linux-aarch64.rpm`
|
||||
},
|
||||
pacman: {
|
||||
x64: `Netcatty-${version}-linux-x64.pacman`,
|
||||
arm64: `Netcatty-${version}-linux-aarch64.pacman`
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const badges = {
|
||||
win: {
|
||||
setup_x64: `[](${baseUrl}/${files.win.x64})`
|
||||
},
|
||||
mac: {
|
||||
apple_silicon: `[](${baseUrl}/${files.mac.arm64})`,
|
||||
intel: `[](${baseUrl}/${files.mac.x64})`
|
||||
},
|
||||
linux: {
|
||||
appimage_x64: `[](${baseUrl}/${files.linux.appimage.x64})`,
|
||||
appimage_arm64: `[](${baseUrl}/${files.linux.appimage.arm64})`,
|
||||
deb_x64: `[](${baseUrl}/${files.linux.deb.x64})`,
|
||||
deb_arm64: `[](${baseUrl}/${files.linux.deb.arm64})`,
|
||||
rpm_x64: `[](${baseUrl}/${files.linux.rpm.x64})`,
|
||||
rpm_arm64: `[](${baseUrl}/${files.linux.rpm.arm64})`,
|
||||
pacman_x64: `[](${baseUrl}/${files.linux.pacman.x64})`,
|
||||
pacman_arm64: `[](${baseUrl}/${files.linux.pacman.arm64})`
|
||||
}
|
||||
};
|
||||
|
||||
const content = `
|
||||
## Download based on your OS:
|
||||
|
||||
| OS | Download |
|
||||
| :--- | :--- |
|
||||
| **Windows** | ${badges.win.setup_x64} |
|
||||
| **macOS** | ${badges.mac.apple_silicon} ${badges.mac.intel} |
|
||||
| **Linux** | ${badges.linux.appimage_x64} ${badges.linux.deb_x64} ${badges.linux.rpm_x64} ${badges.linux.pacman_x64} <br> ${badges.linux.appimage_arm64} ${badges.linux.deb_arm64} ${badges.linux.rpm_arm64} ${badges.linux.pacman_arm64} |
|
||||
|
||||
## Code signing policy
|
||||
|
||||
Netcatty is applying to the SignPath Foundation open-source program. Once
|
||||
approved, covered Windows release artifacts will use **Free code signing provided by SignPath.io, certificate by SignPath Foundation**.
|
||||
See the
|
||||
[Code signing policy](https://github.com/${repo}/blob/${tag}/CODE_SIGNING_POLICY.md)
|
||||
and [Privacy policy](https://github.com/${repo}/blob/${tag}/PRIVACY.md).
|
||||
`;
|
||||
|
||||
fs.writeFileSync('release_notes.md', content);
|
||||
console.log('Generated release_notes.md');
|
||||
76
.github/scripts/update-nix-release.js
vendored
Normal file
76
.github/scripts/update-nix-release.js
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
import crypto from 'node:crypto';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
function usage() {
|
||||
console.error('Usage: node .github/scripts/update-nix-release.js --artifacts <dir> --version <semver>');
|
||||
}
|
||||
|
||||
function parseArgs(argv) {
|
||||
const args = {};
|
||||
for (let index = 2; index < argv.length; index += 1) {
|
||||
const arg = argv[index];
|
||||
if (arg === '--artifacts' || arg === '--version') {
|
||||
args[arg.slice(2)] = argv[index + 1];
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
usage();
|
||||
process.exit(2);
|
||||
}
|
||||
if (!args.artifacts || !args.version) {
|
||||
usage();
|
||||
process.exit(2);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
function sriSha256(filePath) {
|
||||
const digest = crypto.createHash('sha256').update(fs.readFileSync(filePath)).digest('base64');
|
||||
return `sha256-${digest}`;
|
||||
}
|
||||
|
||||
function findArtifact(artifactsDir, fileName) {
|
||||
const filePath = path.join(artifactsDir, fileName);
|
||||
if (!fs.existsSync(filePath)) {
|
||||
throw new Error(`Missing release artifact: ${filePath}`);
|
||||
}
|
||||
return filePath;
|
||||
}
|
||||
|
||||
function renderReleaseNix({ version, x64Hash, arm64Hash }) {
|
||||
return `{
|
||||
version = "${version}";
|
||||
|
||||
sources = {
|
||||
x86_64-linux = {
|
||||
appImageArch = "x86_64";
|
||||
hash = "${x64Hash}";
|
||||
};
|
||||
aarch64-linux = {
|
||||
appImageArch = "arm64";
|
||||
hash = "${arm64Hash}";
|
||||
};
|
||||
};
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
const args = parseArgs(process.argv);
|
||||
const version = args.version.replace(/^v/, '');
|
||||
|
||||
if (!/^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-.+)?$/.test(version)) {
|
||||
throw new Error(`Expected semver version, got: ${args.version}`);
|
||||
}
|
||||
|
||||
const x64AppImage = findArtifact(args.artifacts, `Netcatty-${version}-linux-x86_64.AppImage`);
|
||||
const arm64AppImage = findArtifact(args.artifacts, `Netcatty-${version}-linux-arm64.AppImage`);
|
||||
|
||||
const releaseNix = renderReleaseNix({
|
||||
version,
|
||||
x64Hash: sriSha256(x64AppImage),
|
||||
arm64Hash: sriSha256(arm64AppImage),
|
||||
});
|
||||
|
||||
fs.writeFileSync('nix/release.nix', releaseNix);
|
||||
console.log(`Updated nix/release.nix for Netcatty ${version}`);
|
||||
Reference in New Issue
Block a user