Skip to content

Commit 367a01f

Browse files
feat: init cli
0 parents  commit 367a01f

32 files changed

+2544
-0
lines changed

.github/workflows/ci.yaml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: 'CI'
2+
3+
on:
4+
push:
5+
branches: [main]
6+
7+
pull_request:
8+
branches: [main]
9+
10+
env:
11+
DENO_DIR: ~/.deno-cache
12+
13+
jobs:
14+
ci:
15+
runs-on: ubuntu-latest
16+
17+
strategy:
18+
matrix:
19+
deno-version: [1.37.2]
20+
21+
steps:
22+
- name: Checkout
23+
uses: actions/checkout@v4
24+
25+
- name: Setup Deno ${{ matrix.deno-version }}
26+
uses: denoland/setup-deno@v1
27+
with:
28+
deno-version: ${{ matrix.deno-version }}
29+
30+
- name: Deno Lint
31+
run: deno lint
32+
continue-on-error: true
33+
34+
- name: Deno Format
35+
run: deno fmt --check
36+
continue-on-error: true
37+
38+
- name: Deno Info
39+
run: deno info src/index.ts
40+
41+
- name: Deno Compile [windows]
42+
run: deno task compile-win
43+
44+
- name: Deno Compile [macos]
45+
run: deno task compile-macos
46+
47+
- name: Deno Compile [linux]
48+
run: deno task compile-linux
49+
50+
- name: Cache Deno dependencies
51+
uses: actions/cache@v3
52+
with:
53+
path: ${{ env.DENO_DIR }}
54+
key: ${{ hashFiles('deno.lock') }}

.github/workflows/release.yaml

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
name: 'Release'
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
permissions:
9+
contents: write
10+
pull-requests: write
11+
12+
env:
13+
DENO_DIR: ~/.deno-cache
14+
15+
jobs:
16+
release:
17+
runs-on: ubuntu-latest
18+
19+
strategy:
20+
matrix:
21+
deno-version: [1.37.2]
22+
23+
steps:
24+
- uses: google-github-actions/release-please-action@v3
25+
id: release
26+
with:
27+
token: ${{ secrets.GH_RUNREAL_TOKEN }}
28+
pull-request-title-pattern: "chore${scope}: release${component} ${version}"
29+
release-type: simple
30+
extra-files: |
31+
README.md
32+
src/version.ts
33+
34+
- uses: actions/checkout@v4
35+
if: ${{ steps.release.outputs.release_created }}
36+
37+
- name: Setup Deno ${{ matrix.deno-version }}
38+
if: ${{ steps.release.outputs.release_created }}
39+
uses: denoland/setup-deno@v1
40+
with:
41+
deno-version: ${{ matrix.deno-version }}
42+
43+
- name: Deno Compile [windows]
44+
if: ${{ steps.release.outputs.release_created }}
45+
run: deno task compile-win
46+
47+
- name: Deno Compile [macos]
48+
if: ${{ steps.release.outputs.release_created }}
49+
run: deno task compile-macos
50+
51+
- name: Deno Compile [linux]
52+
if: ${{ steps.release.outputs.release_created }}
53+
run: deno task compile-linux
54+
55+
- name: Upload Artifacts
56+
if: ${{ steps.release.outputs.release_created }}
57+
env:
58+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
59+
run: gh release upload ${{ steps.release.outputs.tag_name }} ./build/runreal-win-x64.exe ./build/runreal-macos-arm ./build/runreal-linux-x64
60+
61+
- name: Cache Deno dependencies
62+
if: ${{ steps.release.outputs.release_created }}
63+
uses: actions/cache@v3
64+
with:
65+
path: ${{ env.DENO_DIR }}
66+
key: ${{ hashFiles('deno.lock') }}

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Changelog

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# runreal cli

deno.jsonc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"imports": {
3+
"/": "./src/",
4+
"./": "./",
5+
"std/": "https://deno.land/std@0.204.0/"
6+
},
7+
"tasks": {
8+
"start": "deno run -A --unstable --watch=src src/index.ts",
9+
"run": "deno run -A --unstable src/index.ts",
10+
"compile-win": "deno compile --unstable -A --target x86_64-pc-windows-msvc --output build/runreal-win-x64 src/index.ts",
11+
"compile-linux": "deno compile --unstable -A --target x86_64-unknown-linux-gnu --output build/runreal-linux-x64 src/index.ts",
12+
"compile-macos": "deno compile --unstable -A --target aarch64-apple-darwin --output build/runreal-macos-arm src/index.ts"
13+
},
14+
"lint": {
15+
"include": ["src/"],
16+
"rules": {
17+
"tags": ["recommended"],
18+
"include": ["ban-untagged-todo"],
19+
"exclude": ["no-unused-vars", "no-explicit-any"]
20+
}
21+
},
22+
"fmt": {
23+
"include": ["src/"],
24+
"useTabs": true,
25+
"lineWidth": 120,
26+
"indentWidth": 2,
27+
"singleQuote": true,
28+
"proseWrap": "preserve",
29+
"semiColons": false
30+
}
31+
}

deno.lock

Lines changed: 270 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/commands/build.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { Command, EnumType, ValidationError } from '/deps.ts'
2+
3+
import { createEngine, Engine, EngineConfiguration, EnginePlatform, EngineTarget } from '/lib/engine.ts'
4+
import { findProjectFile, getProjectName } from '/lib/utils.ts'
5+
import { GlobalOptions } from '/index.ts'
6+
import { config } from '/lib/config.ts'
7+
import { CliOptions } from '/lib/types.ts'
8+
9+
const TargetError = (target: string, targets: string[]) => {
10+
return new ValidationError(`Invalid Target: ${target}
11+
Valid Targets: ${targets.join(', ')}
12+
`)
13+
}
14+
export type BuildOptions = typeof build extends Command<any, any, infer Options, any, any> ? Options
15+
: never
16+
17+
export const build = new Command<GlobalOptions>()
18+
.description('build')
19+
.type('Configuration', new EnumType(EngineConfiguration))
20+
.type('Platform', new EnumType(EnginePlatform))
21+
.option('-p, --platform <platform:Platform>', 'Platform', { default: Engine.getCurrentPlatform() })
22+
.option('-c, --configuration <configuration:Configuration>', 'Configuration', {
23+
default: EngineConfiguration.Development,
24+
})
25+
.option('-d, --dry-run', 'Dry run')
26+
.arguments('<target:string>')
27+
.action(async (options, target = EngineTarget.Editor) => {
28+
const { platform, configuration, dryRun } = options as BuildOptions
29+
const { engine: { path: enginePath }, project: { path: projectPath } } = config.get(options as CliOptions)
30+
31+
const engine = await createEngine(enginePath)
32+
const validTargets = await engine.parseEngineTargets()
33+
const extraArgs = []
34+
35+
const projectFile = await findProjectFile(projectPath).catch(() => null)
36+
if (projectFile) {
37+
extraArgs.push(`-project=${projectFile}`)
38+
validTargets.push(...(await engine.parseProjectTargets(projectPath)))
39+
}
40+
41+
// Shorthand target specifier: Editor, Game, Client, Server
42+
if (Object.values(EngineTarget).includes(target as EngineTarget)) {
43+
if (projectFile) {
44+
const projectName = await getProjectName(projectPath)
45+
target = `${projectName}${target}`
46+
} else {
47+
target = `Unreal${target}`
48+
}
49+
}
50+
51+
if (!validTargets.includes(target)) {
52+
throw TargetError(target, validTargets)
53+
}
54+
55+
if (dryRun) {
56+
console.log(`[build] enginePath: ${enginePath}`)
57+
console.log(`[build] projectPath: ${projectPath}`)
58+
console.log(`[build] projectFile: ${projectFile}`)
59+
console.log(`[build] command: ${configuration} ${target} ${platform}`)
60+
}
61+
62+
// const manifest = `${enginePath}/Manifests/${target}-${configuration}-${platform}-Manifest.xml`
63+
// extraArgs.push(`-Manifest=${manifest}`)
64+
extraArgs.push('-NoUBTMakefiles')
65+
extraArgs.push('-NoHotReload')
66+
extraArgs.push('-TraceWrites')
67+
extraArgs.push('-NoXGE')
68+
// extraArgs.push('-UsePrecompiled')
69+
70+
// Build Target
71+
// Build.bat TestProjectEditor Win64 Development -project=E:\Project\TestProject.uproject
72+
await engine.runUBT({
73+
target,
74+
configuration: configuration as EngineConfiguration,
75+
platform: platform as EnginePlatform,
76+
extraArgs,
77+
dryRun,
78+
})
79+
})

src/commands/buildgraph/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { Command } from '/deps.ts'
2+
3+
import { GlobalOptions } from '/index.ts'
4+
import { run } from './run.ts'
5+
6+
export const buildgraph = new Command<GlobalOptions>()
7+
.description('buildgraph')
8+
.command('run', run)

src/commands/buildgraph/run.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { Command, path, readNdjson } from '/deps.ts'
2+
import { config } from '/lib/config.ts'
3+
import { GlobalOptions } from '/index.ts'
4+
import { CliOptions } from '/lib/types.ts'
5+
import { createEngine } from '/lib/engine.ts'
6+
7+
export type RunOptions = typeof run extends Command<any, any, infer Options, any, any> ? Options
8+
: never
9+
10+
interface AutomationToolLogs {
11+
time: string
12+
level: string
13+
message: string
14+
format: string
15+
properties: Record<string, string>
16+
}
17+
18+
async function getAutomationToolLogs(enginePath: string) {
19+
const logJson = path.join(enginePath, 'Engine', 'Programs', 'AutomationTool', 'Saved', 'Logs', 'Log.json')
20+
let logs: AutomationToolLogs[] = []
21+
try {
22+
logs = await readNdjson(logJson) as unknown as AutomationToolLogs[]
23+
} catch (e) {
24+
// pass
25+
}
26+
return logs
27+
}
28+
29+
export const run = new Command<GlobalOptions>()
30+
.description('run buildgraph script')
31+
.arguments('<buildGraphScript:file> <buildGraphArgs...>')
32+
.stopEarly()
33+
.action(async (options, buildGraphScript: string, ...buildGraphArgs: Array<string>) => {
34+
const { engine: { path: enginePath } } = config.get(options as CliOptions)
35+
const engine = await createEngine(enginePath)
36+
const { success, code } = await engine.runBuildGraph(buildGraphScript, buildGraphArgs)
37+
if (!success) {
38+
const logs = await getAutomationToolLogs(enginePath)
39+
logs.filter(({ level }) => level === 'Error').forEach(({ message }) => console.log(`[BUILDGRAPH RUN] ${message}`))
40+
Deno.exit(code)
41+
}
42+
})

0 commit comments

Comments
 (0)