diff --git a/.github/scripts/select-unpublished.py b/.github/scripts/select-unpublished.py deleted file mode 100755 index a766e84..0000000 --- a/.github/scripts/select-unpublished.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python3 -"""Print the Mill selector for packages whose version is not on Maven Central yet. - -Reads `mill show __.artifactMetadata` on stdin and writes `count=` / `selector=` lines -suitable for $GITHUB_OUTPUT, with a per-package report on stderr. - -Which packages a release publishes is derived from Central rather than from -release-please's outputs, for two reasons. The publish job runs *before* the tagging half, -so those outputs do not exist yet; and asking Central makes the job idempotent — re-running -after a partial failure uploads exactly what is still missing, which is what the -workflow_dispatch escape hatch relies on. - -Caveat: repo1 lags a Portal publish by a few minutes, so a re-run started immediately after -a successful upload can still see a package as missing and try to publish it again, which -Central rejects. Wait for the deployment to reach PUBLISHED before re-running. -""" -import json -import subprocess -import sys - -BASE = "https://repo1.maven.org/maven2" - - -def published(group: str, artifact: str, version: str) -> bool: - """True if the POM is already on Central. Uses curl rather than urllib so the - system CA bundle is used; some Python installs do not have one configured.""" - path = f"{group.replace('.', '/')}/{artifact}/{version}/{artifact}-{version}.pom" - out = subprocess.run( - ["curl", "-sS", "-I", "--max-time", "30", "-o", "/dev/null", - "-w", "%{http_code}", f"{BASE}/{path}"], - capture_output=True, text=True, check=True, - ).stdout.strip() - if out == "200": - return True - if out == "404": - return False - raise RuntimeError(f"unexpected HTTP {out} for {path}") - - -def main() -> int: - meta = json.load(sys.stdin) - missing = [] - for task, m in sorted(meta.items()): - module = task[: -len(".artifactMetadata")] - coord = f"{m['group']}:{m['id']}:{m['version']}" - if published(m["group"], m["id"], m["version"]): - print(f" present {coord}", file=sys.stderr) - else: - print(f" MISSING {coord} ({module})", file=sys.stderr) - missing.append(module) - - print(f"count={len(missing)}") - if len(missing) == 1: - # Mill's brace syntax needs at least two alternatives: `{a,b}` parses, `{a}` does not. - print(f"selector={missing[0]}") - elif missing: - print("selector={" + ",".join(missing) + "}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/.github/scripts/sync-example-versions.py b/.github/scripts/sync-example-versions.py deleted file mode 100755 index 40f9384..0000000 --- a/.github/scripts/sync-example-versions.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python3 -"""Pin the examples to the currently released version of each Chippy package. - -The examples depend on Chippy by released coordinate rather than through `moduleDeps`, so -their version literals have to be maintained by hand. release-please cannot do it once -packages version independently: its generic updater has no component-scoped annotations -and keeps a single version context per file, while every example build file mixes packages -from several version lines. Annotating one would rewrite every coordinate in it with the -same version. - -The artifact -> version mapping is read from the build rather than duplicated here, so it -cannot drift from `versionLine` in build.mill: - - ./mill show '__.artifactMetadata' 2>/dev/null | python3 .github/scripts/sync-example-versions.py - ./mill show '__.artifactMetadata' 2>/dev/null | python3 .github/scripts/sync-example-versions.py --check - -Run it *after* a release has published, not on the release PR: pinning a version that is -not on Maven Central yet fails the examples job for everyone until it is. -""" -import json -import pathlib -import re -import sys - -COORD = re.compile(r'(mvn"io\.github\.ucb-substrate::)([A-Za-z0-9._-]+)(:)([^"]+)(")') -SKIP = ("saturn-vectors", "shuttle") - - -def main() -> int: - check = "--check" in sys.argv[1:] - meta = json.load(sys.stdin) - # "cde_2.13" -> "cde"; the `::` in a coordinate is what appends the Scala suffix. - versions = { - m["id"].rsplit("_", 1)[0]: m["version"] for m in meta.values() - } - - stale, unknown = [], [] - for f in sorted(pathlib.Path("examples").rglob("*.mill")): - if any(s in str(f) for s in SKIP): - continue - text = f.read_text() - - def repl(m: re.Match) -> str: - artifact, current = m.group(2), m.group(4) - want = versions.get(artifact) - if want is None: - unknown.append((str(f), artifact)) - return m.group(0) - if want != current: - stale.append((str(f), artifact, current, want)) - return f"{m.group(1)}{artifact}{m.group(3)}{want}{m.group(5)}" - - updated = COORD.sub(repl, text) - if updated != text and not check: - f.write_text(updated) - - for path, artifact in unknown: - print(f"unknown artifact {artifact!r} in {path}", file=sys.stderr) - for path, artifact, current, want in stale: - print(f"{'stale' if check else 'updated'}: {path}: {artifact} {current} -> {want}") - - if unknown: - return 2 - if not stale: - print("examples already match the released versions") - return 0 - return 1 if check else 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6266859..7ee0f4d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -125,15 +125,13 @@ jobs: key: mill-out-examples-${{ runner.os }}-${{ github.sha }} restore-keys: mill-out-examples-${{ runner.os }}- - # Covers the window where an example pins a version that is not on Maven Central - # yet. Example versions are no longer bumped by release-please — see the README — - # so the intended workflow keeps them on published versions and this never fires. - # It stays because syncing them on the release PR instead is a reasonable thing for - # someone to do, and it should not break ci when they do. It triggers on - # release-please's own PR, which it always opens from this branch, and on the commit - # that lands when that PR is merged, which is titled `chore(main): release ...`. Its - # `autorelease:` label is not used for this: it is attached after the PR is created - # and flips to `autorelease: tagged` once the release exists. + # The one case where the released artifacts cannot be used: a release bumps the + # examples to the version it is about to publish, so that version is not on Maven + # Central yet. Build it from source instead — on release-please's own PR, which it + # always opens from this branch, and on the commit that lands when that PR is + # merged, which is titled `chore(main): release X.Y.Z`. Its `autorelease:` label is + # not used for this: it is attached after the PR is created and flips to + # `autorelease: tagged` once the release exists. # # Deliberately conditional rather than a repository that is always available as a # fallback: a package missing from Maven Central has to fail here, not be quietly diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5e5ba65..264084a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,10 +10,10 @@ on: workflows: [ci] types: [completed] branches: [main] - # Escape hatch: publish whatever the manifest names that Central does not have yet, and - # finish tagging it. Maven Central refuses a version it already holds, but the publish - # job selects on exactly that, so this is safe to re-run — it uploads only what is still - # missing and does nothing at all once everything has landed. + # Escape hatch: publish the version currently in version.txt and finish tagging it. + # Unlike the GitHub Pages repository this replaced, Maven Central refuses a version it + # already holds, so this recovers a run that failed before Central accepted the bundle. + # A run that failed after that point is finished by re-running the tag job alone. workflow_dispatch: permissions: {} @@ -28,7 +28,7 @@ concurrency: # are live. A publish failure therefore leaves no tag to clean up, and re-running finishes # the release rather than duplicating it. # -# publish -> tag -> release-pr -> sync-examples +# publish -> tag -> release-pr # # The file lists them in that order too; `release-pr` runs last because tagging first is # what stops it from re-proposing a release that is already on its way out. @@ -36,9 +36,7 @@ jobs: # Uploads this release's packages to Maven Central through the Sonatype Central Portal. # # Nothing has been tagged at this point, so the release is identified by the commit - # release-please's PR lands: "chore(main): release". The title carries no version — the - # merged manifest PR takes its component and version from a root ("." path) package, and - # this repository has none, so both are empty. `release_created` is not + # release-please's PR lands: "chore(main): release X.Y.Z". `release_created` is not # available yet by design — it comes from the tagging half, which now runs last. publish: if: >- @@ -73,35 +71,26 @@ jobs: key: mill-${{ runner.os }}-${{ hashFiles('build.mill', 'mill') }} restore-keys: mill-${{ runner.os }}- - # Packages version independently, so a release publishes only the ones whose version - # is not on Central yet — which is most of the point: rocket-chip is nearly half the - # bytes of a full release and only moves when its submodule pointer does. + # `publishAll` with no `--publishArtifacts` resolves every PublishModule in the + # build, which is exactly the eleven packages and none of the examples — the same + # wildcard property the README asks you not to break by making an example a + # PublishModule. # - # The set is derived by asking Central rather than by reading release-please's - # outputs, which do not exist yet at this point: the tagging half runs after this - # job, deliberately. Deriving it from Central also makes the job idempotent, which is - # what the workflow_dispatch escape hatch relies on — a re-run uploads exactly what - # is still missing rather than failing on what already landed. - - name: Work out which packages need publishing - id: select - run: | - ./mill show '__.artifactMetadata' 2>/dev/null > metadata.json - python3 .github/scripts/select-unpublished.py < metadata.json >> "$GITHUB_OUTPUT" - - # Whatever is selected goes up as one bundle, so Central validates and releases it - # atomically, and the release costs one deployment against Central's publishing - # limits rather than one per package. + # Naming a bundle sends all of them to Central as one deployment, so it validates + # and releases them together or not at all. A half-published version is not a state + # this repository can be in — every package shares `version.txt` — and one + # deployment is also one release event against Central's publishing limits rather + # than eleven. # # Signing uses Mill's built-in PGP worker rather than a gpg binary, so # MILL_PGP_SECRET_BASE64 is all the runner needs. `shouldRelease` defaults to true, # which publishes the bundle as soon as Central has validated it instead of leaving # it sitting in the portal for someone to release by hand. # - # The await timeout defaults to two minutes, which validating a large bundle can - # outrun; twenty costs nothing when things go well, since the call returns as soon - # as Central reports a terminal state. + # The await timeout defaults to two minutes, which validating an eleven-package + # bundle can outrun; twenty costs nothing when things go well, since the call + # returns as soon as Central reports a terminal state. - name: Publish to Maven Central - if: steps.select.outputs.count != '0' env: MILL_SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} MILL_SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} @@ -109,29 +98,14 @@ jobs: MILL_PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} run: | ./mill mill.javalib.SonatypeCentralPublishModule/publishAll \ - --publishArtifacts '${{ steps.select.outputs.selector }}.publishArtifacts' \ - --bundleName "chippy-$(git rev-parse --short HEAD)" \ + --bundleName "chippy-$(cat version.txt)" \ --awaitTimeout 1200000 - # Not a failure: an ordinary release only moves some packages, and a re-run after a - # successful publish legitimately has nothing left to do. - - name: Nothing to publish - if: steps.select.outputs.count == '0' - run: echo "Every package's current version is already on Maven Central." - - # Tags each released package and creates its GitHub release, now that the artifacts they - # point at are actually resolvable. With per-package versions this is one tag and one - # release per package the run actually bumped, not one per package in the repository. - # - # Both halves of this are release-please's own: it has no tag-only mode, because creating - # the tag is a side effect of creating the release. That is also what clears the merged - # release PR's `autorelease: pending` label — release-please refuses to propose anything - # new while a merged release PR still carries it, so the `release-pr` job below depends - # on this one having run. - # - # Keys off that label rather than off anything in this run, so re-running after a partial - # failure finishes the release instead of creating a second one. On an ordinary push it - # is skipped along with the publish job it depends on. + # Tags the release and creates the GitHub release, now that the artifacts it points at + # are actually resolvable. This keys off the merged release PR's `autorelease: pending` + # label rather than off anything in this run, so re-running after a partial failure + # finishes the release instead of creating a second one. On an ordinary push it is + # skipped along with the publish job it depends on. tag: needs: [publish] runs-on: ubuntu-latest @@ -145,7 +119,7 @@ jobs: # The tagging half only; the release PR is maintained by the job below. skip-github-pull-request: true - # Maintains the release PR ("chore(main): release") for every push to main that + # Maintains the release PR ("chore(main): release X.Y.Z") for every push to main that # passes ci. On a release push it waits for the tag: release-please decides what to # propose from the commits since the last tag, so running it while a release is still # untagged would have it propose that same release again. If tagging fails it does not @@ -166,75 +140,3 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} skip-github-release: true - - # Adds the example version bumps to the release PR release-please just opened, so a - # release is one pull request rather than a release followed by a cleanup. - # - # release-please cannot do this itself: its component-scoped updaters only handle - # json/toml/yaml/xml, and every example build file mixes packages from several version - # lines, so the annotation-based generic updater would rewrite each file's coordinates - # with a single package's version. - # - # The versions being pinned are not on Maven Central yet — they are the ones this PR - # proposes to publish. That is exactly the window the ci workflow's "Build Chippy from - # source for a release" step covers, keyed off this branch name and off the - # `chore(main): release` commit that lands when the PR merges. - # - # release-please force-pushes its branch whenever it regenerates the PR, dropping this - # commit; this job runs after it on every push to main, so it is simply re-applied. - sync-examples: - needs: [release-pr] - if: ${{ !cancelled() && needs.release-pr.result == 'success' }} - runs-on: ubuntu-latest - permissions: - contents: write - steps: - # There is only a branch to update when a release is actually pending. - - name: Look for a pending release PR - id: check - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - if gh api "repos/${{ github.repository }}/branches/release-please--branches--main" >/dev/null 2>&1; then - echo "exists=true" >> "$GITHUB_OUTPUT" - else - echo "exists=false" >> "$GITHUB_OUTPUT" - echo "no release pending; nothing to sync" - fi - - - uses: actions/checkout@v7 - if: steps.check.outputs.exists == 'true' - with: - ref: release-please--branches--main - submodules: recursive - - - uses: actions/setup-java@v5 - if: steps.check.outputs.exists == 'true' - with: - distribution: temurin - java-version: '21' - - - uses: actions/cache@v6 - if: steps.check.outputs.exists == 'true' - with: - path: | - ~/.cache/coursier - ~/.cache/mill - key: mill-${{ runner.os }}-${{ hashFiles('build.mill', 'mill') }} - restore-keys: mill-${{ runner.os }}- - - - name: Pin the examples to the pending release - if: steps.check.outputs.exists == 'true' - run: | - set -euo pipefail - ./mill show '__.artifactMetadata' 2>/dev/null > metadata.json - python3 .github/scripts/sync-example-versions.py < metadata.json - rm -f metadata.json - if git diff --quiet; then - echo "examples already pin the pending release" - exit 0 - fi - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git commit -am "chore(examples): pin to the pending release" - git push origin HEAD:release-please--branches--main diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 3815790..a915e8c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,9 +1,3 @@ { - "rocket-chip": "0.1.1", - "rocket-chip-blocks": "0.1.1", - "rocket-chip-inclusive-cache": "0.1.1", - "testchipip": "0.1.1", - "constellation": "0.1.1", - "chipyard": "0.1.1", - "chippy": "0.1.1" + ".": "0.1.1" } diff --git a/README.md b/README.md index f47195b..fdcd2e2 100644 --- a/README.md +++ b/README.md @@ -6,37 +6,6 @@ Individual packages can be easily compiled, tested, and used in other projects w ## Usage -Chippy releases are published under the `io.github.ucb-substrate` namespace to -[Maven Central](https://central.sonatype.com/namespace/io.github.ucb-substrate). Mill, sbt and Maven -all resolve from Central out of the box, so there is no repository to add and no credentials to -configure — only the dependency itself. - -The namespace is a coordinate, not a package name: the Scala packages are unchanged, so `chippy` -still lives in `edu.berkeley.cs.chippy` and rocket-chip in `freechips.rocketchip`. Nothing in an -`import` moves. - -### Packages - -Eleven artifacts are published, listed here roughly bottom-up. API documentation is rendered from the -published Scaladoc jars by [javadoc.io](https://javadoc.io); the first request for a given version -takes a moment while it unpacks the jar. The -[Maven Central namespace page](https://central.sonatype.com/namespace/io.github.ucb-substrate) is the -canonical listing. - -| Package | Description | API docs | -| --- | --- | --- | -| `cde` | A Scala library for Context-Dependent Environments. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/cde_2.13/latest) | -| `diplomacy` | A parameter negotiation framework for Chisel. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/diplomacy_2.13/latest) | -| `hardfloat` | Hardware floating-point units written in Chisel. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/hardfloat_2.13/latest) | -| `rocketchip-macros` | Scala macros used by the Rocket Chip generator. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/rocketchip-macros_2.13/latest) | -| `rocketchip` | The Rocket Chip generator. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/rocketchip_2.13/latest) | -| `rocketchip-blocks` | RTL blocks compatible with the Rocket Chip generator. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/rocketchip-blocks_2.13/latest) | -| `rocketchip-inclusive-cache` | An RTL generator for a last-level shared inclusive TileLink cache controller. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/rocketchip-inclusive-cache_2.13/latest) | -| `testchipip` | Useful IP components for chips. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/testchipip_2.13/latest) | -| `constellation` | A Chisel NoC RTL generator framework designed to provide the core interconnect fabric for heterogeneous many-core, many-accelerator SoCs. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/constellation_2.13/latest) | -| `chippy` | An SoC design framework for integrating cores, accelerators, and other peripherals. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/chippy_2.13/latest) | -| `chipyard` | Prebuilt config fragments and full chip configs for Chippy. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/chipyard_2.13/latest) | - To include a package in a new project, add the dependency. If you are using Mill 1.1.2, for example, add the following to your `build.mill` to use the `diplomacy` package: @@ -67,119 +36,30 @@ git submodule update --init --recursive Usage examples can be found in the `examples/` folder. -## Releasing - -Versions are managed by [release-please](https://github.com/googleapis/release-please) and are **per -package**, so a release publishes only what changed. `.release-please-manifest.json` is the single -source of truth; `build.mill` reads it, so no version numbers are hardcoded in the build. - -There are seven version lines, one per submodule rather than one per artifact: - -| Version line | Artifacts | -| --- | --- | -| `rocket-chip` | `rocketchip`, `rocketchip-macros`, `cde`, `diplomacy`, `hardfloat` | -| `rocket-chip-blocks` | `rocketchip-blocks` | -| `rocket-chip-inclusive-cache` | `rocketchip-inclusive-cache` | -| `testchipip` | `testchipip` | -| `constellation` | `constellation` | -| `chipyard` | `chipyard` | -| `chippy` | `chippy` | - -The grouping is forced rather than chosen. release-please attributes a commit to a package by the -paths it touches, and every source tree above except `chippy/` is a git submodule — so bumping one -appears as a change to exactly one path. The five artifacts built out of `rocket-chip` share a -version because nothing distinguishes them in the commit history, which is also how they actually -change. - -Version lines move independently, and a package is **not** republished when something it depends on -bumps: `chippy` at 0.1.1 keeps referencing whatever `rocketchip` version it was built against, which -is ordinary Maven behaviour. Mill derives each POM's dependency versions from the depended-on -module's own `publishVersion`, so this needs no bookkeeping. - -The flow is: - -1. Land changes on `main` using [Conventional Commits](https://www.conventionalcommits.org/) — `fix:` - bumps the patch version, `feat:` bumps the minor version, and `feat!:` / a `BREAKING CHANGE:` - footer also bumps the minor version while the project is pre-1.0. Commits with any other prefix - (`chore:`, `docs:`, ...) do not trigger a release. Since the repository squash-merges, the **PR - title** is what ends up in the commit history and therefore what release-please parses. -2. release-please keeps a single `chore(main): release` PR open covering every package with a pending - bump. -3. Merging that PR publishes the packages whose versions are not on Maven Central yet, then tags - each of them. Tags carry the component: `chippy-v0.1.2`, `rocketchip-v0.2.0`. - -Tagging and the GitHub release for a package are one step, done by release-please: creating the tag -is a side effect of creating the release, and the same step clears the merged release PR's -`autorelease: pending` label, which release-please requires before it will propose anything new. Only -the packages a run actually bumped are tagged and released, not all seven. - -The publish job works out what to upload by asking Central which versions already exist, rather than -by reading release-please's outputs — those do not exist yet, because tagging deliberately runs -afterwards. That also makes it idempotent: re-running uploads only what is still missing. - -### Publishing credentials - -Whatever a release publishes goes to Central as a single signed bundle, uploaded by -`mill.javalib.SonatypeCentralPublishModule/publishAll`, so it is accepted whole or not at all — and -costs one deployment against Central's publishing limits rather than one per package. Unlike the -GitHub Pages repository this replaced, that needs four repository secrets, which -`.github/workflows/release.yml` passes to Mill under its own `MILL_`-prefixed names: - -- `SONATYPE_USERNAME` and `SONATYPE_PASSWORD` — a *user token*, generated from the account page of - the [Central Portal](https://central.sonatype.com/). These are not the portal login itself. -- `PGP_SECRET_BASE64` and `PGP_PASSPHRASE` — the base64-encoded private key the artifacts are signed - with, and its passphrase. Central rejects unsigned uploads, and the matching public key has to be - on a public keyserver. `./mill mill.javalib.SonatypeCentralPublishModule/initGpgKeys` generates a - key pair, publishes the public half and prints both values ready to paste in. - -The `io.github.ucb-substrate` namespace also has to be verified against the account doing the -publishing before its first upload. Because `ucb-substrate` is a GitHub organization rather than a -personal account, Central does not grant it automatically on login: add the namespace in the portal, -then create a public repository in the organization named after the verification key it hands back. -Everything else still runs with the built-in `GITHUB_TOKEN`. - -Central refuses a version it already holds, but the publish job selects on exactly that, so the -`workflow_dispatch` escape hatch is safe to re-run: it uploads only what is still missing and does -nothing once everything has landed. Give Central a few minutes to reach `PUBLISHED` before -re-running, though — `repo1` lags a publish, so a re-run started immediately after one can still see -a package as missing and try it again. - -### Examples - -The projects under `examples/` are consumers, not published packages. Each is its own nested build -that depends on Chippy the way an external project would — by released coordinate, resolved from -Maven Central — rather than via `moduleDeps`. None of them extends `PublishModule`, which is what -keeps them out of the wildcards the release and ci jobs resolve. **Do not make an example a -`PublishModule`**: it would be picked up by the release, and because its dependencies are the -artifacts that same job is producing, the build would fail to resolve them on a clean checkout. - -Their pinned versions are bumped automatically, as part of the release PR. The `sync-examples` job in -`.github/workflows/release.yml` runs after release-please has opened or updated that PR, rewrites the -example coordinates to the versions it proposes, and pushes the result onto the same branch. A -release is therefore one pull request, and the examples always demonstrate the version being -published. - -Those versions are not on Maven Central at that point — they are what the PR is proposing to publish. -That is exactly the window the ci workflow's "Build Chippy from source for a release" step covers, -which is keyed off release-please's branch name and off the `chore(main): release` commit that lands -when the PR merges. - -release-please cannot do the rewrite itself. Its component-scoped updaters only handle -json/toml/yaml/xml, and the annotation-based generic updater keeps a single version context per file, -while every example build file mixes packages from several version lines — annotating one would -rewrite every coordinate in it with the same version. Keeping literal versions in the build files -rather than reading them from the manifest is also what keeps the examples copy-pasteable. - -`.github/scripts/sync-example-versions.py` does the rewrite, taking the artifact-to-version mapping -from the build itself so it cannot drift from `versionLine`. To run it by hand: +### Packages -``` -./mill show '__.artifactMetadata' 2>/dev/null | python3 .github/scripts/sync-example-versions.py -./mill show '__.artifactMetadata' 2>/dev/null | python3 .github/scripts/sync-example-versions.py --check -``` +Eleven artifacts are published, listed here roughly bottom-up. API documentation is rendered from the +published Scaladoc jars by [javadoc.io](https://javadoc.io); the first request for a given version +takes a moment while it unpacks the jar. The +[Maven Central namespace page](https://central.sonatype.com/namespace/io.github.ucb-substrate) is the +canonical listing. + +| Package | Description | API docs | +| --- | --- | --- | +| `cde` | A Scala library for Context-Dependent Environments. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/cde_2.13/latest) | +| `diplomacy` | A parameter negotiation framework for Chisel. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/diplomacy_2.13/latest) | +| `hardfloat` | Hardware floating-point units written in Chisel. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/hardfloat_2.13/latest) | +| `rocketchip-macros` | Scala macros used by the Rocket Chip generator. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/rocketchip-macros_2.13/latest) | +| `rocketchip` | The Rocket Chip generator. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/rocketchip_2.13/latest) | +| `rocketchip-blocks` | RTL blocks compatible with the Rocket Chip generator. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/rocketchip-blocks_2.13/latest) | +| `rocketchip-inclusive-cache` | An RTL generator for a last-level shared inclusive TileLink cache controller. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/rocketchip-inclusive-cache_2.13/latest) | +| `testchipip` | Useful IP components for chips. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/testchipip_2.13/latest) | +| `constellation` | A Chisel NoC RTL generator framework designed to provide the core interconnect fabric for heterogeneous many-core, many-accelerator SoCs. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/constellation_2.13/latest) | +| `chippy` | An SoC design framework for integrating cores, accelerators, and other peripherals. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/chippy_2.13/latest) | +| `chipyard` | Prebuilt config fragments and full chip configs for Chippy. | [docs](https://javadoc.io/doc/io.github.ucb-substrate/chipyard_2.13/latest) | + + +## Versioning -The snippets in this README *are* still updated automatically: they only ever show `diplomacy`, so -the file is listed under the `rocket-chip` package's `extra-files` and the block annotations in it -have a single version context. Note that release-please scans this file, so avoid writing the literal -block-annotation markers in prose — an unmatched opening marker turns the rest of the file into a -replacement zone. +Versions are managed by [release-please](https://github.com/googleapis/release-please). Every +package shares one version, held in `version.txt`. diff --git a/build.mill b/build.mill index e1ed413..f3b072b 100644 --- a/build.mill +++ b/build.mill @@ -21,18 +21,10 @@ trait ChippyModule extends ScalaModule { } trait ChippyPublishModule extends ChippyModule, PublishModule { - // The release-please package this artifact's version comes from. Packages are one per - // submodule rather than one per artifact, because release-please attributes commits by - // path and a submodule bump touches exactly one: the five artifacts built out of - // `rocket-chip` therefore share a version, which is also how they actually change. - def versionLine: String - - // Versions live only in the release-please manifest, keyed by that same path. Nothing - // duplicates them — release-please's `simple` strategy does write a `version.txt` under - // each package path, but with createIfMissing: false, and these paths are submodules - // where no such file exists, so the manifest is the sole source of truth. - def versionManifest = Task.Source(BuildCtx.workspaceRoot / ".release-please-manifest.json") - def publishVersion = Task { ujson.read(os.read(versionManifest().path))(versionLine).str } + // Single source of truth for the version of every published Chippy artifact. + // Bumped automatically by release-please; see .github/workflows/release.yml. + def versionFile = Task.Source(BuildCtx.workspaceRoot / "version.txt") + def publishVersion = Task { os.read(versionFile().path).trim } def makePomSettings(description: String) = PomSettings( description = description, @@ -47,7 +39,6 @@ trait ChippyPublishModule extends ChippyModule, PublishModule { } object rocketchip extends ChippyPublishModule { - def versionLine = "rocket-chip" def moduleDir = super.moduleDir / os.up / "rocket-chip" def resources = Task.Sources { moduleDir / "src" / "main" / "resources" } @@ -63,20 +54,18 @@ object rocketchip extends ChippyPublishModule { mvn"org.chipsalliance:::chisel-plugin:${chiselVersion}" ) - def pomSettings = makePomSettings("The Rocket Chip generator.") + def pomSettings = makePomSettings("Hardware floating-point units written in Chisel.") object macros extends ChippyPublishModule { - def versionLine = "rocket-chip" def mvnDeps = Seq( mvn"org.scala-lang:scala-reflect:${scalaVersion}", ) - def pomSettings = makePomSettings("Scala macros used by the Rocket Chip generator.") + def pomSettings = makePomSettings("Hardware floating-point units written in Chisel.") } object dependencies extends Module { object cde extends ChippyPublishModule { - def versionLine = "rocket-chip" def artifactName = "cde" def sources = Task.Sources(this.moduleDir / "cde" / "src") @@ -93,7 +82,6 @@ object rocketchip extends ChippyPublishModule { } object diplomacy extends ChippyPublishModule { - def versionLine = "rocket-chip" def artifactName = "diplomacy" def sources = Task.Sources(this.moduleDir / "diplomacy" / "src") @@ -112,7 +100,6 @@ object rocketchip extends ChippyPublishModule { } object hardfloat extends ChippyPublishModule { - def versionLine = "rocket-chip" def artifactName = "hardfloat" def sources = Task.Sources(this.moduleDir / "hardfloat" / "src") @@ -140,7 +127,6 @@ object rocketchip extends ChippyPublishModule { } object `rocketchip-blocks` extends ChippyPublishModule { - def versionLine = "rocket-chip-blocks" def moduleDir = super.moduleDir / os.up / "rocket-chip-blocks" def moduleDeps = Seq(rocketchip) @@ -152,11 +138,10 @@ object `rocketchip-blocks` extends ChippyPublishModule { mvn"org.chipsalliance:::chisel-plugin:${chiselVersion}" ) - def pomSettings = makePomSettings("RTL blocks compatible with the Rocket Chip generator.") + def pomSettings = makePomSettings("RTL generators designed to be compatible with Rocket Chip.") } object `rocketchip-inclusive-cache` extends ChippyPublishModule { - def versionLine = "rocket-chip-inclusive-cache" def moduleDir = super.moduleDir / os.up / "rocket-chip-inclusive-cache" def sources = Task.Sources(moduleDir / "design" / "craft" / "inclusivecache") @@ -173,7 +158,6 @@ object `rocketchip-inclusive-cache` extends ChippyPublishModule { } object testchipip extends ChippyPublishModule { - def versionLine = "testchipip" def resources = Task.Sources { moduleDir / "src" / "main" / "resources" } def moduleDeps = Seq(rocketchip.dependencies.cde, rocketchip, `rocketchip-blocks`) @@ -189,7 +173,6 @@ object testchipip extends ChippyPublishModule { } object constellation extends ChippyPublishModule { - def versionLine = "constellation" def sources = Task.Sources(this.moduleDir / "src" / "main") def moduleDeps = Seq(rocketchip.dependencies.cde, rocketchip, rocketchip.macros) @@ -213,7 +196,6 @@ object constellation extends ChippyPublishModule { } object chippy extends ChippyPublishModule { - def versionLine = "chippy" def moduleDeps = Seq(rocketchip.dependencies.cde, rocketchip.dependencies.diplomacy, rocketchip) def mvnDeps = Seq( @@ -223,11 +205,10 @@ object chippy extends ChippyPublishModule { mvn"org.chipsalliance:::chisel-plugin:${chiselVersion}" ) - def pomSettings = makePomSettings("An SoC design framework for integrating cores, accelerators, and other peripherals.") + def pomSettings = makePomSettings("An SoC design framework for integrating cores, accelerators, and other peripherals. ") } object chipyard extends ChippyPublishModule { - def versionLine = "chipyard" def sources = Task.Sources(this.moduleDir / "src" / "main") def resources = Task.Sources { moduleDir / "src" / "main" / "resources" } @@ -241,7 +222,7 @@ object chipyard extends ChippyPublishModule { mvn"org.chipsalliance:::chisel-plugin:${chiselVersion}" ) - def pomSettings = makePomSettings("Prebuilt config fragments and full chip configs for Chippy.") + def pomSettings = makePomSettings("An SoC design framework for integrating cores, accelerators, and other peripherals. ") object test extends ScalaTests, TestModule.ScalaTest { def sources = Task.Sources(this.moduleDir / os.up / "src" / "test") diff --git a/examples/mmio-adder/build.mill b/examples/mmio-adder/build.mill index 6b0b2e3..01eb649 100644 --- a/examples/mmio-adder/build.mill +++ b/examples/mmio-adder/build.mill @@ -11,10 +11,10 @@ object `package` extends ScalaModule { def mvnDeps = Seq( mvn"org.chipsalliance::chisel:${chiselVersion}", - mvn"io.github.ucb-substrate::diplomacy:0.1.1", - mvn"io.github.ucb-substrate::rocketchip:0.1.1", - mvn"io.github.ucb-substrate::chippy:0.1.1", - mvn"io.github.ucb-substrate::testchipip:0.1.1" + mvn"io.github.ucb-substrate::diplomacy:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::rocketchip:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::chippy:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::testchipip:0.1.1" // x-release-please-version ) def scalacPluginMvnDeps = Seq( mvn"org.chipsalliance:::chisel-plugin:${chiselVersion}", diff --git a/examples/rocket-config/build.mill b/examples/rocket-config/build.mill index 8d08d22..b4f2139 100644 --- a/examples/rocket-config/build.mill +++ b/examples/rocket-config/build.mill @@ -11,13 +11,13 @@ object `package` extends ScalaModule { def mvnDeps = Seq( mvn"org.chipsalliance::chisel:${chiselVersion}", - mvn"io.github.ucb-substrate::cde:0.1.1", - mvn"io.github.ucb-substrate::diplomacy:0.1.1", - mvn"io.github.ucb-substrate::rocketchip:0.1.1", - mvn"io.github.ucb-substrate::rocketchip-blocks:0.1.1", - mvn"io.github.ucb-substrate::rocketchip-inclusive-cache:0.1.1", - mvn"io.github.ucb-substrate::testchipip:0.1.1", - mvn"io.github.ucb-substrate::chippy:0.1.1", + mvn"io.github.ucb-substrate::cde:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::diplomacy:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::rocketchip:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::rocketchip-blocks:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::rocketchip-inclusive-cache:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::testchipip:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::chippy:0.1.1", // x-release-please-version ) def scalacPluginMvnDeps = Seq( mvn"org.chipsalliance:::chisel-plugin:${chiselVersion}", @@ -26,7 +26,7 @@ object `package` extends ScalaModule { object test extends ScalaTests, TestModule.ScalaTest { def mvnDeps = Seq( mvn"org.scalatest::scalatest:3.2.19", - mvn"io.github.ucb-substrate::testchipip:0.1.1", + mvn"io.github.ucb-substrate::testchipip:0.1.1", // x-release-please-version ) } } diff --git a/examples/sky130-chip/build.mill b/examples/sky130-chip/build.mill index acb830e..f8224bb 100644 --- a/examples/sky130-chip/build.mill +++ b/examples/sky130-chip/build.mill @@ -11,11 +11,11 @@ object `package` extends build.`digital-chip`.ChipModule { def mvnDeps = Seq( mvn"org.chipsalliance::chisel:${chiselVersion}", - mvn"io.github.ucb-substrate::cde:0.1.1", - mvn"io.github.ucb-substrate::diplomacy:0.1.1", - mvn"io.github.ucb-substrate::rocketchip:0.1.1", - mvn"io.github.ucb-substrate::chippy:0.1.1", - mvn"io.github.ucb-substrate::constellation:0.1.1", + mvn"io.github.ucb-substrate::cde:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::diplomacy:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::rocketchip:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::chippy:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::constellation:0.1.1", // x-release-please-version ) def scalacPluginMvnDeps = Seq( mvn"org.chipsalliance:::chisel-plugin:${chiselVersion}", diff --git a/examples/sky130-chip/digital-chip/build.mill b/examples/sky130-chip/digital-chip/build.mill index 79b4ad0..05304fa 100644 --- a/examples/sky130-chip/digital-chip/build.mill +++ b/examples/sky130-chip/digital-chip/build.mill @@ -10,14 +10,14 @@ object `package` extends ChipModule { def mvnDeps = Seq( mvn"org.chipsalliance::chisel:${chiselVersion}", - mvn"io.github.ucb-substrate::cde:0.1.1", - mvn"io.github.ucb-substrate::diplomacy:0.1.1", - mvn"io.github.ucb-substrate::testchipip:0.1.1", - mvn"io.github.ucb-substrate::rocketchip-blocks:0.1.1", - mvn"io.github.ucb-substrate::rocketchip-inclusive-cache:0.1.1", - mvn"io.github.ucb-substrate::rocketchip:0.1.1", - mvn"io.github.ucb-substrate::chippy:0.1.1", - mvn"io.github.ucb-substrate::constellation:0.1.1", + mvn"io.github.ucb-substrate::cde:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::diplomacy:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::testchipip:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::rocketchip-blocks:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::rocketchip-inclusive-cache:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::rocketchip:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::chippy:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::constellation:0.1.1", // x-release-please-version ) def scalacPluginMvnDeps = Seq( mvn"org.chipsalliance:::chisel-plugin:${chiselVersion}", @@ -26,16 +26,16 @@ object `package` extends ChipModule { object test extends ScalaTests, TestModule.ScalaTest { def mvnDeps = Seq( mvn"org.scalatest::scalatest:3.2.19", - mvn"io.github.ucb-substrate::testchipip:0.1.1", + mvn"io.github.ucb-substrate::testchipip:0.1.1", // x-release-please-version ) } object shuttle extends ChipModule { def mvnDeps = Seq( mvn"org.chipsalliance::chisel:${chiselVersion}", - mvn"io.github.ucb-substrate::cde:0.1.1", - mvn"io.github.ucb-substrate::diplomacy:0.1.1", - mvn"io.github.ucb-substrate::rocketchip:0.1.1", + mvn"io.github.ucb-substrate::cde:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::diplomacy:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::rocketchip:0.1.1", // x-release-please-version ) def scalacPluginMvnDeps = Seq( mvn"org.chipsalliance:::chisel-plugin:${chiselVersion}", @@ -49,9 +49,9 @@ object `package` extends ChipModule { def mvnDeps = Seq( mvn"org.chipsalliance::chisel:${chiselVersion}", - mvn"io.github.ucb-substrate::cde:0.1.1", - mvn"io.github.ucb-substrate::diplomacy:0.1.1", - mvn"io.github.ucb-substrate::rocketchip:0.1.1", + mvn"io.github.ucb-substrate::cde:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::diplomacy:0.1.1", // x-release-please-version + mvn"io.github.ucb-substrate::rocketchip:0.1.1", // x-release-please-version ) def scalacPluginMvnDeps = Seq( mvn"org.chipsalliance:::chisel-plugin:${chiselVersion}", diff --git a/release-please-config.json b/release-please-config.json index e70e3c9..719d7ad 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -4,32 +4,13 @@ "skip-changelog": true, "bump-minor-pre-major": true, "include-v-in-tag": true, - "include-component-in-tag": true, - "separate-pull-requests": false, + "include-component-in-tag": false, "packages": { - "rocket-chip": { - "component": "rocketchip", + ".": { "extra-files": [ - "README.md" + "README.md", + { "type": "generic", "path": "examples/**/*.mill", "glob": true } ] - }, - "rocket-chip-blocks": { - "component": "rocketchip-blocks" - }, - "rocket-chip-inclusive-cache": { - "component": "rocketchip-inclusive-cache" - }, - "testchipip": { - "component": "testchipip" - }, - "constellation": { - "component": "constellation" - }, - "chipyard": { - "component": "chipyard" - }, - "chippy": { - "component": "chippy" } } } diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..17e51c3 --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +0.1.1