Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
6139290
feat: native slackware package
elibosley May 7, 2025
a719aba
chore: add install verification script
elibosley May 7, 2025
0427c14
chore: exact node version
elibosley May 7, 2025
3c1b797
chore: fix shellcheck and other errors
elibosley May 7, 2025
d243133
chore: fix rc scripts
elibosley May 7, 2025
df22255
fix: doinst.sh was gitignored
elibosley May 7, 2025
6bfde19
chore: delete duplicated script
elibosley May 7, 2025
a98ab8e
chore: build dynamix.unraid.net with versioning a-la-slackware
elibosley May 7, 2025
f236a0d
chore: fix missing api_version entry
elibosley May 7, 2025
48bb2b2
fix: patches escaping
elibosley May 7, 2025
a03da69
chore: more coderabbit fixes
elibosley May 7, 2025
b866766
chore: normalilze plugin casing
elibosley May 7, 2025
09d8522
chore: cleanup plugin builder
elibosley May 7, 2025
7311da0
chore: remove duplicated gitignore entries
elibosley May 7, 2025
f4e6933
chore: always quote
elibosley May 7, 2025
84d5fe9
chore: fix missing entities
elibosley May 7, 2025
a3f1382
fix: remove restore files calls, they were deleting necessary files
elibosley May 7, 2025
8992391
chore: fix the API service commands
elibosley May 7, 2025
e39edff
chore: restore files on uninstall
elibosley May 7, 2025
64047f1
chore: always build package with version
elibosley May 7, 2025
078960f
chore: copy txz to right location
elibosley May 7, 2025
4b51ac3
fix: revert change to main workflow and simplify command
elibosley May 7, 2025
d19c8f7
fix: txz path incorrect
elibosley May 7, 2025
f6a7548
fix: txz path fallback
elibosley May 7, 2025
b3dbe1b
fix: install package as versioned package
elibosley May 7, 2025
4214777
fix: txz version
elibosley May 7, 2025
38f088e
chore: url readability improvements
elibosley May 7, 2025
94769b2
chore: remove unused command
elibosley May 8, 2025
cd1513d
chore: don't start the API twice, build process workinbg
elibosley May 8, 2025
f33f96e
chore: fix download location for archive
elibosley May 8, 2025
4eaf8cf
chore: more cleanup for install and setup steps
elibosley May 8, 2025
c862fa1
chore: remove vendor archive from git
elibosley May 8, 2025
b18130b
chore: fix script paths
elibosley May 8, 2025
40e89cd
chore: fix verify_install.sh
elibosley May 8, 2025
3657886
chore: remove color codes
elibosley May 8, 2025
57db5b3
chore: fix coderabbit issues
elibosley May 8, 2025
e3741b1
chore: minor build fix
elibosley May 8, 2025
ea46815
chore: fix vendor path
elibosley May 8, 2025
237903f
chore: fix connect_plugin_installed incorrect value
elibosley May 8, 2025
c2dc88c
chore: add set -eu
elibosley May 8, 2025
043070b
fix: code review feedback
elibosley May 9, 2025
6606eb8
chore: remove sudo as it was replaced with runtime ownership changes
elibosley May 9, 2025
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
7 changes: 3 additions & 4 deletions .github/workflows/build-plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ jobs:
uses: actions/download-artifact@v4
with:
name: packed-node-modules
path: ${{ github.workspace }}/plugin/
path: ${{ github.workspace }}/plugin/node-modules-archive/
- name: Extract Unraid API
run: |
mkdir -p ${{ github.workspace }}/plugin/source/dynamix.unraid.net/usr/local/unraid-api
Expand All @@ -113,9 +113,8 @@ jobs:
id: build-plugin
run: |
cd ${{ github.workspace }}/plugin
ls -al
pnpm run build:txz
pnpm run build:plugin --tag="${{ inputs.TAG }}" --base-url="${{ inputs.BASE_URL }}"
pnpm run build:txz --tag="${{ inputs.TAG }}" --base-url="${{ inputs.BASE_URL }}" --api-version="${{ steps.vars.outputs.API_VERSION }}"
pnpm run build:plugin --tag="${{ inputs.TAG }}" --base-url="${{ inputs.BASE_URL }}" --api-version="${{ steps.vars.outputs.API_VERSION }}"

- name: Ensure Plugin Files Exist
run: |
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ jobs:
auth_unix_rw = "none"
EOF

# Add the current user to libvirt and kvm groups (note: this change wont apply to the current session)
# Add the current user to libvirt and kvm groups (note: this change won't apply to the current session)
sudo usermod -aG libvirt,kvm $USER

sudo mkdir -p /var/run/libvirt
Expand Down Expand Up @@ -179,11 +179,11 @@ jobs:
PACKAGE_LOCK_VERSION=$(jq -r '.version' package.json)
API_VERSION=$([[ -n "$IS_TAGGED" ]] && echo "$PACKAGE_LOCK_VERSION" || echo "${PACKAGE_LOCK_VERSION}+${GIT_SHA}")
export API_VERSION
echo "API_VERSION=${API_VERSION}" >> $GITHUB_ENV

- name: Build
run: |
pnpm run build:release

tar -czf deploy/unraid-api.tgz -C deploy/pack/ .

- name: Upload tgz to Github artifacts
Expand All @@ -195,7 +195,7 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: packed-node-modules
path: ${{ github.workspace }}/api/deploy/packed-node-modules.tar.xz
path: ${{ github.workspace }}/api/deploy/node-modules-archive/packed-node-modules.tar.xz

build-unraid-ui-webcomponents:
name: Build Unraid UI Library (Webcomponent Version)
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,4 @@ web/scripts/.sync-webgui-repo-*
plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/data/activation-data.php

# Config file that changes between versions
api/dev/Unraid.net/myservers.cfg
api/dev/Unraid.net/myservers.cfg
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
22
22.11.0
12 changes: 5 additions & 7 deletions api/scripts/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { exit } from 'process';
import type { PackageJson } from 'type-fest';
import { $, cd } from 'zx';

import { getDeploymentVersion } from './get-deployment-version.js';
import { getDeploymentVersion } from '@app/../scripts/get-deployment-version.js';

type ApiPackageJson = PackageJson & {
version: string;
Expand Down Expand Up @@ -49,13 +49,11 @@ try {

await writeFile('package.json', JSON.stringify(parsedPackageJson, null, 4));

const sudoCheck = await $`command -v sudo`.nothrow();
const SUDO = sudoCheck.exitCode === 0 ? 'sudo' : '';
await $`${SUDO} chown -R 0:0 node_modules`;

await $`XZ_OPT=-5 tar -cJf packed-node-modules.tar.xz node_modules`;
await $`mv packed-node-modules.tar.xz ../`;
await $`${SUDO} rm -rf node_modules`;
// Create a subdirectory for the node modules archive
await mkdir('../node-modules-archive', { recursive: true });
await $`mv packed-node-modules.tar.xz ../node-modules-archive/`;
await $`rm -rf node_modules`;

// chmod the cli
await $`chmod +x ./dist/cli.js`;
Expand Down
19 changes: 17 additions & 2 deletions plugin/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# Thumbnails
._*
Thumbs.db
Expand All @@ -15,6 +14,22 @@ source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/unraid-com
source/dynamix.unraid.net/usr/local/unraid-api/*
!source/dynamix.unraid.net/usr/local/unraid-api/.gitkeep

source/dynamix.unraid.net/install/doinst.sh
### Generated Files by Plugin Builder ###

# Ignore node binaries
source/dynamix.unraid.net/usr/local/bin/

packed-pnpm-store.txz

# Node.js download files
node-v*.tar.xz

# Node.js man pages
source/dynamix.unraid.net/usr/local/share/man/man1/node.1

# Node version files
.node-version
source/dynamix.unraid.net/usr/local/.node-version

# Vendor archive files
source/dynamix.unraid.net/usr/local/share/dynamix.unraid.net/config/vendor_archive.json
39 changes: 27 additions & 12 deletions plugin/builder/build-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { readFile, writeFile, mkdir, rename } from "fs/promises";
import { $ } from "zx";
import { escape as escapeHtml } from "html-sloppy-escaper";
import { dirname, join } from "node:path";
import { getTxzName, pluginName, startingDir } from "./utils/consts";
import { getTxzName, pluginName, startingDir, defaultArch, defaultBuild } from "./utils/consts";
import { getAssetUrl, getPluginUrl } from "./utils/bucket-urls";
import { getMainTxzUrl } from "./utils/bucket-urls";
import {
Expand All @@ -26,9 +26,17 @@ const checkGit = async () => {
}
};

const moveTxzFile = async (txzPath: string, pluginVersion: string) => {
const txzName = getTxzName(pluginVersion);
await rename(txzPath, join(deployDir, txzName));
const moveTxzFile = async ({txzPath, apiVersion}: Pick<PluginEnv, "txzPath" | "apiVersion">) => {
const txzName = getTxzName(apiVersion);
const targetPath = join(deployDir, txzName);

// Ensure the txz always has the full version name
if (txzPath !== targetPath) {
console.log(`Ensuring TXZ has correct name: ${txzPath} -> ${targetPath}`);
await rename(txzPath, targetPath);
} else {
console.log(`TXZ file already has correct name: ${txzPath}`);
}
};

function updateEntityValue(
Expand All @@ -50,20 +58,27 @@ const buildPlugin = async ({
tag,
txzSha256,
releaseNotes,
apiVersion,
}: PluginEnv) => {
console.log(`API version: ${apiVersion}`);

// Update plg file
let plgContent = await readFile(getRootPluginPath({ startingDir }), "utf8");

// Update entity values
const entities: Record<string, string> = {
name: pluginName,
version: pluginVersion,
pluginURL: getPluginUrl({ baseUrl, tag }),
MAIN_TXZ: getMainTxzUrl({ baseUrl, pluginVersion, tag }),
TXZ_SHA256: txzSha256,
VENDOR_STORE_URL: getAssetUrl({ baseUrl, tag }, getVendorBundleName()),
VENDOR_STORE_FILENAME: getVendorBundleName(),
...(tag ? { TAG: tag } : {}),
api_version: apiVersion,
arch: defaultArch,
build: defaultBuild,
plugin_url: getPluginUrl({ baseUrl, tag }),
txz_url: getMainTxzUrl({ baseUrl, apiVersion, tag }),
txz_sha256: txzSha256,
txz_name: getTxzName(apiVersion),
vendor_store_url: getAssetUrl({ baseUrl, tag }, getVendorBundleName(apiVersion)),
vendor_store_filename: getVendorBundleName(apiVersion),
...(tag ? { tag } : {}),
};

console.log("Entities:", entities);
Expand Down Expand Up @@ -107,8 +122,8 @@ const main = async () => {
await cleanupPluginFiles();

await buildPlugin(validatedEnv);
await moveTxzFile(validatedEnv.txzPath, validatedEnv.pluginVersion);
await bundleVendorStore();
await moveTxzFile(validatedEnv);
await bundleVendorStore(validatedEnv.apiVersion);
} catch (error) {
console.error(error);
process.exit(1);
Expand Down
94 changes: 90 additions & 4 deletions plugin/builder/build-txz.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { join } from "path";
import { $, cd } from "zx";
import { existsSync } from "node:fs";
import { readdir } from "node:fs/promises";
import { readdir, writeFile } from "node:fs/promises";
import { getTxzName, pluginName, startingDir } from "./utils/consts";
import { ensureNodeJs } from "./utils/nodejs-helper";

import { setupTxzEnv, TxzEnv } from "./cli/setup-txz-environment";
import { cleanupTxzFiles } from "./utils/cleanup";
import { apiDir } from "./utils/paths";
import { getVendorBundleName, getVendorFullPath } from "./build-vendor-store";
import { getAssetUrl } from "./utils/bucket-urls";


// Recursively search for manifest files
const findManifestFiles = async (dir: string): Promise<string[]> => {
Expand Down Expand Up @@ -40,6 +45,59 @@ const findManifestFiles = async (dir: string): Promise<string[]> => {
}
};

// Function to store vendor archive information in a recoverable location
const storeVendorArchiveInfo = async (version: string, vendorUrl: string, vendorFilename: string) => {
try {
if (!version || !vendorUrl || !vendorFilename) {
throw new Error("Cannot store vendor archive info: Missing required parameters");
}

// Create a config directory in the source tree
const configDir = join(
startingDir,
"source",
"dynamix.unraid.net",
"usr",
"local",
"share",
"dynamix.unraid.net",
"config"
);

// Ensure directory exists
await $`mkdir -p ${configDir}`;

// Get the full path for vendor archive
const vendorFullPath = getVendorFullPath(version);

// Create a JSON config file with vendor information
const configData = {
vendor_store_url: vendorUrl,
vendor_store_path: vendorFullPath,
api_version: version
};

// Validate all fields are present
Object.entries(configData).forEach(([key, value]) => {
if (!value) {
throw new Error(`Cannot store vendor archive info: Missing value for ${key}`);
}
});

const configPath = join(configDir, "vendor_archive.json");
await writeFile(configPath, JSON.stringify(configData, null, 2));

console.log(`Vendor archive information stored in ${configPath}`);
console.log(`API Version: ${version}`);
console.log(`Vendor URL: ${vendorUrl}`);
console.log(`Vendor Full Path: ${vendorFullPath}`);
return true;
} catch (error) {
console.error(`Failed to store vendor archive information: ${error.message}`);
throw error; // Re-throw to prevent build from succeeding with invalid vendor info
}
};

const validateSourceDir = async (validatedEnv: TxzEnv) => {
if (!validatedEnv.ci) {
console.log("Validating TXZ source directory");
Expand Down Expand Up @@ -70,8 +128,15 @@ const validateSourceDir = async (validatedEnv: TxzEnv) => {

if (!hasManifest || !hasUiManifest) {
console.log("Existing Manifest Files:", manifestFiles);
const missingFiles: string[] = [];
if (!hasManifest) missingFiles.push("manifest.json");
if (!hasUiManifest) missingFiles.push("ui.manifest.json");

throw new Error(
`Webcomponents must contain both "ui.manifest.json" and "manifest.json" - be sure to have run pnpm build:wc in unraid-ui`
`Webcomponents missing required file(s): ${missingFiles.join(", ")} - ` +
`${!hasUiManifest ? "run 'pnpm build:wc' in unraid-ui for ui.manifest.json" : ""}` +
`${!hasManifest && !hasUiManifest ? " and " : ""}` +
`${!hasManifest ? "run 'pnpm build' in web for manifest.json" : ""}`
);
}

Expand All @@ -88,16 +153,37 @@ const validateSourceDir = async (validatedEnv: TxzEnv) => {

const buildTxz = async (validatedEnv: TxzEnv) => {
await validateSourceDir(validatedEnv);
const txzPath = join(validatedEnv.txzOutputDir, getTxzName());

// Use version from validated environment
const version = validatedEnv.apiVersion;

// Always use version when getting txz name
const txzName = getTxzName(version);
console.log(`Package name: ${txzName}`);
const txzPath = join(validatedEnv.txzOutputDir, txzName);

// Use the getVendorBundleName function for consistent naming
const vendorFilename = getVendorBundleName(version);
// Use the baseUrl and tag from validatedEnv, consistent with build-plugin.ts
const vendorUrl = getAssetUrl({
baseUrl: validatedEnv.baseUrl,
tag: validatedEnv.tag
}, vendorFilename);

console.log(`Storing vendor archive information: ${vendorUrl} -> ${vendorFilename}`);
await storeVendorArchiveInfo(version, vendorUrl, vendorFilename);

await ensureNodeJs();

// Create package - must be run from within the pre-pack directory
// Use cd option to run command from prePackDir
await cd(join(startingDir, "source", pluginName));
$.verbose = true;

// Create the package using the default package name
await $`${join(startingDir, "scripts/makepkg")} --chown y --compress -${
validatedEnv.compress
} --linkadd y ${txzPath}`;
} --linkadd n ${txzPath}`;
$.verbose = false;
await cd(startingDir);
};
Expand Down
Loading
Loading