hilink-urllc
32
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a225f75f6d |
hi3518ev300: add an RTL8188EU profile with the driver in the kernel, and drop excludes firmware now handles (#157)
Follow-up to OpenIPC/firmware#2410, which left MT7601U as the only in-tree USB Wi-Fi stack on hi3518ev300. RTL8188EU lands here as a camera profile, splitting the two adapters across the two repositories. hi3518ev300_lite_generic-rtl8188eu builds the driver INTO the kernel rather than shipping it as a module: a profile whose only Wi-Fi is that driver has no reason to carry it as loadable code, and the rootfs is the partition under pressure. The out-of-tree rtl8188eus-openipc cannot make that move -- it is an external kernel-module package, never linked into vmlinux -- so this uses the in-tree staging driver at CONFIG_R8188EU=y through a variant kernel config, the same shape as gk7205v200.generic-otg.config. Built in, the driver also has no modprobe problem: as a module it was unreachable, because /etc/wireless/usb's rtl8188eu-generic profile modprobes '8188eu' while the in-tree module is 'r8188eu'. Linked into the kernel it binds off its own USB device table at boot. CONFIG_R8188EU selects WIRELESS_EXT, so the wext ABI firmware#2410 dropped comes back on this variant only. It requests rtlwifi/rtl8188eufw.bin, so linux-firmware-openipc comes with it. Registered in .github/firmware-drift.json against the firmware blob it derives from. MEASURED in CI, against the module-based version of the same profile: uImage [1873KB/2048KB] -> [1991KB/2048KB] 56KB free rootfs.squashfs [5084KB/5120KB] -> [4728KB/5120KB] 392KB free Also drops excludes entries firmware now handles upstream: r8188eu.ko from xiaomi-mjsxj02hl, and r8188eu.ko + scsi_mod.ko + sd_mod.ko from yuancam-dgk423403. Both cameras build green; both run out-of-tree Realtek drivers over nl80211 and are otherwise unaffected. Not tested on a camera. This changes which 8188EU driver is used -- mainline staging rather than the Realtek vendor fork -- so it wants confirmation that a dongle is detected at boot without a modprobe, associates, and streams. |
||
|
|
3bd11b95cc |
Rename hi3518ev300_lite_bathhouse to yuancam-dgk423403 (#153)
The device is a YuanCam-branded (HQLS/hdwificam OEM) HI3518EV300 board —
confirmed on a lab unit via its Factory.bin/SysParam.bin tags
("YuanCamFactory"/"YuanCamSysparam") and its P2P device id
(DGK-423403-YZHGE). Rename the placeholder "Bathhouse" profile to a
proper vendor-model name and fill in the sensor, identified on hardware
with ipctool as JXH62 (previously "?" in the README table). The
defconfig, customizer.sh and excludes list carry over unchanged except
for the upgrade URL, which now points at the renamed release asset.
|
||
|
|
694749162c |
Stop shipping a dangling /etc/sensors/iq/default.ini (#150)
The osdrv packages create default.ini as a symlink to one fixed sensor's
IQ file -- imx307.ini for hisilicon-osdrv-hi3516ev200 and
goke-osdrv-gk7205v200. Two device profiles prune that exact file to fit
NOR and leave the symlink behind, so the image ships a default.ini that
resolves to nothing.
majestic answers that silently. init_iq_monitor() (src/hisi/sdk.c) has no
default for isp.iqProfile, falls through to /etc/sensors/iq/default.ini,
and returns on `access(default_prof, 0) != 0` without logging at any
level. No IQ profile means no monitor thread, so SCENE_Set3DNR() never
runs and VPSS keeps the single static NRX block from scene.c tune_vpss()
at every ISO. The explicit-iqProfile path does log "Cannot find %s file";
only this fallback is mute.
Measured on a lab hi3516ev300_85h50ai (IMX335, nightly-20260904-605fa9d)
against a night scene at ISO ~30000, changing nothing but the profile
majestic loads:
dangling imx335.ini
RTSP, 20 s capture 14.13 Mbit/s 3.54 Mbit/s
/proc/umap/rc InsBr 14310 kbps 3626 kbps
StartQp 42 (= MaxQp) 31
3DNR SFS2 5/16/0/30 36/60/60/52
3DNR TFS 1/7/12/10 5/9/13/11
The encoder was configured correctly the whole time -- VBR 4096, MinQp
28, MaxQp 42. Rate control pinned at MaxQp while still emitting 14 Mbit/s
is what an undenoised sensor at ISO 30000 costs, not a bitrate that was
ignored. It reads as "the bitrate setting does nothing" and "3DNR is
off", which is how it was reported.
hi3516ev300_lite_xm-85h50ai keeps imx335.ini and runs an IMX335, so
general/overlay now carries a default.ini aimed at it. BR2_ROOTFS_OVERLAY
is rsynced after the packages install and rootfs_script.sh runs the
excludes list after that, so the overlay's symlink replaces the package's
and the pruning that follows is harmless. This also stops the board
loading an IMX307 profile for an IMX335 sensor, which is what it would
have got had imx307.ini simply been kept.
gk7202v300_lite_ipg-g3-wr prunes every IQ file its package installs
(imx307, imx335, sc2232), so there is nothing to aim a symlink at. It
drops default.ini instead. Behaviour is unchanged -- majestic already
loads no profile there -- but the image stops carrying a broken link that
would silently start resolving to the wrong sensor's profile the moment
one of those entries goes stale. The board runs jxh63, which no shipped
IQ file covers; a note in the list records that keeping imx307.ini costs
126 KB if it turns out to want one.
An audit of every device profile against its SoC's osdrv package finds no
others: the rest either keep the symlink's target, remove default.ini
already, or pin .isp.iqProfile in customizer.sh.
|
||
|
|
c2f5024972 |
ci: check the setting paths shipped scripts hand to cli (#146)
* ci: check the setting paths shipped scripts hand to cli
`cli -s` cannot fail. yaml-cli stores whatever dotted path it is given,
creating intermediate mappings as it goes, and exits 0; majestic then silently
ignores a key it does not recognise. So a typo in a setting path applies
nothing and reports nothing, from the moment it is written to the end of the
device's life.
t40_lite_movols-mo-805p has been shipping six of them:
cli -s .video0.bitrate: 4000
cli -s .video0.rcMode: avbr
The path is `.video0.bitrate:`, not `.video0.bitrate`. Bitrate, rate-control
mode, profile, GOP size, GOP mode and OSD size have never applied on that
camera. The trailing colons are dropped here, including the one on the
commented-out `.onvif.enabled:`, which was a trap for whoever uncommented it.
The linter checks shape and nothing else. Whether a well-formed key is one a
given majestic build actually declares can only be answered by the running
binary -- it varies by vendor and by flavour -- while shape is decidable from
the tree, costs nothing, and is the whole of the class that shipped. A path
built at runtime is skipped rather than guessed at: uvc-gadget-setup reads
`cli -g ".$1"`, which is fine and unknowable here.
It carries a floor check for the same reason lint-workflow-shell.py does. A
matcher that quietly stops matching finds no bad paths, which looks exactly
like a clean tree -- so finding no cli invocation at all is itself a failure.
80 scripts scanned, 610 invocations, 6 bad paths, all in the one device.
* ci: recheck the merged result when the cli linter itself changes
lint.yml's push trigger names the checkers it guards one by one, and the new
one was not on the list -- so a master push touching only
.github/scripts/lint-cli-paths.py would have skipped the very job that exists
because #121 shipped a broken merged result nothing re-checked.
Same reasoning as the lint-workflow-shell.py entry beside it, and the same
cost: seconds, no runners.
|
||
|
|
605fa9dd97 |
hi3516ev300_lite_xm-85h50ai: ship the majestic-af autofocus plugin (#145)
Select BR2_PACKAGE_MAJESTIC_AF in the device defconfig so the test board's firmware carries /usr/lib/majestic-af.so out of the box. The package is defined in the firmware external tree (OpenIPC/firmware#2357, merged first); builder.sh clones firmware master, and the device build compiles the plugin from source (7caebdc6) and installs it — verified end-to-end in CI after the firmware merge. |
||
|
|
4f640b335b |
ssc377qe fpv: drop the prebuilt imx335 module (#139)
This overlay carried a 25KB sensor_imx335_mipi.ko because the driver OpenIPC built at the time could not reach the rates this board needs: its 2560x1920@60 mode served 30fps and its 90fps mode produced no usable output at all. The blob shadowed the built module and fixed it for this one device, and for nobody else. The source behind it is now what OpenIPC builds. openipc/sensors carries it as sigmastar/infinity6c/sensor_imx335_mipi.c instead of a symlink to the infinity6e driver (OpenIPC/sensors#3), and the infinity6c loader states the lane count it needs (OpenIPC/firmware#2343). sigmastar-osdrv-sensors is unpinned, and this device's defconfig already selects it -- BR2_PACKAGE_SIGMASTAR_OSDRV_INFINITY6C selects BR2_PACKAGE_SIGMASTAR_OSDRV_SENSORS -- so the module is built and installed to /lib/modules/5.10.61/sigmastar either way. The overlay copy was only ever shadowing it. Removing it means this device tracks the driver instead of freezing a copy of it, which is the point: the next person who needs a mode changed can change it. The built driver is a later revision than the blob (72ad30b against the 30fdac4 it came from) and measures the same or better on an SSC377QE, rebooting before every mode: 2592x1944@59 59.2 fps (blob 59.2) 2560x1920@60 60.1 fps (blob 58.4) 2208x1248@90 89.5 fps (blob 89.5) 1920x1080@120 116.1 fps (blob 119.6) Verified end to end on hardware afterwards: with the built module and the merged loader and nothing else, the loader applies lane_num=4 on its own and a 60fps request delivers 60.0. Nothing else in the overlay changes. |
||
|
|
832c2afa1a |
ci: let a pull request keep the image it just built (#135)
Verified on this PR's own run rather than merged on the reasoning. Across all 15 devices in the matrix: ``` Stage artifacts 15 success Upload build artifacts 15 success Send binary 15 skipped Publish releases skipped CI Gate success ``` 15 `fw-*` artifacts produced, and the retention the fix was about is what actually landed: ``` fw-hi3516ev300_ultimate_rvi-1ncmw2028 created 2026-08-27T21:17:00Z expires 2026-09-03T21:16:58Z -> 7 days ``` So a pull request now keeps the images it built, for a week, while the two paths that must stay closed to a PR -- the Telegram secret and shared release assets -- are still closed. |
||
|
|
fc476c895d |
ci: only lint real steps, and find the real end of an expression (#124)
Two bugs in the linter #122 added, found by Qodo reviewing the port of it to OpenIPC/firmware#2290 and confirmed against this copy rather than taken on trust. walk() collected any mapping with a scalar `run` key, anywhere in the document. That is one key name away from linting things that are not shell: an action input, an env var or a matrix field called `run` holds arbitrary text, and feeding it to bash -n fails a workflow that is fine. On a fixture with one real step plus an `env: run:` and a `with: run:`, this copy collects three blocks. Steps now have to come out of a `steps:` sequence, which is the actual schema invariant and still not a hardcoded jobs.*.steps[*] path, so composite actions (`runs: steps:`) keep working. The expression substitution used `\$\{\{.*?\}\}`, which stops at the first `}}` even when it is inside a string literal. On x=${{ fromJSON('{"a": {"b": 1}}') }} this copy produces `x=__GHA_EXPR__') }}` and bash -n then reports an unbalanced quote -- a false failure on a valid block, in the direction that trains people to ignore the job. Replaced with a scanner that tracks GitHub's single-quoted strings, including the doubled '' escape, and returns the text untouched if an expression is never closed. Both are latent here: nothing in this repo has a `run` key outside a step or a `}}` inside an expression string, and the block count is unchanged at 23. They are fixed because the failure mode is a red job with nothing wrong with the tree, which is how a check stops being believed. Self-tests for both. The docstring described the behaviour this replaces, so it is corrected too, and the now-unused `re` import drops. Keeps this copy identical to firmware's apart from the incident paragraph and the block floor. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
6872639ed8 |
ci: stop the lint job's apt step hanging for six minutes (#123)
The unconditional `apt-get update` added to satisfy review on #122 was fine on the PR runs (~5s) and then sat for six minutes on the first master push, still in progress when it was cancelled. Nothing was wrong with the tree; apt was just slow. That is a bad trade for this job in particular. Its argument for existing -- and for carrying a push trigger at all -- is that it answers in seconds, and it was made to depend on a network fetch it does not normally need. ubuntu-latest ships PyYAML. So import first and install only if that fails. The dependency is still handled rather than assumed, which was the point of the review finding, but a working runner pays nothing for it. `if` rather than `python3 -c 'import yaml' && exit 0`, because under `bash -e` the latter fails the step on the branch where the import fails -- exactly when the install needs to run. Both paths checked under -e. Also timeout-minutes: 10. The default is six hours, which is how a step that hangs rather than fails occupies a runner and tells nobody. The whole job now completes in three seconds, and selects 0 devices rather than 107 because #122 classified lint.yml as no-build. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
0455db0027 |
ci: close the if that cost last night's release, and parse-check the rest (#122)
The Collect guard added to the publish job in #121 shipped without its closing `fi`. Run 32096242353 -- the first nightly to reach the new single publish job -- built all 107 devices, staged 219 assets, and then died in `bash -e` with line 25: syntax error: unexpected end of file from `if' command on line 14 before writing anything. No nightly-20260818-* release exists, `nightly` and `latest` still carry the 17th's images, and ci-gate went red. The gate did its job; there was simply nothing left to publish by then. Nothing caught it earlier because the publish job carries `if: github.event_name != 'pull_request'` -- there are no artifacts to publish on a PR, so the entire path is unreachable from PR CI by construction. Both of #121's runs were green without ever executing the step. #121 said as much ("none of this path can run on a pull request") and checked the four states offline, but offline-checking the logic does not check that the script parses, and that is what broke. So the one-line fix, plus the check that would have caught it in seconds without a runner: lint-workflow-shell.py parses every `run:` block in .github/workflows/ with `bash -n`, and lint.yml runs it on PRs and on master pushes that touch either. Notes on the checker: - ${{ }} is not shell, so each expression is replaced with a plain word first. That is a real limitation -- an expression interpolating shell syntax is checked as the word, not as what it expands to -- and the substitution preserves line counts so reported lines still point at the right line. --self-test asserts an unterminated `if` containing an expression is still rejected while the closed form passes, because the way this breaks is by making everything pass. - Steps are found by walking for any mapping with a `run:` key rather than by the jobs.*.steps[*] path, so nothing depends on guessing where they live, and a discovery floor fails the run if the walk stops finding them. A checker that silently checks nothing looks exactly like a clean tree. - Syntax only. It says nothing about quoting or `-e` semantics; a shellcheck pass wants per-block disables for the substitution above and is a separate change. actionlint would cover more and is worth considering later; keeping this narrow is what makes it noise-free now. ci-matrix.py classifies both new files as no-build. They were names it had never heard of, and unknown widens by design, so the first push queued all 107 devices to prove a one-line YAML fix -- #121, which touched only master.yml, ran 19. This PR still took the full matrix because it edits ci-matrix.py itself, which always widens; the selector is not trusted to pick a smaller matrix for its own changes. PyYAML is installed explicitly rather than inherited from the runner image, and the workflow declares `contents: read` rather than taking the repo default. Both from review; neither would have failed the job today. Verified: the checker flags the merged master.yml with the same message the runner gave, passes the fixed tree, and all five guard states behave as #121 intended -- normal night publishes, a broken download and a green-but-empty dist both fail, and a dead matrix with nothing built still exits clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
5701c6710a |
ci: write releases from one paced job, not from 107 at once (#121)
* ci: write releases from one paced job, not from 107 at once Every matrix job uploaded its images to three shared releases with softprops/action-gh-release, so a nightly fired on the order of 400 concurrent asset writes at `nightly`, `latest` and the dated tag. OpenIPC/firmware ran exactly this design and the releases API answered HTTP 500 under the contention -- run 27108181857 built every board and still went red on 14 jobs, all of them in their upload step. Firmware then hit the sequel: consolidating into one job but keeping concurrent uploads tripped the per-actor secondary rate limit at 350 of 393 assets. This lands where that ended up, without the two failures in between. Matrix jobs now stage what they produced into dist/ and hand it to actions/upload-artifact. A single publish job downloads all of it and drives the release writes with gh: one asset at a time, paced ~1/s under the per-minute mutation ceiling, with exponential backoff so a transient 403/429 is retried rather than failing the nightly. The single-writer property is what fixes the 500s; the pacing is what keeps the fix from tripping the other limit. The dated release keeps the full asset set, because enrich_manifest.py only ever reads dated releases. `nightly` and `latest` are delivery aliases for flashers and now get images only: re-uploading the size sidecars to two more tags is pure rate-limit cost, and nothing reads them from those tags. Staging copies whichever of the two naming schemes the build used -- compound devices rename to <device>-<flash>.tgz in the workspace root, single-underscore ones leave openipc.<soc>-<flash>-<variant>.tgz under openipc/output/images/ -- so asset names are byte-identical to today. Checked both against enrich_manifest.py's COMPOUND_RE and SIMPLE_RE. ci-gate covers publish, so a failed release write fails the run instead of passing quietly. The staging loop uses `if` rather than a trailing `&&` chain: the step runs under `bash -e`, where a chain that tests false is only harmless because something after it happens to reset the status. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ci: stop the publish job succeeding without publishing Two High findings on #121, both real. The download step carried continue-on-error: true, so a transient or real artifact-download failure produced an empty dist/, the publish step's count guard skipped it, the job went green, and ci-gate accepts publish=success. A nightly could silently write nothing while the run stayed green. The flag stays -- it exists so a matrix where every device failed, and so uploaded no fw-* artifact at all, does not hard-fail before the gate can report why -- but Collect now turns it back into a failure for every other case: if the matrix went green, a download that did not succeed is an error, and zero collected assets is an error. Only "matrix failed and produced nothing" is still tolerated, and the gate fails that run on the matrix result anyway. The second finding said count could read " 0" because wc pads. On GNU coreutils, which is what the runner has, it does not -- that is BSD behaviour, and `printf '' | wc -l` here gives an unpadded 0. Normalised anyway, since it costs a tr and stops the guard depending on which wc is in front of it. Chasing it did surface a worse hole it sits next to. dist/ can hold sidecars and no images -- one device that produced a size report and no .tgz is enough -- and count is then 1, so publish ran, force-moved the nightly and latest tag refs, and uploaded zero images. The two tags users flash from would point at a build with no firmware behind them. Both tags now move only when there is at least one image to move them to; otherwise they stay on yesterday's, with a warning. Checked all four states offline, since none of this path can run on a pull request: green matrix with a broken download, green matrix with an empty dist, failed matrix with nothing produced, and a normal night. The first two now fail and used to pass. Note the same continue-on-error and unnormalised wc are in OpenIPC/firmware's publish job, which is where this one came from. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
edc0a0f88f |
ci: build pull requests, and only the devices they reach (#120)
* ci: build pull requests, and only the devices they reach This repo had no pull_request trigger at all. A change landed unbuilt, and the nightly found out the next morning -- or a user did. Turning PR CI on meant 107 device builds per push, which is why it stayed off. Almost every change here is one device: 639 of the file touches in the last 200 commits sit under a single devices/<dir>/, and the median commit reaches 2 devices. So narrowing first is what makes PR CI affordable at all. .github/scripts/ci-matrix.py maps the paths a PR touches to the devices that build them, and master.yml takes its matrix from it. The mapping is not written down, it is read off the tree the same way builder.sh reads it. builder.sh line 121 locates a device by its defconfig and copies that WHOLE devices/<dir>/ tree over the firmware clone, so the devices a file affects are exactly the devices whose defconfig shares its directory. That distinction is load-bearing: devices/common/ backs 18 targets and devices/apfpv/ backs 2, and treating a directory as one device would skip 17 real builds. A defconfig still names one target even inside a shared directory. THE NIGHTLY IS NOT NARROWED. builder.sh re-clones OpenIPC/firmware at HEAD on every run, so what a nightly builds is decided mostly outside this repo; master.yml already carries the scar of an earlier gate that skipped on this repo's HEAD and left upstream fixes invisible to users. Every event except pull_request gets the whole matrix, and --self-test asserts that for schedule, workflow_dispatch and push. Nothing on a pull_request may write a release. The three upload steps were gated only on an image existing, so with a pull_request trigger added they would have clobbered the published nightly and latest assets that users flash. They and the Telegram post are now guarded on the event. master.yml and check-adjacent plumbing get a 15-device smoke set rather than all 107: they decide how a build runs, not what it produces. --self-test enforces the cover -- every vendor, architecture, toolchain tuple and variant, plus both shared device directories -- rather than the list, so the set can be re-picked while the property holds. It already earned itself: the first run rejected my hand-picked set for missing arm-openipc-linux-gnueabi, which exactly one target in the tree has, and musleabihf. Also adds the CI Gate umbrella check, since a dynamic matrix cannot be named in branch protection and nothing reported a verdict before; and freezes the 7 defconfigs that exist but are in no matrix, so a device falling out of CI is a test failure rather than a silent skip. Replaying the last 200 commits: 20330 device-builds if every PR built everything, 5930 with the selector, 70.8% less, no coverage leaks. 43 of the 49 that still widen do so on paths that no longer exist (devices/ssc338q_apfpv/ before it became devices/apfpv/, the old top-level common/, a deleted builder-local.sh); restricted to commits whose paths survive, it is 78.2%. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ci: derive the device list instead of writing it down Adding a camera IS the work in this repo: 8 of the 10 PRs open right now add a device, and 14% of recent commits do. With the list written down in ci-matrix.py, every one of those PRs also had to edit that file -- and a change to that file cannot narrow, because it is what does the narrowing. So registering one camera cost a full 107-device build to prove one device. The most common change got the worst outcome. The matrix is now every defconfig under devices/, minus a NOT_BUILT opt-out that keeps the 7 already in the tree but out of CI. Adding a device is creating its directory, nothing else, and it builds exactly that device. This is the opposite call to OpenIPC/firmware's ci-matrix.py, on purpose. There the matrix is curated -- 29 defconfigs are deliberately never built and boards are not the product -- so an explicit list is the honest description and an opt-out list would be noise. Here devices are the product and the list is just "all of them". The derived matrix is identical to the 107 master.yml carried: nothing lost, nothing gained. --self-test now checks the opt-outs still name real defconfigs, so a rename cannot leave a device silently building under its new name while its old name sits in NOT_BUILT. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ci-matrix: own $GITHUB_OUTPUT instead of being redirected into it The docstring said the default mode writes $GITHUB_OUTPUT; it printed key=value lines to stdout and left the workflow to redirect them there. Raised in review on #120. Fixing the prose would have made the file honest, but the redirect itself is the weaker half. Under `>> ${GITHUB_OUTPUT}` every print() in this file is one keystroke away from corrupting the step outputs, and a crash between the first line and the last leaves a half-written file that Actions still reads. That the diagnostics go to stderr is what keeps it safe today -- a rule that has to hold forever, rather than a property of the code. So the script appends the three lines itself when $GITHUB_OUTPUT is set, and prints them when it is not, so a local run still shows its decision. --stdin never touches the file: it is the mode for reading with your eyes. master.yml drops the redirect, though leaving one in place would have been harmless -- with the file written directly, stdout is empty. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
222db9e291 |
ci: keep inherited workflows from billing non-canonical repos (#118)
A clone of this repo pushed to a new repository -- a private mirror, an internal re-host -- inherits .github/workflows together with its cron. The full platform matrix then runs on that owner's Actions bill, nightly and unattended. Forks are only partially covered: GitHub disables scheduled workflows there, but nothing covers a fresh repository, and nothing warns the owner. This mirrors OpenIPC/firmware#2255, where the same inherited cron was measured at 97 jobs and 2,146 billed minutes from a single unattended night, and never converged: publishing failed on the mirror, so the sha skip-gate could never engage and the matrix rebuilt in full every night. The rule: unattended runs happen only on the canonical repo. Anywhere else a workflow runs only if someone explicitly asked for it (workflow_dispatch), or if it is both free and attended (pull_request on a public repo). This is deliberately stricter than gating purely on cost -- a public re-host's minutes are free and its cron is still skipped, because a re-host quietly publishing nightly releases under its own name is a worse outcome than wasted minutes. master carries the guard on preflight; buildroot needs it and inherits the skip. manifest gates its cron-originated workflow_run path the same way, because a nightly whose jobs all skipped still completes and fires workflow_run. cleanup carries it on its weekly cron. build-one is dispatch-only and needs nothing. The pull_request clause is unreachable here today -- no workflow in this repo has a pull_request trigger -- and is kept on purpose: it is the clause that lets contributor PRs run, and omitting it would mean adding a pull_request trigger later silently skips CI on every fork. That over-block was the first thing reviewers caught upstream. Upstream impact is none: on OpenIPC/builder the first disjunct is true, so every added condition is a tautology and each job's if reduces to what it was before. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
94cce13948 |
gk7205v200: flip dwc3 to host before unbinding xhci (otg) (#114)
Booting the otg profile with /etc/usbmode = device made S72usbmode's
`usb-mode device` log, on every single boot:
xhci-hcd xhci-hcd.0.auto: Host not halted after 16000 microseconds.
xhci-hcd xhci-hcd.0.auto: Host controller not halted, aborting reset.
dwc3_core_init() leaves GCTL.PRTCAPDIR = OTG(3) and this 4.9 dwc3 never
moves off OTG on its own. xhci-hcd binds and registers both buses on top
of that anyway, but it is not actually driving the port -- so unbinding
straight from OTG asks xhci_halt() to halt a host that was never really
running, and it times out.
The gadget composed regardless, so this was cosmetic in practice, but it
left the host controller un-halted: exactly the live-DMA-engine state the
unbind is there to avoid.
Flip the controller to host before unbinding, so the already-bound xHCI
is genuinely running and the unbind halts cleanly. A switch from host is
already in that state, so only boot pays for the extra flip.
Measured on gk7205v200 (Xiongmai IPC_GK7205V200_50H20AI_S38): 5/5 cold
boots warned before, 0/5 after. Runtime host<->device round trips stay
clean and still take ~0.35s, with no reboot and no majestic restart.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
96633d5577 |
gk7205v200: add an OTG profile that makes the camera a USB webcam (#113)
Adds gk7205v200_otg_generic, a firmware profile that puts the single DWC3 controller into dual-role so the board can either consume a USB webcam (existing usbcam path, host role) or present itself to a PC as one (UVC gadget, device role). The roles are mutually exclusive -- xHCI HCSPARAMS1 reports MaxPorts = 1 -- but usb-mode switches between them at runtime, so one image covers both and no reboot is needed. Kernel side, three patches: 0015 sets dr_mode = "otg" in the DTS so dwc3 registers both an xHCI host and a UDC. 0016 makes device mode actually work on a part that has only ever run as a host. Three fixes: re-run dwc3_event_buffers_setup() on gadget start (an xHCI reset wipes GEVNTADR), soft-reset the core before taking the lock so the PHY is re-initialised (without it high-speed chirp fails), and swallow the run_stop timeout on pullup(0), which otherwise permanently poisons cdev->deactivations. 0017 disables the vendor's UVC_SG_REQ path. It hands a whole frame to the UDC as one scatter-gather request; dwc3 chains those sg entries into a single isochronous service interval, which on a full-speed link is one 1023-byte packet, so every frame larger than that reached the host truncated and H.264 decoders reported "bytestream -5" on roughly half the frames. Goke never shipped this path enabled -- CONFIG_USB_CONFIGFS_F_UVC is unset in every vendor defconfig, including gk7605v100's, and the SDK carries no userspace UVC sample -- so it was never exercised. The mainline path (32 plain one-packet requests) is used instead. Userspace side: usb-mode switches roles with the unbind/flip/bind sequencing dwc3_set_mode() does not do on its own, uvc-gadget-setup composes the configfs gadget, and S72usbmode forces a concrete role at boot -- not optional, since dr_mode = "otg" leaves GCTL.PRTCAPDIR in a state this 4.9 dwc3 never moves off by itself. The descriptors advertise exactly the one format, frame size and interval majestic is configured to serve, read from /etc/majestic.yaml. majestic answers every PROBE/COMMIT with its own bFormatIndex/bFrameIndex because it has one stream and cannot follow the host, so anything extra is an invitation to select something that will not arrive: asking for MJPEG got raw H.264 (an SPS where a JPEG SOI belongs, garbage to every consumer), and asking for 1080p got 720p. Profile drops the air-unit packages (wifibroadcast, rtl8812au, mavfwd, mavlink-router, vtund, linux-firmware, wireless-tools) and the whole wireless kernel stack, which pays for usb_f_uvc.ko and for keeping the full sensor list -- the fpv trim to IMX307/IMX335 is keyed on OPENIPC_VARIANT="fpv", and a general-purpose USB webcam should not be sensor-locked. Measured on a gk7205v200 lab board over a full-speed link: H.264 1280x720 at 30 fps with zero decoder errors and no dropped buffers, and MJPEG delivering valid JPEGs at the jpeg channel's own rate. Requires a majestic built with ENABLE_UVC_GADGET to feed the gadget; that is a separate change. |
||
|
|
6c0a45e66d |
gk7205v200: enable USB (UVC) webcam kernel support (fpv) (#112)
Enable the media / V4L2 / uvcvideo kernel stack so a USB camera exposes /dev/videoN for majestic's usbcam second-camera path. To fit the 8M NOR (2M kernel / 5M rootfs) without dropping any sensor library, uvcvideo and the videobuf2 framework are built INTO the kernel (=y) instead of shipped as rootfs modules: the kernel partition had ~55 KB of spare room while the rootfs was tight, so ~44 KB of weight moves from rootfs to kernel. Resulting images: uImage 2022.8 KB / 2048 KB (25 KB spare), rootfs squashfs 5080 KB / 5120 KB (40 KB spare). GSPCA -- a separate driver for non-UVC webcams, pulled in by "default m depends on VIDEO_V4L2" -- is disabled. No kernel patch is carried: mmap capture works on stock uvcvideo once majestic aligns its mmap() prototype with this MMAP_MUSL build's uint32_t-offset shim (a userspace fix), so the earlier read()/fileio uvcvideo patch is not needed. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
9d85e993fb |
ci: evict majestic's moving S3 tarball from the dl cache too (#109)
PR #105 added a "Refresh moving-ref package downloads" step that drops *-{HEAD,master,main,dist}.tar.gz before each build so buildroot re-fetches the current ref. That fixed the majestic-webui-dist.tar.gz staleness (the *-dist.tar.gz case), but it never matched majestic itself. majestic downloads from S3 as majestic.<family>.<variant>.master.tar.bz2 (majestic.mk) — a DOT separator, .tar.bz2, and an S3 host the old pattern deliberately spared as "content-addressed". But that S3 object is a moving `master` build, re-uploaded on every majestic CI run, with no .hash to force a refetch. So it stayed frozen in the monthly builder-dl cache while the webui refreshed — the exact desync that shipped a pre-x-groups majestic in a t31 lite image against the current webui, blanking the settings page with "No settings groups in schema." Broaden the eviction to a regex covering both -ref and .ref separators across gz/bz2/xz, so majestic.*.master.tar.bz2 and majestic-webui-dist.tar.gz are both dropped while semver/SHA-pinned tarballs keep their cache. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
d6a1c32761 |
docs: add CLAUDE.md for Claude Code (#107)
Document the builder overlay model (per-device deltas layered onto a fresh OpenIPC/firmware clone), the build flow in builder.sh, device directory anatomy, the package/ and devices/common/ conventions, the CI workflows (including the moving-ref cache caveat), and a step-by-step "Adding a new device" walkthrough. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
97356e0cfe |
ci: re-fetch moving-ref package downloads each build (#105)
builder caches BR2_DL_DIR (/tmp/builder-dl) under a monthly key (date +%m), and
actions/cache only saves on a key miss, so the first build of the month freezes it for
weeks. Packages pinned to a moving ref (VERSION = HEAD/branch, or the majestic-webui
`dist` release asset) download as a constant <pkg>-<ref>.tar.gz, so buildroot keeps
reusing the stale tarball — defeating the clean firmware-HEAD re-clone builder does for
freshness.
Empirically, a 2026-06-14 builder nightly shipped a ~2-week-old majestic-webui (full
bootstrap.min.css, no mj-settings.js) while the firmware nightly of the same day shipped
the current slim UI. Drop *-{HEAD,master,main,dist}.tar.gz before each build (master.yml
+ build-one.yml) so buildroot re-fetches the current ref. Mirrors the same fix in
OpenIPC/firmware.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
21de4f7b92 |
ci: drop sizes.json URLs from manifest.json (CORS-blocked in browsers) (#103)
Mirror of OpenIPC/firmware#2169. PR #102 extended enrich_manifest.py with SIZES_COMPOUND_RE + SIZES_SIMPLE_RE + parse_sizes() so the public manifest carried `platforms[<plat>].sizes.url` and `@sizes` lines pointing at each release's sizes.json asset. The intent was a browser-side consumer; the GitHub release-asset URLs return no Access-Control-Allow-Origin header, so every browser fetch was blocked by CORS. This commit reverts only the manifest-indexing half of #102. The release-asset upload itself stays in master.yml — server-side consumers can still read the JSON via `gh release download` or any CI workflow. Only the in-manifest URL is removed, because that URL only made sense for an in-browser reader that turns out can't reach it. The resulting enrich_manifest.py is bit-for-bit identical to the pre-#102 state. Co-authored-by: John <zekccsripfwrocp-15689@yn.furvionx.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
da13271f94 |
ci: mirror firmware's size-report sidecar (OpenIPC/firmware#2166) (#102)
Firmware PR #2166 added a `size-report` Makefile target + the `general/scripts/size_report.py` analyser that emits a per-package / per-kernel-module `sizes.<soc>-<variant>.json` next to the .tgz. Builder clones firmware fresh on every run and shells to `make BOARD=...`, so the script + target are already available downstream — this PR adds the CI wiring and manifest extension so the JSON ships as a release asset and surfaces through https://openipc.github.io/builder/manifest.json. Three changes: * `builder.sh`: best-effort `make size-report` after the main build, and copy `sizes.*.json` into the timestamped archive next to `.tgz` / `rootfs.squashfs.*`. Failure is swallowed so a legacy `OPENIPC_FW_REV` pin to a pre-#2166 firmware ref can't sink the build. * `.github/workflows/master.yml`: new `Build size report` step after the existing `Build firmware`. Mirrors the bimodal rename trick the .tgz path already does — compound matrix entries (`<soc>_<variant>_<vendor>-<model>`) share `<soc>_<variant>` and would otherwise collide on the firmware-side `sizes.<soc>-<variant>.json` filename when uploaded to the same release tag. Compound entries get the JSON renamed to `sizes.<NAME>.json`; simple entries keep `sizes.<soc>-<variant>.json`. `${{env.SIZES}}` is added to all three upload `files:` blocks (dated / nightly / latest). * `.github/scripts/enrich_manifest.py`: `SIZES_COMPOUND_RE` + `SIZES_SIMPLE_RE`, a `parse_sizes()` helper that tries compound first (because `[^._-]+` in the simple soc class would otherwise accept the compound form too), the sidecar is recorded at the platform level under a `"sizes"` key in `manifest.json`, and a new `@sizes <build_id> <platform> <size> <url>` line type is emitted in `manifest.flat` alongside the existing `@channel` directive. Schema is unchanged for existing consumers — on-device sysupgrade reads positional 4-column `manifest.flat` lines and stays inert on unknown `@`-prefixed directives. Co-authored-by: John <zekccsripfwrocp-15689@yn.furvionx.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
83faaad635 |
toolchain: drop legacy gcc 8.4 pin (mirror firmware #2162) (#101)
OpenIPC/firmware PR #2162 (merged 2026-05-30) dropped the legacy BR2_TOOLCHAIN_EXTERNAL_GCC_8=y + BR2_GCC_VERSION_LEGACY=y block from its 18 ARM defconfigs and ships gcc 13.3.0 to those platforms now. OpenIPC/builder's per-device and common Goke defconfigs still pinned gcc 8, so every Goke job in the 2026-06-02 nightly Build run failed at the toolchain stage with: Incorrect selection of gcc version: expected 8.x, got 13.3.0 make[1]: *** [toolchain-external-custom/.stamp_configured] Error 1 Mirror #2162 across the 24 affected defconfigs (8 common + 16 per-device). No other defconfig content changes. Unrelated 4 Sigmastar rootfs-overflow failures in the same nightly are tracked separately. Fixes failing run: https://github.com/OpenIPC/builder/actions/runs/26804792607 Co-authored-by: John <zekccsripfwrocp-15689@yn.furvionx.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
2febc00893 |
cleanup: grant actions:write and skip manifest refresh on no-op (#100)
Mirrors OpenIPC/firmware#2133. Today's scheduled cleanup run failed with HTTP 403: Resource not accessible by integration when dispatching manifest.yml — the prune job only declared contents:write. The refresh step also fires on the empty-prune path (exit 0 only exits the step, not the job), which is wasted work since manifest.yml is already kept fresh by master.yml's workflow_run. Add actions:write to the permissions block, and gate the refresh on a step output so it runs only after an actual deletion. Co-authored-by: John <zekccsripfwrocp-15689@yn.furvionx.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
a36a2d50aa |
ci: always rebuild on schedule (drop builder-HEAD-only dedupe) (#98)
The preflight gate skipped scheduled runs whenever this repo's HEAD matched the SHA recorded in the previous nightly release body. That key ignores every upstream input the build actually depends on: OpenIPC/firmware HEAD, the toolchain release, the kernel tarball, the vendor osdrv packages, and individual buildroot package upstreams. builder.sh re-clones OpenIPC/firmware fresh on every run, so those inputs do move between nightlies even when this repo is quiet. The concrete failure mode this caused: on 2026-05-26 OpenIPC/firmware bumped its hisilicon-opensdk pin to b958db4, which contains the V4 mipi_rx vsync IRQ fix (openhisilicon PR #195, closes #194 — torn frames / 'Timeout from venc channel 0' on hi3516ev200, gk7205v200, gk7205v210, gk7205v300, hi3516ev300 hardware). The next builder nightly (2026-05-27 07:00 UTC) ran with this repo unchanged since 2026-05-25, so preflight skipped the entire Firmware matrix. Field cameras (verified: gk7205v210_lite_vixand-ivg-g4h at IP redacted, running BUILD_ID nightly-20260526-ee40da8, srcversion 8EF923DF907C1F7F3C6898E — the pre-fix open_mipi_rx fingerprint from PR #195's verification table) kept pulling the stale 'latest' release asset and kept showing the regression after sysupgrade. A cross-input dedupe key would be possible (firmware HEAD + toolchain URL hash + ...) but enumerates every upstream this build pulls. Simpler and correct: scheduled nightlies always build. workflow_dispatch is unaffected — that path was already unconditional. Co-authored-by: Dmitry Ilyin <zekccsripfwrocp-15689@yn.furvionx.com> |
||
|
|
910c6326a3 |
ci: cache Buildroot dl/ at /tmp/builder-dl (mirrors firmware's dl cache) (#96)
OpenIPC/firmware/.github/workflows/build.yml has a `output/dl` cache
step that mirrors the Buildroot download directory across runs. This
saves both runner-minutes and — importantly — masks transient upstream
mirror failures: once any cron has cached the canonical tarball for a
package, every subsequent run reuses it regardless of whether the
primary URL is healthy that day.
builder's master.yml + build-one.yml had no equivalent. Each cron run
fully re-downloads the entire dl/ tree, so every package's upstream
must be healthy in every run. Hit hard 2026-05-24 by
wireguard-tools-1.0.20210914.tar.xz: it's served from a cgit
`snapshot/` URL on git.zx2c4.com which regenerates the tarball
per-request with shifting sha256, and `sources.buildroot.net` also
served drifted bytes — see kaeru
'wireguard-zx2c4-tarball-regeneration-hash-drift'. Result: random
matrix entries fail with hash mismatches each cron, with selection
roulette-style (93 boards enable wireguard; on any given run a few
roll snake-eyes on the download).
Mirror firmware's pattern with one wrinkle: builder.sh does
`rm -rf openipc` at the top of every run to force a clean re-clone of
firmware, which would obliterate `openipc/output/dl/` if we cached the
default path. Cache `/tmp/builder-dl` instead (outside the openipc
tree) and point Buildroot at it via BR2_DL_DIR env var, honored per
Buildroot manual section "Location of source tarballs". Same restore +
save lifecycle as firmware's, same monthly key shape.
Effect:
- First cron after merge: full download as usual; warms /tmp/builder-dl.
- Subsequent crons: instant cache hit for unchanged packages; only
re-download for version bumps. Removes the wireguard-roulette class
of failure entirely once cache is populated.
build-one.yml gets the same treatment so single-board dispatches share
the cache pool.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
7b0757eb0e |
xg521: update device override for 60fps→high-fps rename in firmware (#95)
OpenIPC/firmware PR #2090 (2026-05-13, "IMX335 companion to openhisilicon #99") renamed `general/package/goke-osdrv-gk7205v200/ files/sensor/config/60fps/` to `high-fps/`. The xg521 device-specific goke-osdrv-gk7205v200.mk override here still references the old path, causing every cron build of gk7202v300_lite_xg521 to fail: /usr/bin/install: cannot stat 'general/package/goke-osdrv-gk7205v200// files/sensor/config/60fps/*.ini': No such file or directory Update the two install lines to use `high-fps` matching the renamed upstream directory. Target install path also moves from /etc/sensors/60fps → /etc/sensors/high-fps for consistency with what the rest of the V4 sensor presets use. The matching exclude-list entry in devices/gk7202v300_lite_xg521/general/scripts/excludes/gk7202v300_lite.list references /etc/sensors/60fps/... and is now stale; left as-is since `rm -f` on a non-existent path is a no-op (rootfs_script.sh: xargs -I % rm -f ${TARGET_DIR}%). Can be cleaned in a follow-up. Other Goke device overlays (gk7205v200_lite_*, gk7205v210_lite_*, gk7205v300_lite_*) only have the same exclude-list staleness and no broken install rule, so they aren't affected by this bug. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
25ed956610 |
build-one: add firmware_ref input for cross-repo bisect (#94)
When investigating a regression that lives in OpenIPC/firmware (or its
referenced packages like hisilicon-opensdk) but only manifests in a
builder build, you previously had to either roll firmware master back
or fork builder.sh manually. Adds a clean way:
gh workflow run build-one.yml -f platform=hi3516ev200_fpv \
-f firmware_ref=<sha-or-tag-or-branch>
The workflow exports OPENIPC_FW_REV as env, which builder.sh now
honours: when set, it does a full clone (not --depth=1) and checks
out the requested ref before invoking the firmware build. When unset,
behaviour is unchanged (shallow clone of master HEAD).
Immediate motivation: bisect the +180 KB rootfs growth in
hi3516ev200_fpv between 2026-05-08 (5016 KB) and 2026-05-24 (5196 KB,
76 KB over partition limit). Per kaeru
'hi3516ev200-ev300-fpv-rootfs-size-overflow-2026-05-24'. Suspect is
recent hisilicon-opensdk bumps that brought in source-built sensor
drivers for ev200; bisect across firmware commits varying
HISILICON_OPENSDK_VERSION will pinpoint which bump pushed us past
the 5120 KB limit.
Generally useful long after this specific incident:
- Reproducing user-reported regressions at a specific firmware tag.
- Locking builds to a known-good firmware revision when builder is
ahead of firmware.
- Future cross-repo bisects of any kind.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
c427c735b5 |
ci/build-one: accept arbitrary commit input; publish to nightly-bisect-* tag (#93)
PR-Bld-C in the mirror of OpenIPC/firmware's nightly redesign. Mirrors OpenIPC/firmware#2116. Adds an optional `commit` workflow_- dispatch input to `build-one.yml` so: - `gh workflow run build-one.yml -f platform=X -f commit=<sha>` builds the given SHA from `git bisect run`. - Output goes to `nightly-bisect-<short>` (prerelease) tag, distinct from the dated `nightly-YYYYMMDD-<short>` namespace produced by PR-Bld-A's master.yml. The manifest aggregator's regex only indexes `^nightly-[0-9]{8}-[0-9a-f]{7}$`, so one-off bisect rebuilds never enter manifest.{json,flat}. - Without `commit`, falls back to building HEAD and tags as `nightly-bisect-<short>-<UTC ts>` so repeated dispatches of the same HEAD don't collide. Also: - Retry budget around `bash builder.sh` matching master.yml + OpenIPC/firmware#2129's hardening. - BUILD_ID / BUILD_SHA / BUILD_PLATFORM env at the Build firmware step level (forward-compat with Phase 3 of the mirror plan). - Drops dead `env: TAG_NAME: latest` at workflow level. - Release body carries sha/short/platform/one_off=true for the aggregator's downstream consumers to easily distinguish bisect builds from dated nightlies. See ~/.claude/plans/mirror-nightly-redesign-to-builder.md. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
63994266e2 |
ci/nightly: manifest aggregator + 90-build retention sweep (#92)
PR-Bld-B in the mirror of OpenIPC/firmware's nightly redesign. Adds
the two workflows that turn dated nightly-* releases (from PR-Bld-A)
into a queryable index served via GitHub Pages.
`manifest.yml` — triggers on successful `Build` workflow_run completion
(or manual dispatch). Runs `.github/scripts/enrich_manifest.py` to
enumerate dated releases, keep the 90 newest, parse the body
(sha/short/built_at from PR-Bld-A) and asset list, then emit:
- `manifest.json` — rich JSON for hosts/agents/CI.
- `manifest.flat` — whitespace-delimited columns
`build_id platform flash size url` plus `@channel` records,
parseable by pure busybox `awk` (no jq, no jsonfilter) for
on-device sysupgrade in Phase 2.
Both committed to the `gh-pages` branch (already bootstrapped).
`cleanup.yml` — Mondays 06:00 UTC (offset by +1h from firmware's
05:00 UTC cleanup). Deletes dated nightly releases beyond the 90
newest via `gh release delete --cleanup-tag`, then re-triggers
manifest.yml.
`enrich_manifest.py` differs from firmware's only in the asset parser:
builder produces TWO filename forms (per `master.yml`'s COMMON awk
trick that counts underscores in the matrix entry name):
- **Compound** `<soc>_<variant>_<vendor>-<model>-nor.tgz` →
platform key = the full string. This is the common case
(per-device builds).
- **Simple** `openipc.<soc>-<flash>-<variant>.tgz` (firmware-style,
when matrix name has one underscore) → platform key =
`<soc>_<variant>`.
The platform key gets carried into manifest.flat as a single column.
sysupgrade's existing `awk '$2==p'` lookup works unchanged; Phase 3
(model-aware BUILD_PLATFORM field in os-release) will let cameras
filter against the full per-model key.
URLs after merge:
https://openipc.github.io/builder/manifest.json
https://openipc.github.io/builder/manifest.flat
(`gh-pages` branch + Pages config already set up; mirrors firmware-
side setup.)
Concurrency-grouped `gh-pages-manifest` so manifest.yml and
cleanup.yml can't race the gh-pages push.
Includes the retry hardening from firmware OpenIPC/firmware#2129
(4-attempt backoff for transient GitHub API 401/5xx, fast-fail on
permanent 404).
First-run behaviour validated locally: empty index emits explicit
placeholder. Parser unit-tested across 7 synthetic filenames covering
compound, simple, and edge cases.
See ~/.claude/plans/mirror-nightly-redesign-to-builder.md.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
6bf71492fd |
ci/nightly: SHA-gate cron, publish dated nightly-* releases, BUILD_ID env (#91)
Mirror the OpenIPC/firmware nightly redesign (PRs #2111-#2129) to builder. This commit is PR-Bld-A: the build.yml-side changes only. Subsequent PRs add the manifest aggregator + retention sweep (PR-Bld-B) and the build-one.yml commit input (PR-Bld-C). Changes: 1. **Preflight SHA gate**. New `preflight` job reads `sha=` from the rolling `nightly` release body. On schedule events it short- circuits the matrix when HEAD matches the previously-published SHA; PRs and workflow_dispatch always build. Mirrors firmware's #2111. 2. **Three release tags per build**: - `nightly-YYYYMMDD-<short>` (prerelease, content-addressable, the unit of history — 90-day retention via PR-Bld-B's cleanup.yml). - `nightly` (rolling channel pointer; body carries sha/short/ built_at). - `latest` (legacy alias, kept one cycle so existing sysupgrade clients hitting the old hardcoded URL don't break). 3. **`BUILD_ID` / `BUILD_SHA` / `BUILD_PLATFORM` env** exported at the job level from preflight outputs. firmware's rootfs_script.sh (which builder.sh reuses via its clone of firmware) picks BUILD_ID + BUILD_SHA into /etc/os-release automatically. BUILD_PLATFORM is set to the matrix entry (e.g. `gk7205v200_fpv_caddx-fly`) and is forward-compatible with Phase 3 of the mirror plan (the firmware- side rootfs_script.sh update that emits BUILD_PLATFORM as an os-release field). 4. **Retry budget** around `bash builder.sh`. Matches firmware's `30 60 120 300 600 1200` ladder, covering toolchain/CDN flakes (#2115 + #2129 in firmware). 5. **Telegram caption** leads with `Build: <build_id>`; obsolete `Tag: ${TAG_NAME}` line gone; workflow-level `env: TAG_NAME= latest` removed. No on-device firmware changes; builder cameras keep their existing sysupgrade legacy URL until Phase 2 of the mirror (sysupgrade variant routing) lands in OpenIPC/firmware. See ~/.claude/plans/mirror-nightly-redesign-to-builder.md. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
49dc2fdb33 |
ci: add build-one workflow for single-platform test builds (#88)
The Build workflow's matrix-of-everything makes it slow and noisy to test a single device profile. Mirrors the build-one workflow already present in OpenIPC/firmware. Takes a full platform name (e.g. hi3518ev200_lite_switcam-hs303-v2) and runs only that build via builder.sh. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
92a237e82a |
enable opensdk for all CV200-family device profiles (#86)
Add BR2_PACKAGE_HISILICON_OPENSDK=y to 9 hi3516cv200-family profiles that were missing it. These boards will now get open_ modules built from openhisilicon source instead of vendor-only blobs from osdrv. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |