Skip to content

Add toolchain like features - #7

Draft
UnsignedArduino wants to merge 32 commits into
dagfrom
toolchain
Draft

UnsignedArduino wants to merge 32 commits into
dagfrom
toolchain

Conversation

@UnsignedArduino

Copy link
Copy Markdown
Owner

No description provided.

@UnsignedArduino UnsignedArduino self-assigned this Aug 1, 2026
@UnsignedArduino
UnsignedArduino marked this pull request as draft August 1, 2026 00:15
UnsignedArduino and others added 27 commits July 31, 2026 20:34
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mbb9ZcpdvCZoLyyheJd2FF
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mbb9ZcpdvCZoLyyheJd2FF
- Add the required `target:` to the e2e fixture config.
- Install the toolchain and target in a session fixture before building.
- Remove `cache=False` so builds are incremental.
- Check the second build by parsing redun's job status table (every job
  CACHED, none DONE) instead of wall-clock time.
- Update the project context doc, including the newly exposed stale-cache
  issue for inputs redun can't see.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drop the main-only base filter on pull_request so stacked PRs (dag,
toolchain) get CI. Pushes still only trigger on main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- MKCD2APP_HOME moves data/state dirs to $MKCD2APP_HOME/{data,state}/<version>.
  The e2e tests install into .pytest_cache/d/mkcd2app-home with it, so they
  don't touch the real user dirs and reruns hit the install cache.
- Rename `build --clear-cache` to `--full-rebuild` and explain in its help
  text that it's how to pick up changes to source files, icons, or GitHub
  branches, which aren't tracked automatically.
- Update the project context doc (CI green on all OSes, roadmap, decision
  to rely on --full-rebuild for out-of-band inputs).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- download_sim decodes downloads as UTF-8 instead of res.text (which falls
  back to ISO-8859-1 without a charset), and all text file reads/writes pass
  encoding="utf-8" so Windows doesn't use cp1252.
- get_resource_template_path(name) now actually joins name.
- load_config_from_yaml raises NotImplementedError for a missing/unknown
  version instead of AttributeError.
- Fix uninstall_toolchain and fill_website_template docstrings, drop a stray
  comment in "Racers offline.yaml", and update the project context doc.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…file

install_deps_and_build_website* hashed the whole filled site, so any game or
asset change re-ran npm ci. install_website_deps now runs npm ci once from
only the template's package.json and package-lock.json, and the renamed
build_website* tasks copy that node_modules into their own site copy and run
only npm run build*. static and static-singlefile share the one install.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cloning and checking out a `github` code source now uses dulwich (pure
Python) in `utils/git.py`, so a globally installed `git` is no longer
required.

Branches and tags get a shallow `depth=1` + `branch=` clone. Anything
else is treated as a (possibly short) commit SHA and gets a full clone
followed by a checkout. That clone checks out the default branch first,
because dulwich's checkout only writes files that differ from the current
HEAD tree and leaves the worktree empty when the target's tree matches
HEAD. Clone progress is only shown with --debug, since dulwich's
\r-separated progress floods non-TTY logs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mbb9ZcxTDte5nuYr92ZaBg
Add a `git` code source taking any URL dulwich can clone (https, http,
git, file, or ssh with an `ssh` binary) and an optional `ref` (branch,
tag, or commit SHA; omitted means the remote's default branch), so games
can come from GitLab, Codeberg, or self-hosted servers. The `github`
source stays as an alias with its existing `value`/`checkout` fields, and
`fetch_code` handles both in one case.

Add the first unit tests: config parsing for both source types, and
`clone_and_checkout` against a local repo built with dulwich so they run
offline, including the same-tree-as-HEAD empty worktree regression.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mbb9ZcxTDte5nuYr92ZaBg
Decode the MakeCode project embedded in a shareable PNG or UF2 (format
detected by magic bytes) into the usual -source folder, warning when the
saved Arcade version differs from the configured target. Adds the repo's
first unit tests, covering synthetic PNG (incl. overflow rows) and UF2
round trips, error cases, and path traversal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mbb9ZdVK71NaCgpyqUP1Wf
Falling duck PNG and UF2 (4.1.27) for the unit tests, and the empty game
exported as a PNG from 4.0.14 for a new e2e test that builds it with a
file code source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mbb9ZdVK71NaCgpyqUP1Wf
Compare the extracted main.ts against the PNG's embedded bytes, and
against the checked-in fixture as text, since git's autocrlf gives the
fixture CRLF on Windows while extraction keeps the embedded LF.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mbb9ZdVK71NaCgpyqUP1Wf
A ZIP (e.g. GitHub's Download ZIP) is detected by magic bytes like PNG and
UF2. The project root is wherever pxt.json is, at the top level or inside
one wrapping folder, which is stripped. Directories and symlinks are
skipped, entry count and uncompressed size are capped, and names go
through the existing traversal check. Adds the Racers Download ZIP as a
fixture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mbb9ZdVK71NaCgpyqUP1Wf
The test zips tests/fixtures/empty_game under an empty_game-master/
wrapper at run time and builds it as a file source, checking the
extracted files byte for byte against the checkout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mbb9ZdVK71NaCgpyqUP1Wf
- is_strict_semver uses fullmatch so "4.0.14\n" is rejected; BuildConfig.target
  is validated as strict semver when the config loads.
- project.title is rendered with a single-pass substitution of {NAME},
  {VERSION} and {AUTHOR} instead of str.format, so other braces no longer
  crash the build and substituted values aren't expanded again.
- The title is HTML-escaped before it goes into index.html.
- The index.html title and favicon markers must each appear exactly once;
  template drift now raises instead of silently doing nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mbb9ZbdDZ5goMxMi7N2f4j
pytest-cov runs on every pytest invocation (--no-cov to skip), and
tests/conftest.py marks each test unit or e2e by its directory, so
`uv run pytest -m unit` runs only the fast offline tests. CI is unchanged:
`uv run pytest` still runs everything.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mbb9ZdHu1tFP2ZhM62pbgq
- test_code.py: fetch_code for every source type, the target mismatch
  warning, build_binary_js, and copy_support_files with path/URL icons
- test_website.py: copy/fill the real bundled template (title, favicon,
  package.json, copy-on-write), install_website_deps, and both website
  builds including node_modules symlinks
- test_redun_compat.py: the get_proto patch and content-based dir hashing
- extract_meta_comment, utils/paths, run_cmd, rmtree_robust, resources

Tasks run through .func with run_cmd and network calls monkeypatched, so
everything stays offline. Unit coverage goes from 42% to 66%.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mbb9ZdHu1tFP2ZhM62pbgq
unit.yaml runs `pytest -m unit` with coverage and no Node.js setup, so unit
results come back in seconds instead of after the toolchain install.
e2e.yaml now runs only `pytest -m e2e --no-cov`, since coverage can't see
the mkcd2app subprocess the e2e tests drive. Both run on all three OSes and
neither waits for the other.

Because CI now selects by marker, tests/conftest.py fails collection for a
test outside tests/unit and tests/e2e, which would otherwise run in
neither workflow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mbb9ZdHu1tFP2ZhM62pbgq
UnsignedArduino and others added 4 commits November 3, 2026 19:24
Expand unit tests, add coverage, and split unit/e2e CI
- test_semver.py: is_strict_semver / raise_for_invalid_strict_semver over valid
  and invalid versions (including a trailing newline), and BuildConfig rejecting
  a non-semver target.
- test_website.py: render_title placeholders, literal braces, no double
  expansion; HTML escaping of the title; fill_index_html and
  fill_website_template raising when the title or favicon marker is missing,
  duplicated, or reformatted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mbb9ZbdDZ5goMxMi7N2f4j
- uninstall_toolchain/uninstall_target use cache_scope=NONE: they return
  None, so a cached result made a second uninstall after a reinstall a no-op.
- MKCD2APP_HOME is ~-expanded and made absolute, so mkc and npm --cache
  paths still point at the install when subprocesses run elsewhere.
- Embedded PNG/UF2 text is decoded the way LZMA-JS writes it (CESU-8, each
  UTF-16 code unit separately), so projects with emoji import, and UF2
  headerSize is applied in UTF-16 code units. Fixtures come from real
  LZMA-JS (tests/fixtures/embedded/lzma-js/generate.cjs).
- UF2 blocks are reassembled into runs instead of one dense image from the
  lowest to the highest address; payload sizes and the total size are
  checked before anything is allocated.
- run_redun_task closes its SQLite session and engine after each run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mbb9ZbdDZ5goMxMi7N2f4j
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants