Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ci): Use metadata for builds #889

Merged
merged 3 commits into from Feb 3, 2022

Conversation

Nicell
Copy link
Member

@Nicell Nicell commented Aug 2, 2021

Refactors the build workflow to use hardware metadata to accomplish the following:

  • Nightly, build every single onboard MCU board and board+shield combo possible
  • Whenever app/** is changed (minus app/boards), run a short, premade core builds list
  • Whenever app/boards is changed, build every board+shield combo that's affected by the changes

Here's a nightly build: https://github.com/Nicell/zmk/actions/runs/1519228121
Here's a boards change run: https://github.com/Nicell/zmk/actions/runs/1517831312
Here's a core run: https://github.com/Nicell/zmk/actions/runs/1517789825

Todo:

  • make the final compile-matrix output remove all duplicates includes.
  • add cmake-args to artifact name in some fashion
  • figure out 256 matrix job limit (do one job per board rather than one job per board + shield combo)
  • get-changed-files seems to fail after squashes and PRs (alternative action with fixes: https://github.com/Ana06/get-changed-files)
  • don't inline the core build list (use a separate .yml file)
  • make sure to build setting-reset shield (update link to them on docs)

print("Failed validation of: " + file)
print(vexc)

exit(1 if failure else 0)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exit() is supposed to only be used from within the Python interactive interpreter from what I understand. You probably want sys.exit() instead.

metadata = yaml.safe_load(stream)
ret = validate(metadata, schema)
except yaml.YAMLError as exc:
failure = True
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it would be simpler to just

print(exc)
sys.exit(1)

instead of having a common exit point. You've already hit an error, so you should probably bail immediately.

Alternatively, you could wrap all of this up in another function and have it re-raise the exceptions with added info, then have a single handler that prints the error and exits. It might look something like this:

class MetadataError(Exception):
    pass

def do_run(self, args, unknown_args):
    try:
        self.validate_files()
    except MetadataError as e:
        print(e)
        sys.exit(1)
        
def validate_files(self):
    # ...
    try:
        # ...
    except yaml.YAMLError as e:
        # Use .format() instead of f-strings if we care about Python < 3.6
        raise MetadataError(f'Failed loading YAML file "{file}": {e}') from e
    except ValidationError as e:
        raise MetadataError(f'Failed validation of file "{file}": {e}') from e

...which I kinda like because all the logic for printing an error is in one spot instead of spread across multiple exception handlers.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, the point is to continue, so we can check all the files. Then if any fail... we return a non-zero exit code.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We specifically don't want to exit early.

with open(file, 'r') as stream:
try:
metadata = yaml.safe_load(stream)
ret = validate(metadata, schema)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ret appears unused?


## Overview

ZMK leverages an additional metadata YAML file for all boards and shields to provide high level information about the hardware to be leveraged by setup scripts/utilities, proper inclusion in the website hardware list, etc.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super minor: using "leverage" twice makes this read a bit awkwardly to me. Maybe just use "use" and/or "to be read by setup scripts" to keep things easy to understand?

(If you change this, Ctrl+F "leverage" since it's used in a few other places too.)

@joelspadin
Copy link
Collaborator

Whoops. I am on the wrong PR. Those comments apply to #883.

Copy link
Contributor

@petejohanson petejohanson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like a good start. I think in general, the code could be cleaned up, even if the you can't declare functions in github script, you could define lambdas and use them, to make the code clearer, e.g. const mapBoard = (metadata) => foo.

script: |
// break out to file
const coreCoverage = {
boards: [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was assuming we'd tag these boards and shields somehow in the .zmk.yml file, or maybe with an extra .core-build empty file, or something, to detect these automatically. Thoughts?

{
"board": "nice_nano_v2",
"shield": "kyria_left",
"cmake-args": "-DCONFIG_ZMK_DISPLAY=y",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this, we could find any boards w/ the display feature, and pass this as an arg to build it, to determine this dynamically.

{
"board": "nice_nano",
"shield": "romac_plus",
"cmake-args": "-DCONFIG_ZMK_RGB_UNDERGLOW=y -DCONFIG_WS2812_STRIP=y"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto, use the features for this.

Comment on lines 162 to 171
let include = [];

coreCoverage.boards.forEach(b => {
coreCoverage.shields.forEach(s => {
include.push({
board: b,
shield: s
});
});
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The purist in me says, do it functionally, darn it!

Suggested change
let include = [];
coreCoverage.boards.forEach(b => {
coreCoverage.shields.forEach(s => {
include.push({
board: b,
shield: s
});
});
});
let include = coreCoverage.boards.flatMap(board => coreCoverage.shields.map(shield => ({ board, shield }));

(I may have the JS syntax slightly wrong)

yaml.loadAll(fs.readFileSync(f, "utf8"))
);

aggregated.forEach(hm => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar grumblings about using forEach here instead of mapping, but this also works fine.

@Nicell Nicell force-pushed the workflow/metadata-build branch 7 times, most recently from c5bc344 to 55a9a05 Compare November 29, 2021 04:33
app/core-coverage.yml Outdated Show resolved Hide resolved
.github/workflows/build.yml Show resolved Hide resolved
.github/workflows/build.yml Show resolved Hide resolved
@Nicell Nicell marked this pull request as ready for review November 29, 2021 17:46
@Nicell Nicell force-pushed the workflow/metadata-build branch 5 times, most recently from 2991f12 to aa6b86c Compare November 29, 2021 20:32
@Nicell Nicell added the enhancement New feature or request label Nov 29, 2021
Copy link
Contributor

@petejohanson petejohanson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems really close! A few tweaks to make the experience a tad nicer needed before we merge.

.github/workflows/build.yml Show resolved Hide resolved
app/core-coverage.yml Outdated Show resolved Hide resolved
.github/workflows/build.yml Outdated Show resolved Hide resolved
.github/workflows/build.yml Show resolved Hide resolved
.github/workflows/build.yml Outdated Show resolved Hide resolved
@Nicell
Copy link
Member Author

Nicell commented Jan 14, 2022

@petejohanson Improved the logging with groups/errors as suggested. Also simplified the combining code using your suggestion, thanks. Let me know what you think now. I still want to add settings-reset to the nightly build and also add cmake args to the artifacts, but I'm not sure the best way to do either if you have suggestions. Have an idea for the settings-reset at the very least.

@petejohanson
Copy link
Contributor

@Nicell Perhaps for the cmake-args case, we expect you to also pass a build-nickname or build-name that's used, and if someone fails to provide that, just do something like (pseudo-code): build-args-${m5dsum(args-string)} to give it a unique name?

@Nicell
Copy link
Member Author

Nicell commented Jan 28, 2022

@petejohanson I added nicknames, you can see it on the core build of this PR. Works well. I've simply removed the spaces from cmake-args as the alternate rather than doing a hash, since it's more readable this way and just a fallback.

I had some thoughts about settings-reset I think we need to address, so I'm not sure if I'm going to add that to this PR. I think this is mostly ready to go then from my point of view.

Copy link
Contributor

@petejohanson petejohanson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One minor tweak needed, then good to go. Thanks!

.github/workflows/build.yml Outdated Show resolved Hide resolved
Copy link
Contributor

@petejohanson petejohanson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thanks!

@petejohanson petejohanson merged commit edbbbc7 into zmkfirmware:main Feb 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants