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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@
```
After tapping, `brew upgrade seanseannery/opsfile/opsfile` keeps `ops` up to date.

### npm (MacOS / Linux)

```bash
npm install -g github:seanseannery/opsfile
```
Requires Node.js ≥ 14. Downloads the correct platform binary from the latest GitHub release on install.
To upgrade, re-run the same command. To uninstall: `npm uninstall -g opsfile`.

### curl (MacOS / Linux)

```bash
Expand Down
25 changes: 25 additions & 0 deletions install/install_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ FAIL=0

BREW_TAPPED=false
BREW_INSTALLED=false
NPM_INSTALLED=false

CURL_TMP_DIR=""

Expand All @@ -29,6 +30,9 @@ cleanup() {
if [ "$BREW_TAPPED" = true ]; then
brew untap seanseannery/opsfile 2>/dev/null && echo " brew untap: done" || echo " brew untap: skipped"
fi
if [ "$NPM_INSTALLED" = true ]; then
npm uninstall -g opsfile 2>/dev/null && echo " npm uninstall: done" || echo " npm uninstall: skipped"
fi
}
trap cleanup EXIT

Expand Down Expand Up @@ -76,6 +80,27 @@ else
fi
fi

# ── npm install test ─────────────────────────────────────────────────────────

echo ""
echo "=== npm install test ==="

if ! command -v npm > /dev/null 2>&1; then
echo " SKIP: npm not found"
else
if npm install -g github:seanseannery/opsfile --no-fund --no-audit 2>&1; then
NPM_INSTALLED=true
NPM_OPS="$(npm config get prefix)/bin/ops"
if "$NPM_OPS" --version > /dev/null 2>&1; then
pass "ops installed via npm and responds to --version"
else
fail "ops installed via npm but --version failed"
fi
else
fail "npm install github:seanseannery/opsfile failed"
fi
fi

# ── summary ──────────────────────────────────────────────────────────────────

echo ""
Expand Down
60 changes: 60 additions & 0 deletions install/npm_install.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env node
'use strict';

const https = require('https');
const fs = require('fs');
const path = require('path');

const REPO = 'seanseannery/opsfile';
const BIN_DIR = path.join(__dirname, '..', 'bin');
const BIN_PATH = path.join(BIN_DIR, 'ops');

function platformAssetPrefix() {
switch (process.platform) {
case 'darwin': return 'ops_darwin_v';
case 'linux': return 'ops_unix_v';
default:
console.error(`Unsupported platform: ${process.platform}`);
process.exit(1);
}
}

function get(url) {
return new Promise((resolve, reject) => {
https.get(url, { headers: { 'User-Agent': 'opsfile-npm-installer' } }, (res) => {
if (res.statusCode === 301 || res.statusCode === 302) {
return get(res.headers.location).then(resolve).catch(reject);
}
const chunks = [];
res.on('data', chunk => chunks.push(chunk));
res.on('end', () => resolve(Buffer.concat(chunks)));
res.on('error', reject);
}).on('error', reject);
});
}

async function main() {
const prefix = platformAssetPrefix();

console.log(`Fetching latest release from github.com/${REPO} ...`);
const apiData = await get(`https://api.github.com/repos/${REPO}/releases/latest`);
const release = JSON.parse(apiData.toString());

const asset = release.assets.find(a => a.name.startsWith(prefix));
if (!asset) {
console.error(`No release asset found matching '${prefix}'`);
process.exit(1);
}

console.log(`Downloading ops ${release.tag_name} for ${process.platform} ...`);
const binary = await get(asset.browser_download_url);

fs.mkdirSync(BIN_DIR, { recursive: true });
fs.writeFileSync(BIN_PATH, binary, { mode: 0o755 });
console.log(`Installed ops ${release.tag_name}`);
}

main().catch(err => {
console.error('Install failed:', err.message);
process.exit(1);
});
21 changes: 21 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "opsfile",
"version": "0.8.1",
"description": "Like make/Makefile but for live operations commands",
"homepage": "https://github.com/seanseannery/opsfile",
"repository": {
"type": "git",
"url": "https://github.com/seanseannery/opsfile.git"
},
"license": "MIT",
"bin": {
"ops": "bin/ops"
},
"scripts": {
"postinstall": "node install/npm_install.js"
},
"os": ["darwin", "linux"],
"engines": {
"node": ">=14"
}
}