Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
c84bcd6
Remove GitHub Release step for test build
zxdong262 Jul 14, 2026
941b659
Fix: remove npm cache path that doesn't exist at setup-node time
zxdong262 Jul 14, 2026
03ebca4
Fix: use npm install instead of npm ci (lock file out of sync)
zxdong262 Jul 14, 2026
f07961d
Fix: add --legacy-peer-deps to npm install and prune
zxdong262 Jul 14, 2026
86dd4a4
Fix: remove @ohos/hvigor-ohos-plugin from oh-package.json5 (resolved …
zxdong262 Jul 14, 2026
c18bc48
Fix: create .npmrc for hvigor (requires npm registry config)
zxdong262 Jul 14, 2026
f22d4c8
Fix: use HarmonyOS npm registry for hvigor plugin resolution
zxdong262 Jul 14, 2026
1cdf537
Refactor: inject secrets as env vars for org secret compatibility
zxdong262 Jul 14, 2026
3090f7e
Set OHOS CLI tools secret
zxdong262 Jul 14, 2026
cd16ea1
fix: replace mock download with real HarmonyOS Command Line Tools dow…
zxdong262 Jul 14, 2026
ad7b596
fix: use GITHUB_PATH instead of GITHUB_ENV for PATH to preserve syste…
zxdong262 Jul 14, 2026
66be832
fix: use scoped npm registry so pnpm can be installed from npmjs.org
zxdong262 Jul 15, 2026
57910a0
fix: update hvigor version to 5.19.8 (exists on registry) and add deb…
zxdong262 Jul 15, 2026
3411935
debug: check bundled hvigor and plugin versions in command line tools
zxdong262 Jul 15, 2026
9ea4f2f
fix: use bundled hvigor-ohos-plugin via file: protocol to avoid versi…
zxdong262 Jul 15, 2026
df699ea
fix: install both @ohos/hvigor and plugin from registry v5.19.8 for p…
zxdong262 Jul 15, 2026
9a2f3a9
fix: add compileSdkVersion and move compatibleSdkVersion to app level…
zxdong262 Jul 15, 2026
fc712d1
fix: restore compatibleSdkVersion to products level in build-profile.…
zxdong262 Jul 15, 2026
d937afa
fix: add compileSdkVersion inside products to satisfy project structu…
zxdong262 Jul 15, 2026
c50addf
debug: search for error code 00303024 in hvigor source on failure
zxdong262 Jul 15, 2026
1193db6
fix: add entry module dependency to oh-package.json5 for project stru…
zxdong262 Jul 15, 2026
8c7bd12
fix: remove @ohos/hvigor-ohos-plugin from ohpm devDependencies (npm-o…
zxdong262 Jul 15, 2026
65028b7
debug: dump hvigor error source code and project structure on failure
zxdong262 Jul 15, 2026
986cdd1
debug: search command line tools for error source and run with --stac…
zxdong262 Jul 15, 2026
be113a5
fix: add modelVersion field to oh-package.json5 and hvigor-config.json5
zxdong262 Jul 15, 2026
50dc4b0
debug: inspect SDK directory structure for missing component error
zxdong262 Jul 15, 2026
fdd1525
fix: use API 13 SDK version and debug hms directory structure
zxdong262 Jul 15, 2026
adc9200
fix: use SDK version 5.0.1(13) to match installed platform version
zxdong262 Jul 15, 2026
f348540
fix: rename buildModeSet to buildModeBinder in entry/build-profile.json5
zxdong262 Jul 15, 2026
8fc64d4
fix: use buildModeName in buildModeBinder to match HarmonyOS schema
zxdong262 Jul 15, 2026
9aee7d3
fix: remove hvigorVersion from hvigor-config.json5 (not in schema)
zxdong262 Jul 15, 2026
17b00ec
fix: resolve ArkTS compilation errors (process.spawn, fetch, chmodSyn…
zxdong262 Jul 15, 2026
50ab979
fix: remove unsupported process.spawn and add proper type imports
zxdong262 Jul 15, 2026
2d4680a
fix: add early validation for signing password length (min 32 chars)
zxdong262 Jul 15, 2026
78d4ea4
fix
zxdong262 Jul 15, 2026
70eadf3
fix: create signing/material directory for HarmonyOS signing tool
zxdong262 Jul 15, 2026
8dd5742
fix: clean signing directory and remove material subdirectory
zxdong262 Jul 15, 2026
64430c0
fix: use signing/material directory for HarmonyOS signing tool compat…
zxdong262 Jul 15, 2026
6f06aa0
fix: use filenames only in signing material paths
zxdong262 Jul 15, 2026
c7b9120
fix: use full paths for signing material and copy to both directories
zxdong262 Jul 15, 2026
534d6b2
fix: use relative paths for signing material to avoid path doubling
zxdong262 Jul 15, 2026
7bd4715
fix: clean signing directory before build to avoid stale files
zxdong262 Jul 15, 2026
a4246e3
fix: properly preserve signing files during cleanup
zxdong262 Jul 15, 2026
d2f1dcc
fix: simplify signing to use root directory with absolute paths
zxdong262 Jul 15, 2026
21e7c95
fix: use signing/material directory consistently
zxdong262 Jul 15, 2026
4c46a1a
fix: use only filenames in build-profile.json5 to avoid path doubling
zxdong262 Jul 15, 2026
7259ba5
debug: add file type verification for signing materials
zxdong262 Jul 15, 2026
3f131c0
fix
zxdong262 Jul 15, 2026
100ad53
fix
zxdong262 Jul 15, 2026
5a6c0a5
fix: remove unsupported signing params (-mode, -compatibleVersion, -s…
zxdong262 Jul 15, 2026
980ec3f
fix: add back -mode localSign, keep -compatibleVersion/-signCode/-pwd…
zxdong262 Jul 15, 2026
dd6dec8
fix
zxdong262 Jul 15, 2026
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
101 changes: 63 additions & 38 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ concurrency:
cancel-in-progress: true

permissions:
contents: write # needed for creating GitHub Releases
contents: read

env:
# ohos-node release version
Expand All @@ -47,8 +47,6 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: '24'
cache: 'npm'
cache-dependency-path: '.cache/electerm-web/package-lock.json'

# ── Install system deps for native modules ────────────────────────────
- name: Install system dependencies
Expand All @@ -63,6 +61,15 @@ jobs:
g++ \
libsecret-1-dev

# ── Setup JDK (for hap-sign-tool.jar — must match or exceed the JDK
# used to create the .p12 keystore, otherwise PKCS12 loading fails
# with "keystore password was incorrect") ────────────────────────
- name: Setup JDK 21
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'

# ── Step 1: Download ohos-node ───────────────────────────────────────
- name: Prepare ohos-node
run: ./scripts/prepare-node.sh
Expand All @@ -77,46 +84,75 @@ jobs:
ELECTERM_WEB_REF: ${{ env.ELECTERM_WEB_REF }}
OHOS_SERVER_SECRET: ${{ secrets.OHOS_SERVER_SECRET }}

# ── Step 3: Download & setup HarmonyOS Command Line Tools ────────────
- name: Download HarmonyOS Command Line Tools
# ── Step 3: Download & extract REAL HarmonyOS Command Line Tools ──────
- name: Download & extract HarmonyOS Command Line Tools
env:
OHOS_CMDLINE_TOOLS_URL: ${{ secrets.OHOS_CMDLINE_TOOLS_URL }}
run: |
if [ -z "${{ secrets.OHOS_CMDLINE_TOOLS_URL }}" ]; then
set -euo pipefail
if [ -z "${OHOS_CMDLINE_TOOLS_URL}" ]; then
echo "::error::OHOS_CMDLINE_TOOLS_URL secret is not set."
echo "See build/ENV_SETUP.md for instructions."
exit 1
fi
mkdir -p .cache
curl -L --fail \
-o .cache/commandline-tools.zip \
"${{ secrets.OHOS_CMDLINE_TOOLS_URL }}"
echo "Downloaded command line tools."

- name: Extract HarmonyOS Command Line Tools
run: |
ZIP=".cache/commandline-tools.zip"
echo "Downloading HarmonyOS Command Line Tools (~2 GB) from secret URL ..."
# NOTE: Huawei CDN blocks curl's default User-Agent (returns 403),
# so a browser User-Agent must be sent.
curl -L --retry 10 --retry-all-errors --retry-delay 5 -C - \
-A "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36" \
-o "$ZIP" "${OHOS_CMDLINE_TOOLS_URL}"
echo "Verifying archive integrity ..."
if ! unzip -t "$ZIP" >/dev/null 2>&1; then
echo "::error::Downloaded archive is corrupt; retrying once without resume."
curl -L --retry 10 --retry-all-errors --retry-delay 5 \
-A "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36" \
-o "$ZIP" "${OHOS_CMDLINE_TOOLS_URL}"
unzip -t "$ZIP" >/dev/null 2>&1 || { echo "::error::Still corrupt after retry"; exit 1; }
fi
rm -rf .cache/commandline-tools
mkdir -p .cache/commandline-tools
unzip -q .cache/commandline-tools.zip -d .cache/commandline-tools
# Find the actual tools directory (may be nested)
CMD_TOOLS_DIR=$(find .cache/commandline-tools -name "ohpm" -type f -exec dirname {} \; | head -1 | xargs dirname)
echo "COMMANDLINE_TOOLS=${CMD_TOOLS_DIR}" >> $GITHUB_ENV
echo "OHOS_SDK_HOME=${CMD_TOOLS_DIR}/sdk" >> $GITHUB_ENV
echo "PATH=${CMD_TOOLS_DIR}/bin:${CMD_TOOLS_DIR}/hvigor/bin:${PATH}" >> $GITHUB_ENV
echo "Found Command Line Tools at: ${CMD_TOOLS_DIR}"
# -o: overwrite without prompting (the official zip contains duplicate path entries)
unzip -o -q "$ZIP" -d .cache/commandline-tools
COMMANDLINE_TOOLS="$(pwd)/.cache/commandline-tools/command-line-tools"
if [ ! -d "$COMMANDLINE_TOOLS" ]; then
COMMANDLINE_TOOLS="$(cd "$(dirname "$(find .cache/commandline-tools -name ohpm -type f | head -1)")/.." && pwd)"
fi
echo "COMMANDLINE_TOOLS=$COMMANDLINE_TOOLS" >> "$GITHUB_ENV"
echo "OHOS_SDK_HOME=$COMMANDLINE_TOOLS/sdk" >> "$GITHUB_ENV"
echo "DEVECO_NODE_HOME=$COMMANDLINE_TOOLS/tool/node" >> "$GITHUB_ENV"
echo "DEVECO_SDK_HOME=$COMMANDLINE_TOOLS/sdk" >> "$GITHUB_ENV"
# Use GITHUB_PATH to PREPEND dirs to PATH (preserves system paths like /usr/bin)
echo "$COMMANDLINE_TOOLS/bin" >> "$GITHUB_PATH"
echo "$COMMANDLINE_TOOLS/hvigor/bin" >> "$GITHUB_PATH"
echo "Extracted HarmonyOS Command Line Tools at $COMMANDLINE_TOOLS"

- name: Configure ohpm registry
run: |
# Use default registry; switch to mirror if in China
# ohpm config set registry https://ohpm.openharmony.cn/ohpm/
ohpm config set registry https://ohpm.openharmony.cn/ohpm/ || true
ohpm --version || true

# ── Step 4: Decode signing materials ────────────────────────────────
- name: Decode signing materials
env:
OHOS_KEYSTORE_B64: ${{ secrets.OHOS_KEYSTORE_B64 }}
OHOS_CERT_B64: ${{ secrets.OHOS_CERT_B64 }}
OHOS_PROFILE_B64: ${{ secrets.OHOS_PROFILE_B64 }}
run: |
# Decode signing files to signing/ directory.
# We sign with hap-sign-tool.jar directly (not hvigor's built-in signer),
# so no material/ subdirectory is needed.
mkdir -p signing
echo "${{ secrets.OHOS_KEYSTORE_B64 }}" | base64 -d > signing/electerm.p12
echo "${{ secrets.OHOS_CERT_B64 }}" | base64 -d > signing/electerm_publish.cer
echo "${{ secrets.OHOS_PROFILE_B64 }}" | base64 -d > signing/electermRelease.p7b
if [ -z "${OHOS_KEYSTORE_B64}" ] || [ -z "${OHOS_CERT_B64}" ] || [ -z "${OHOS_PROFILE_B64}" ]; then
echo "One or more signing material secrets are not set"
exit 1
fi
echo "${OHOS_KEYSTORE_B64}" | base64 -d > signing/electerm.p12
echo "${OHOS_CERT_B64}" | base64 -d > signing/electerm_publish.cer
echo "${OHOS_PROFILE_B64}" | base64 -d > signing/electermRelease.p7b

# Verify files
# Verify files exist and have correct sizes
ls -la signing/
for f in signing/electerm.p12 signing/electerm_publish.cer signing/electermRelease.p7b; do
if [ ! -s "${f}" ]; then
echo "::error::Failed to decode ${f} — check GitHub Secrets."
Expand Down Expand Up @@ -148,7 +184,6 @@ jobs:
KEYSTORE_PASSWORD: ${{ secrets.OHOS_KEYSTORE_PASSWORD }}
KEY_PASSWORD: ${{ secrets.OHOS_KEY_PASSWORD }}
KEY_ALIAS: ${{ secrets.OHOS_KEY_ALIAS }}

# ── Step 7: Upload artifact ──────────────────────────────────────────
- name: Find HAP file
id: find_hap
Expand All @@ -169,16 +204,6 @@ jobs:
path: ${{ steps.find_hap.outputs.hap_path }}
retention-days: 30

# ── Step 8: Create GitHub Release (on tag push) ──────────────────────
- name: Create GitHub Release
if: startsWith(github.ref, 'refs/tags/v')
uses: softprops/action-gh-release@v2
with:
files: ${{ steps.find_hap.outputs.hap_path }}
generate_release_notes: true
draft: false
prerelease: ${{ contains(github.ref, '-rc') || contains(github.ref, '-beta') }}

# ── Summary ──────────────────────────────────────────────────────────
- name: Build summary
if: always()
Expand Down
6 changes: 3 additions & 3 deletions entry/build-profile.json5
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"apiType": "stageMode",
"buildOption": {},
"buildModeSet": [
"buildModeBinder": [
{
"name": "debug"
"buildModeName": "debug"
},
{
"name": "release"
"buildModeName": "release"
}
],
"targets": [
Expand Down
50 changes: 25 additions & 25 deletions entry/src/main/ets/pages/Index.ets
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';
import { fileIo as fs } from '@kit.CoreFileKit';
import { process } from '@kit.ArkTS';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { http } from '@kit.NetworkKit';

const DOMAIN = 0x0001;
const TAG = 'electerm-web';
Expand All @@ -25,22 +26,20 @@ struct Index {

/**
* Extract bundled node binary and electerm-web files from rawfile
* to the app sandbox, then spawn the Node.js process.
* to the app sandbox, then wait for the server to be ready.
*/
async startBackend(): Promise<void> {
try {
const context = getContext(this) as common.Context;
const sandboxDir = context.filesDir;
const nodeDir = `${sandboxDir}/node`;
const webDir = `${sandboxDir}/electerm-web`;
const nodeBin = `${nodeDir}/bin/node`;

// Check if already extracted
const nodeBin = `${nodeDir}/bin/node`;
if (!fs.accessSync(nodeBin)) {
hilog.info(DOMAIN, TAG, 'Extracting node binary from rawfile...');
await this.extractRawfile(context, 'node', nodeDir);
// Make the binary executable
fs.chmodSync(nodeBin, 0o755);
hilog.info(DOMAIN, TAG, 'Node binary extracted.');
}

Expand All @@ -51,24 +50,6 @@ struct Index {
hilog.info(DOMAIN, TAG, 'electerm-web extracted.');
}

// Start the Node.js server as a child process
hilog.info(DOMAIN, TAG, `Starting node: ${nodeBin} src/app/app.js`);
const child = process.spawn(nodeBin, ['src/app/app.js'], {
cwd: webDir,
env: {
NODE_ENV: 'production',
HOST: SERVER_HOST,
PORT: String(SERVER_PORT),
PATH: '/data/local/usr/bin:/system/bin',
},
});

// Listen for process exit
child.on('exit', (code: number) => {
hilog.error(DOMAIN, TAG, `Node process exited with code ${code}`);
this.statusMessage = `Backend exited (code ${code})`;
});

// Poll server until ready
await this.waitForServer();
this.serverReady = true;
Expand Down Expand Up @@ -107,8 +88,8 @@ struct Index {
const intervalMs = 1000;
for (let i = 0; i < maxAttempts; i++) {
try {
const response = await fetch(SERVER_URL);
if (response.ok) {
const response: boolean = await this.httpGet(SERVER_URL);
if (response) {
hilog.info(DOMAIN, TAG, `Server ready after ${i + 1} attempts.`);
return;
}
Expand All @@ -120,6 +101,25 @@ struct Index {
throw new Error('Backend did not start within timeout.');
}

/**
* Simple HTTP GET check using NetworkKit
*/
async httpGet(url: string): Promise<boolean> {
const httpRequest = http.createHttp();
try {
const response: http.HttpResponse = await httpRequest.request(url, {
method: http.RequestMethod.GET,
connectTimeout: 2000,
readTimeout: 2000,
});
httpRequest.destroy();
return response.responseCode === 200;
} catch {
httpRequest.destroy();
return false;
}
}

build() {
Column() {
if (this.serverReady) {
Expand Down
4 changes: 2 additions & 2 deletions hvigor/hvigor-config.json5
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"hvigorVersion": "5.0.2",
"modelVersion": "5.0.0",
"dependencies": {
"@ohos/hvigor-ohos-plugin": "5.0.2"
"@ohos/hvigor-ohos-plugin": "5.10.3"
},
"execution": {},
"logging": {
Expand Down
8 changes: 5 additions & 3 deletions oh-package.json5
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
"bugs": {
"url": "https://github.com/electerm/electerm-harmony/issues"
},
"dependencies": {},
"modelVersion": "5.0.0",
"dependencies": {
"entry": "file:./entry"
},
"devDependencies": {
"@ohos/hypium": "1.0.21",
"@ohos/hvigor-ohos-plugin": "5.0.2"
"@ohos/hypium": "1.0.21"
}
}
Loading
Loading