Skip to content

feat: add make notices for third-party license aggregation#234

Merged
lockwobr merged 1 commit into
mainfrom
worktree-3rd-party
May 14, 2026
Merged

feat: add make notices for third-party license aggregation#234
lockwobr merged 1 commit into
mainfrom
worktree-3rd-party

Conversation

@lockwobr

Copy link
Copy Markdown
Collaborator

Summary

Adds an aicr-inspired third-party notices workflow. Generates per-component THIRD_PARTY_NOTICES.md files (operator/CLI via go-licenses, agent via
pip-licenses) plus a combined rollup at the repo root, regenerates them at release time, and attaches the appropriate file to every component GitHub
release. Adds a path-gated merge-gate workflow for go-licenses check and drops that check from make lint's prerequisites. Deletes the stale
hand-curated NOTICE file.

Why

  • The hand-curated NOTICE at the repo root had drifted from reality (mixed Go + Python, no clear regen path, no CI gate).
  • aicr ships a THIRD_PARTY_NOTICES.md per release; skyhook should have the same attribution story.
  • make lint was running license-check on every developer's local lint cycle, even when deps hadn't changed. Moving it to a path-filtered CI job
    keeps the gate but takes it off the hot path.

What changed

New: notices generator

File Purpose
scripts/generate-notices.py Single Python script (~235 lines, stdlib-only). Subprocesses go-licenses for the operator pass and pip-licenses
(inside a cached venv at agent/.notices-venv) for the agent pass, then composes a root rollup by inlining both component files with their #
headings demoted outside fenced code blocks.
operator/THIRD_PARTY_NOTICES.md Generated. 62 Go deps.
agent/THIRD_PARTY_NOTICES.md Generated. 1 Python dep (jsonschema).
THIRD_PARTY_NOTICES.md (root) Generated rollup of the two.

New: Makefile targets

make notices            # regenerates all three files
make notices-operator   # operator + CLI Go deps only
make notices-agent      # agent Python deps only
make notices-rollup     # root rollup only (requires the two above to exist)

The agent pass caches a venv at agent/.notices-venv. First run ~30s (installs pip-licenses + the agent's pinned deps); subsequent runs ~2s.

New: merge-gate CI workflow

.github/workflows/merge-gate.yaml mirrors aicr's verify-licenses pattern:

  • check-paths uses dorny/paths-filter@v3 to detect changes to operator/go.mod, operator/go.sum, or operator/vendor/**.
  • verify-licenses runs make -C operator license-check only when those paths change.
  • verify-licenses-skip is a paired skip job — keeps required-check parity when deps don't change, so branch protection requiring verify-licenses
    doesn't block PRs that don't touch deps.

Modified: release workflow

.github/workflows/release.yml now regenerates the notices files in CI and attaches the appropriate one to the GitHub release based on the tag
prefix:

Tag pattern Asset uploaded
operator/v* operator/THIRD_PARTY_NOTICES.md
agent/v* agent/THIRD_PARTY_NOTICES.md
chart/v* THIRD_PARTY_NOTICES.md (rollup — chart packages both images)

Upload uses gh release upload --clobber so the step is idempotent on workflow re-runs.

Modified: operator/Makefile

  • lint: golangci-lint license-checklint: golangci-lint. The license-check target itself is unchanged; CI invokes it via the merge-gate
    workflow.

Removed: NOTICE

Stale hand-curated file at the repo root. Apache-2.0 attribution is satisfied by the repo LICENSE plus the generated THIRD_PARTY_NOTICES.md files.
No remaining references in source.

Docs

  • docs/release-process.md — new "Third-Party Notices" section explaining the three files, the four make targets, prerequisites, when to
    regenerate, and both CI workflows.
  • CONTRIBUTING.md — new bullet under "Pull Requests" reminding contributors to run make notices when bumping Go or Python deps.

New patterns introduced (per .claude/CLAUDE.md)

Upload uses gh release upload --clobber so the step is idempotent on workflow re-runs.

Modified: operator/Makefile

  • lint: golangci-lint license-checklint: golangci-lint. The license-check target itself is unchanged; CI invokes it via the merge-gate
    workflow.

Removed: NOTICE

Stale hand-curated file at the repo root. Apache-2.0 attribution is satisfied by the repo LICENSE plus the generated THIRD_PARTY_NOTICES.md files.
No remaining references in source.

Docs

  • docs/release-process.md — new "Third-Party Notices" section explaining the three files, the four make targets, prerequisites, when to
    regenerate, and both CI workflows.
  • CONTRIBUTING.md — new bullet under "Pull Requests" reminding contributors to run make notices when bumping Go or Python deps.

New patterns introduced (per .claude/CLAUDE.md)

Calling these out explicitly since none exist elsewhere in the repo today:

  • dorny/paths-filter is new to skyhook's workflows. Justification: aicr uses it, and it's the cleanest way to satisfy the "required-check always
    passes" property via a paired skip job. Alternative paths: filter at trigger level doesn't give that property.
  • ##@ Licenses Makefile section — new section in the root Makefile. Trivially symmetric with existing ##@ Build, ##@ Test, etc.
  • pip-licenses as a build-time Python dependency, installed into a cached venv at agent/.notices-venv (gitignored). Replaces a hand-rolled
    agent/vendor/ walk. Standard tool; same role as go-licenses on the Go side.

CI behavior changes

  • PRs that change operator/go.{mod,sum} or operator/vendor/** now hit a new required check (verify-licenses). PRs that don't touch those paths
    see verify-licenses-skip complete in ~5 seconds — no impact.
  • Local make lint no longer runs license-check; make lint is now strictly golangci-lint. Run make -C operator license-check directly (or
    push to a PR) when you want to verify dep licenses locally.
  • Release runs add ~1 min for go-licenses install + notices regeneration.

Test plan

  • make notices regenerates all three files locally without error.
  • make notices-operator only touches operator/THIRD_PARTY_NOTICES.md (verify via mtime).
  • make notices-agent only touches agent/THIRD_PARTY_NOTICES.md.
  • make notices-rollup only touches the root file; errors with an actionable message if either component file is missing.
  • agent/THIRD_PARTY_NOTICES.md correctly lists jsonschema 4.23.0 with the MIT license text inlined.
  • operator/THIRD_PARTY_NOTICES.md lists all 62 Go deps.
  • Rollup file's heading demotion respects fenced code blocks (license texts with #-prefixed lines are not mangled).
  • make lint (under operator/) no longer invokes license-check.
  • make -C operator license-check still works standalone.
  • The merge-gate workflow runs on a PR that changes operator/go.mod; verify-licenses-skip runs on a PR that doesn't.
  • release.yml workflow uploads the correct file per component tag (verify on the next operator/agent/chart release, or via a release-dry-run).

@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a Merge Gate GitHub Actions workflow that conditionally verifies operator Go dependency license compliance when operator/go.mod, operator/go.sum, or operator/vendor/** change; updates the release workflow to run Go/Python setup, generate operator go-licenses, regenerate THIRD_PARTY_NOTICES.md, and upload the appropriate notices file to the GitHub Release; adds scripts/generate-notices.py to produce operator, agent, and rollup THIRD_PARTY_NOTICES.md outputs; adds Makefile targets to regenerate notices; adds agent/THIRD_PARTY_NOTICES.md; updates docs, CONTRIBUTING, lint CI exclusions, .gitignore, removes the top-level NOTICE file, and tweaks operator/Makefile lint prerequisites.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • NVIDIA/nodewright#233: Related changes touching .github/workflows/release.yml (chart publishing/publish-job dependencies).

Suggested reviewers

  • mskalka
  • rice-riley
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding Make targets and supporting infrastructure for third-party license aggregation via notices files.
Description check ✅ Passed The description is highly detailed and directly related to the changeset, covering the summary, rationale, all modified files, new patterns, CI behavior changes, and a comprehensive test plan.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-3rd-party

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
agent/THIRD_PARTY_NOTICES.md (1)

41-41: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix multiple consecutive blank lines.

The markdownlint pipeline failure indicates multiple consecutive blank lines at the end of the file (Expected: 1; Actual: 2). Remove the extra blank line.

📝 Proposed fix

Remove one blank line at the end of the file. The file should end with exactly one newline after the closing triple backticks.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent/THIRD_PARTY_NOTICES.md` at line 41, Remove the extra blank line at the
end of THIRD_PARTY_NOTICES.md so there is exactly one trailing newline after the
final closing triple backticks; open the file, delete the extra empty line
following the closing ``` fence so the file ends with a single newline.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/generate-notices.py`:
- Line 59: Rename the ambiguous loop variable `l` in the set comprehension used
to build `stdlib_ignore` to a descriptive name (e.g., `line` or `pkg_path`) to
improve readability; specifically update the comprehension expression in the
assignment to `stdlib_ignore = ",".join(sorted({l.split("/")[0] for l in
stdlib.splitlines() if l}))` by replacing `l` with the chosen name in every
occurrence (`{... for l in stdlib.splitlines() if l}`, and `l.split("/")[0]`) so
the logic remains unchanged but the variable is clearer.
- Around line 135-137: The helper function src is missing a return type
annotation; update its signature from def src(e): to def src(e) -> str: so the
function explicitly declares it returns a string (keeping the existing logic
that returns u or "n/a"), ensuring type consistency for callers and static type
checkers when using src.
- Around line 63-64: The current code calls shutil.rmtree(LICENSES_CACHE)
whenever LICENSES_CACHE.exists(), which will raise if LICENSES_CACHE is a file;
update the removal logic to either (a) check that LICENSES_CACHE.is_dir() before
calling shutil.rmtree(LICENSES_CACHE) or (b) wrap shutil.rmtree in a try/except
and handle OSError by logging and continuing, or call
shutil.rmtree(LICENSES_CACHE, ignore_errors=True); reference LICENSES_CACHE and
shutil.rmtree when making the change so the check/exception handling is applied
in the same location.

---

Outside diff comments:
In `@agent/THIRD_PARTY_NOTICES.md`:
- Line 41: Remove the extra blank line at the end of THIRD_PARTY_NOTICES.md so
there is exactly one trailing newline after the final closing triple backticks;
open the file, delete the extra empty line following the closing ``` fence so
the file ends with a single newline.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: b3f1a023-43cb-4401-b05c-cb8256f31b93

📥 Commits

Reviewing files that changed from the base of the PR and between 13294d3 and f63af78.

📒 Files selected for processing (12)
  • .github/workflows/merge-gate.yaml
  • .github/workflows/release.yml
  • .gitignore
  • CONTRIBUTING.md
  • Makefile
  • NOTICE
  • THIRD_PARTY_NOTICES.md
  • agent/THIRD_PARTY_NOTICES.md
  • docs/release-process.md
  • operator/Makefile
  • operator/THIRD_PARTY_NOTICES.md
  • scripts/generate-notices.py
💤 Files with no reviewable changes (1)
  • NOTICE

Comment thread scripts/generate-notices.py Outdated
Comment thread scripts/generate-notices.py Outdated
Comment thread scripts/generate-notices.py Outdated
@lockwobr
lockwobr force-pushed the worktree-3rd-party branch from f63af78 to 1cdc651 Compare May 13, 2026 23:55

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/release.yml:
- Around line 78-82: The workflow uses actions/setup-python@v6 with
python-version: '3.x', which can drift; update the setup step in the release.yml
(the actions/setup-python block) to pin a specific minor version (e.g., '3.13'
or the project-supported '3.10') instead of '3.x' so releases are
deterministic—modify the python-version field in that setup step to the chosen
explicit minor version.
- Around line 89-111: The release creation step should be made idempotent:
instead of unconditionally running gh release create in the "Create GitHub
Release" step, first check whether the release for "${{ github.ref_name }}"
already exists (e.g. call gh release view "${{ github.ref_name }}" and test its
exit code) and if it exists use gh release edit --title --notes to update it,
otherwise run gh release create --title --notes; keep the "Upload third-party
notices to release" step as-is but ensure it runs after the guarded create/edit
so uploads don’t fail when a release already exists (use the same "${{
github.ref_name }}" variable and NOTICES_FILE mapping in the case block).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: b18a747c-30c3-4485-a6a6-52dedec2abe8

📥 Commits

Reviewing files that changed from the base of the PR and between f63af78 and 1cdc651.

📒 Files selected for processing (13)
  • .github/workflows/lint-ci.yaml
  • .github/workflows/merge-gate.yaml
  • .github/workflows/release.yml
  • .gitignore
  • CONTRIBUTING.md
  • Makefile
  • NOTICE
  • THIRD_PARTY_NOTICES.md
  • agent/THIRD_PARTY_NOTICES.md
  • docs/release-process.md
  • operator/Makefile
  • operator/THIRD_PARTY_NOTICES.md
  • scripts/generate-notices.py
💤 Files with no reviewable changes (1)
  • NOTICE

Comment thread .github/workflows/release.yml
Comment thread .github/workflows/release.yml
@lockwobr
lockwobr force-pushed the worktree-3rd-party branch from 1cdc651 to 18f8449 Compare May 14, 2026 00:35

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
.github/workflows/release.yml (1)

97-101: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make the release step fully idempotent with create-or-edit logic.

Line 97 performs a check-then-create flow; on concurrent reruns this can still fail with already_exists, and existing releases never get refreshed title/notes. Prefer explicit create-or-edit handling.

Suggested minimal change
-          if ! gh release view "${{ github.ref_name }}" >/dev/null 2>&1; then
-            gh release create "${{ github.ref_name }}" \
-              --title "${{ github.ref_name }}" \
-              --notes "${{ steps.release_notes.outputs.notes }}"
-          fi
+          if gh release view "${{ github.ref_name }}" >/dev/null 2>&1; then
+            gh release edit "${{ github.ref_name }}" \
+              --title "${{ github.ref_name }}" \
+              --notes "${{ steps.release_notes.outputs.notes }}"
+          else
+            gh release create "${{ github.ref_name }}" \
+              --title "${{ github.ref_name }}" \
+              --notes "${{ steps.release_notes.outputs.notes }}" \
+              || gh release edit "${{ github.ref_name }}" \
+                --title "${{ github.ref_name }}" \
+                --notes "${{ steps.release_notes.outputs.notes }}"
+          fi
Does `gh release create <tag>` fail when a release for that tag already exists, and is `gh release edit <tag>` the recommended way to make rerun-safe/idempotent workflows?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml around lines 97 - 101, Replace the current
check-then-create flow that uses `gh release view` then `gh release create` for
`${{ github.ref_name }}` with an idempotent create-or-edit pattern: attempt `gh
release create "${{ github.ref_name }}" --title "${{ github.ref_name }}" --notes
"${{ steps.release_notes.outputs.notes }}"` and if it fails due to an existing
release (already_exists) call `gh release edit "${{ github.ref_name }}" --title
"${{ github.ref_name }}" --notes "${{ steps.release_notes.outputs.notes }}"` to
refresh title/notes; alternatively you can unconditionally call `gh release
edit` if the release exists (detectable via `gh release view`) and otherwise
create it—ensure you handle exit codes and stderr redirection the same way as
the original script.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/merge-gate.yaml:
- Around line 32-36: Update the license verification filter to include agent
dependency paths so changes to agent deps trigger verification: add
'agent/go.mod', 'agent/go.sum', and 'agent/vendor/**' to the filters block (in
the same style as 'operator/go.mod', etc.), and update the verify-licenses job
to also run the agent license check (e.g., invoke make notices-agent or the
equivalent Python dependency validation command) so both operator and agent
license checks run when their files change.

---

Duplicate comments:
In @.github/workflows/release.yml:
- Around line 97-101: Replace the current check-then-create flow that uses `gh
release view` then `gh release create` for `${{ github.ref_name }}` with an
idempotent create-or-edit pattern: attempt `gh release create "${{
github.ref_name }}" --title "${{ github.ref_name }}" --notes "${{
steps.release_notes.outputs.notes }}"` and if it fails due to an existing
release (already_exists) call `gh release edit "${{ github.ref_name }}" --title
"${{ github.ref_name }}" --notes "${{ steps.release_notes.outputs.notes }}"` to
refresh title/notes; alternatively you can unconditionally call `gh release
edit` if the release exists (detectable via `gh release view`) and otherwise
create it—ensure you handle exit codes and stderr redirection the same way as
the original script.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 16eef9f6-7fc4-4a5c-9bf6-f1004d5d5fcb

📥 Commits

Reviewing files that changed from the base of the PR and between 1cdc651 and 18f8449.

📒 Files selected for processing (13)
  • .github/workflows/lint-ci.yaml
  • .github/workflows/merge-gate.yaml
  • .github/workflows/release.yml
  • .gitignore
  • CONTRIBUTING.md
  • Makefile
  • NOTICE
  • THIRD_PARTY_NOTICES.md
  • agent/THIRD_PARTY_NOTICES.md
  • docs/release-process.md
  • operator/Makefile
  • operator/THIRD_PARTY_NOTICES.md
  • scripts/generate-notices.py
💤 Files with no reviewable changes (1)
  • NOTICE

Comment thread .github/workflows/merge-gate.yaml
ayuskauskas
ayuskauskas previously approved these changes May 14, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
.github/workflows/merge-gate.yaml (1)

32-36: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Consider adding agent dependency paths to the license verification.

The current filter only checks operator/ Go dependencies. Since the PR adds license generation for both operator and agent, changes to agent/vendor/** should also trigger verification.

📝 Suggested enhancement
          filters: |
            deps:
              - 'operator/go.mod'
              - 'operator/go.sum'
              - 'operator/vendor/**'
+             - 'agent/vendor/**'

And update the verify-licenses job to also regenerate/verify agent notices:

      - name: Check licenses
        env:
          GOFLAGS: -mod=vendor
        run: make -C operator license-check
+     - name: Verify agent licenses
+       run: make notices-agent
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/merge-gate.yaml around lines 32 - 36, The workflow filter
currently only covers operator dependency files ('operator/go.mod',
'operator/go.sum', 'operator/vendor/**') so changes to agent dependencies won’t
trigger license verification; update the filters:deps list to also include the
agent paths (e.g., 'agent/go.mod', 'agent/go.sum', 'agent/vendor/**') and update
the verify-licenses job (the verify-licenses job block) to run the agent notice
generation/verification steps in addition to the operator ones so agent license
changes are regenerated and verified.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In @.github/workflows/merge-gate.yaml:
- Around line 32-36: The workflow filter currently only covers operator
dependency files ('operator/go.mod', 'operator/go.sum', 'operator/vendor/**') so
changes to agent dependencies won’t trigger license verification; update the
filters:deps list to also include the agent paths (e.g., 'agent/go.mod',
'agent/go.sum', 'agent/vendor/**') and update the verify-licenses job (the
verify-licenses job block) to run the agent notice generation/verification steps
in addition to the operator ones so agent license changes are regenerated and
verified.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 2fda2885-fd14-4d18-bbd7-2be68c152590

📥 Commits

Reviewing files that changed from the base of the PR and between 18f8449 and 5bc51ac.

📒 Files selected for processing (13)
  • .github/workflows/lint-ci.yaml
  • .github/workflows/merge-gate.yaml
  • .github/workflows/release.yml
  • .gitignore
  • CONTRIBUTING.md
  • Makefile
  • NOTICE
  • THIRD_PARTY_NOTICES.md
  • agent/THIRD_PARTY_NOTICES.md
  • docs/release-process.md
  • operator/Makefile
  • operator/THIRD_PARTY_NOTICES.md
  • scripts/generate-notices.py
💤 Files with no reviewable changes (1)
  • NOTICE

@lockwobr
lockwobr merged commit 8c58f32 into main May 14, 2026
16 checks passed
@lockwobr
lockwobr deleted the worktree-3rd-party branch May 14, 2026 18:01
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