Skip to content

Conversation

@0xisk
Copy link
Member

@0xisk 0xisk commented Nov 3, 2025

Types of changes

What types of changes does your code introduce to OpenZeppelin Midnight Contracts?
Put an x in the boxes that apply

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation Update (if none of the other choices apply)

Fixes #212 #268

PR Checklist

  • I have read the Contributing Guide
  • I have added tests that prove my fix is effective or that my feature works
  • I have added documentation of new methods and any new behavior or changes to existing behavior
  • CI Workflows Are Passing

Further comments

If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc...

Summary by CodeRabbit

  • New Features

    • Package now published to npm registry with automated versioning and dist-tag management.
    • Integrated Compact compiler setup in GitHub Actions workflows.
  • Documentation

    • Added comprehensive release workflow guide.
  • Chores

    • Streamlined build process in CI/CD pipeline.
    • Updated package metadata (description, license, repository information).

@0xisk 0xisk requested a review from a team as a code owner November 3, 2025 09:10
@coderabbitai
Copy link

coderabbitai bot commented Nov 3, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Establishes release infrastructure by introducing new CI workflows for version bumping and npm publishing, centralizing Compact compiler setup in a composite action, refactoring the build pipeline to a four-step process, and adding public package metadata to enable distribution while documenting the complete release workflow.

Changes

Cohort / File(s) Summary
GitHub Actions Setup Infrastructure
.github/actions/setup/action.yml
Adds integrated Compact compiler support with new input skip-compact (default false), new outputs compact-home and compact-version, caching for compiler artifacts, installation step from COMPACT_INSTALLER_URL, environment setup, and version validation step comparing installed compiler and language versions against expected values.
Release Workflows
.github/workflows/prepare-release.yml, .github/workflows/release.yml
Introduces two new workflows: prepare-release triggers on release branch creation to auto-bump version in contracts/package.json and perform global version string replacements; release triggers on publication to build contracts, validate version consistency, compute npm dist-tag based on semver prerelease status, verify tarball contents, and publish to npm.
Workflow Updates
.github/workflows/checks.yml, .github/workflows/codeql.yml, .github/workflows/test.yml
Adds COMPACT_INSTALLER_URL environment variable at job level across all workflows; test.yml removes manual compiler setup steps and replaces with turbo compact invocation.
Build System Refactor
compact/src/Builder.ts
Replaces prior BUILD steps with new four-step pipeline: clean dist directory, TypeScript compilation (tsc --project tsconfig.build.json), copy .compact files preserving structure, and copy package metadata; updates progress messaging and adds build completion log.
Package Configuration
contracts/package.json
Removes private flag and module resolution fields (main, module, types, exports); adds public metadata (version, description, keywords, repository, license, author, bugs, homepage); declares type as "module"; updates build script from "compact-builder && tsc" to "compact-builder".
TypeScript Configuration
contracts/tsconfig.json
Narrows TypeScript compilation scope from src/\\/\.ts to src/\\/witnesses/\\/\.ts and adds src/archive/ to excludes; removes sourceMap option from compilerOptions.
Release Documentation
RELEASING.md
New documentation file detailing six-step release workflow: checkout release branch, create and push release branch, open PR for automated version bumping, merge and tag from release branch, publish release in GitHub, and create documentation branch from released tag.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant GitHub as GitHub Actions
    participant Installer as Compact Installer
    participant npm as npm Registry

    rect rgb(200, 220, 240)
    Note over User,GitHub: Prepare Release Phase
    User->>GitHub: Push release branch (release-v*)
    GitHub->>GitHub: prepare-release workflow triggers
    GitHub->>GitHub: Extract version from branch name
    GitHub->>GitHub: Update contracts/package.json
    GitHub->>GitHub: Replace version strings in codebase
    GitHub->>GitHub: Auto-commit changes
    end

    rect rgb(240, 220, 200)
    Note over User,GitHub: Version Validation & Setup
    User->>GitHub: Create release tag & publish
    GitHub->>GitHub: release workflow triggers
    GitHub->>GitHub: Build contracts
    GitHub->>GitHub: Validate tag vs package.json version
    end

    rect rgb(220, 240, 200)
    Note over GitHub,npm: Publishing Phase
    GitHub->>GitHub: Pack tarball from contracts/dist
    GitHub->>GitHub: Compute npm dist-tag (latest/beta/next)
    GitHub->>GitHub: Verify tarball (no private field)
    GitHub->>npm: Publish tarball with tag & provenance
    npm-->>GitHub: Package published
    GitHub->>User: Log success with install instructions
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Workflows scope: Two entirely new workflows (prepare-release.yml, release.yml) with distinct logic for version bumping and npm publishing; version mismatch detection and error handling paths require separate reasoning
  • Setup action complexity: New composite action steps with conditional logic (cache-hit checks, skip-compact guards), environment variable exports, version validation, and error emission
  • Build pipeline changes: Four-step refactored pipeline in Builder.ts with distinct file traversal logic and artifact handling differs substantially from prior single-command approach
  • Package.json metadata: Removal of several fields and addition of public metadata requires validation against release requirements and npm publishing expectations
  • tsconfig.json narrowing: Scope reduction to witnesses-only compilation requires understanding impact on type checking and build outputs
  • Heterogeneous nature: Changes span CI/CD orchestration, build system, package configuration, and TypeScript compilation—each domain has distinct implications

Areas requiring extra attention:

  • Version extraction and bumping logic in prepare-release.yml (glob patterns, version derivation from branch name)
  • npm dist-tag computation logic in release.yml based on semver prerelease detection
  • Tarball content validation and private field checks before publishing
  • Build pipeline step ordering and file traversal logic in Builder.ts, particularly .compact file filtering and exclusions
  • Compiler version validation logic in setup action step
  • TypeScript scope narrowing and impact on non-witness source files

Poem

🐰 A builder's burrow grows ever more grand,
With pipelines and packages, all carefully planned!
From witnesses whispering to releases refined,
We hop toward npm with version aligned—
Four steps build, one publish, the whole world to find!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Title Check ⚠️ Warning The PR title "fix(gh-actions): release PR requisted changes" does not accurately represent the nature and scope of the changes. According to the linked issue #212, this PR is implementing a new feature (as marked in the issue checklist), not fixing an existing issue. The changes include adding new release and prepare-release workflows, creating a setup composite action, adding release documentation, improving the build for packaging, and modifying package metadata. The title uses the wrong type marker ("fix" instead of "feat"), and the description "release PR requested changes" is vague and doesn't clearly convey what was actually implemented.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues Check ✅ Passed The PR implements all primary objectives from linked issue #212. It adds the release.yml and prepare-release.yml workflows for automating npm publishing and version bumping [#212], consolidates compact compiler installation into the setup composite action [#212], includes the new RELEASING.md documentation [#212], improves the build logic in Builder.ts to create a dist directory with repo structure minus src/ [#212], narrows the TypeScript configuration to focus on witnesses [#212], and removes the private field from contracts/package.json to enable publishing [#212, #149]. The changes to test.yml and workflow environment variables align with the setup action consolidation objective.
Out of Scope Changes Check ✅ Passed All code changes are directly related to and support the objectives defined in linked issue #212. The modifications span the expected files: GitHub Actions workflows (setup, prepare-release, release, checks, codeql, test), release documentation (RELEASING.md), build improvements (compact/src/Builder.ts), packaging configuration (contracts/package.json, contracts/tsconfig.json), and environment variable setup across workflows. No changes appear to be unrelated to the release automation, packaging, or compiler setup objectives outlined in the linked issue.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (5)
compact/src/Builder.ts (1)

60-71: Consider making the file copy loop more robust for edge cases.

The while read file loop could potentially break if file paths contain spaces, newlines, or other special characters. While .compact files likely follow naming conventions that avoid such characters, using a more robust pattern would align with shell best practices.

Consider this more robust approach using find -print0 and while IFS= read -r -d '':

       {
         cmd: `
-        find src -type f -name "*.compact" ! -name "Mock*" ! -path "*/archive/*" | while read file; do
+        find src -type f -name "*.compact" ! -name "Mock*" ! -path "*/archive/*" -print0 | while IFS= read -r -d '' file; do
           # Remove src/ prefix from path
           rel_path="\${file#src/}"
           mkdir -p "dist/\$(dirname "\$rel_path")"
           cp "\$file" "dist/\$rel_path"
         done
       `,
.github/actions/setup/action.yml (1)

110-134: Version parsing logic assumes specific output format.

The version validation uses head -n 1 for compiler version and tail -n 1 for language version, which assumes a specific output format from compactc --version and compactc --language-version. If the output format changes or multiple version numbers appear, this parsing could break or extract incorrect values.

Consider documenting the expected output format or making the parsing more robust. For example:

      run: |
        set -euo pipefail
        
        echo "🔍 Checking Compact compiler version..."
        # Expected format: "compactc 0.25.0" or similar
        COMPILER_OUTPUT=$(compactc --version)
        echo "Raw compiler output: $COMPILER_OUTPUT"
        COMPUTED_COMPILER_VERSION=$(echo "$COMPILER_OUTPUT" | grep -oP '\b0\.[0-9]+\.[0-9]+\b' | head -n 1)
        
        # ... rest of validation

Additionally, verify that the version commands produce predictable output:

#!/bin/bash
# Verify compactc version output format
echo "=== Testing version command outputs ==="
echo "Checking if compactc is available..."

# Note: This requires the Compact compiler to be installed
# Skip if not available in the environment
if command -v compactc &> /dev/null; then
  echo "Compiler version output:"
  compactc --version
  echo ""
  echo "Language version output:"
  compactc --language-version
else
  echo "compactc not found in PATH (expected in sandbox)"
fi
.github/workflows/release.yml (2)

64-92: Optimize tarball I/O by extracting package.json once and reusing values.

The workflow extracts package.json from the tarball three times (lines 67–69, 90–91), when one extraction could be reused. Additionally, storing extracted values in $GITHUB_OUTPUT would eliminate the need for redundant parsing.

  - name: Verify tarball integrity
    id: verify
    run: |
      echo "=== Verifying tarball contents ==="
-     PACKAGE_NAME=$(tar xfO "${{ steps.pack.outputs.tarball }}" package/package.json | jq -r .name)
-     PACKAGE_VERSION=$(tar xfO "${{ steps.pack.outputs.tarball }}" package/package.json | jq -r .version)
-     PRIVATE_FIELD=$(tar xfO "${{ steps.pack.outputs.tarball }}" package/package.json | jq -r '.private // "not found"')
+     PKG_JSON=$(tar xfO "${{ steps.pack.outputs.tarball }}" package/package.json)
+     PACKAGE_NAME=$(echo "$PKG_JSON" | jq -r .name)
+     PACKAGE_VERSION=$(echo "$PKG_JSON" | jq -r .version)
+     PRIVATE_FIELD=$(echo "$PKG_JSON" | jq -r '.private // "not found"')
+     
+     echo "package_name=$PACKAGE_NAME" >> $GITHUB_OUTPUT
+     echo "package_version=$PACKAGE_VERSION" >> $GITHUB_OUTPUT
+     echo "private_field=$PRIVATE_FIELD" >> $GITHUB_OUTPUT

      echo "📦 Package: $PACKAGE_NAME@$PACKAGE_VERSION"
      echo "🏷️  Tag: ${{ steps.pack.outputs.tag }}"
      echo "🔒 Private field: $PRIVATE_FIELD"

      # Ensure no private field
      if [ "$PRIVATE_FIELD" = "true" ]; then
        echo "❌ Tarball contains private: true - cannot publish"
        exit 1
      fi

  - name: Log success
    run: |
-     PACKAGE_NAME=$(tar xfO "${{ steps.pack.outputs.tarball }}" package/package.json | jq -r .name)
-     PACKAGE_VERSION=$(tar xfO "${{ steps.pack.outputs.tarball }}" package/package.json | jq -r .version)
-     echo "✅ Successfully published $PACKAGE_NAME@$PACKAGE_VERSION to npm with tag ${{ steps.pack.outputs.tag }}"
-     echo "📦 Install with: npm install $PACKAGE_NAME@${{ steps.pack.outputs.tag }}"
+     echo "✅ Successfully published ${{ steps.verify.outputs.package_name }}@${{ steps.verify.outputs.package_version }} to npm with tag ${{ steps.pack.outputs.tag }}"
+     echo "📦 Install with: npm install ${{ steps.verify.outputs.package_name }}@${{ steps.pack.outputs.tag }}"

81-86: Remove redundant provenance configuration.

The --provenance flag on line 84 and NPM_CONFIG_PROVENANCE: true on line 86 are redundant. The environment variable alone is sufficient.

  - name: Publish to npm
    run: |
      # Publish the tarball with appropriate tag
-     npm publish "${{ steps.pack.outputs.tarball }}" --tag "${{ steps.pack.outputs.tag }}" --access public --provenance
+     npm publish "${{ steps.pack.outputs.tarball }}" --tag "${{ steps.pack.outputs.tag }}" --access public
    env:
      NPM_CONFIG_PROVENANCE: true
.github/workflows/prepare-release.yml (1)

54-64: Consider restricting sed replacement to targeted version contexts.

The global find-and-replace (lines 55–64) using sed will match the version string anywhere it appears in files, including unintended locations like commented examples, hardcoded test strings, or as part of larger version numbers. This could introduce subtle bugs or false positives.

Consider a more targeted approach for critical files (e.g., only updating version fields in JSON/YAML files, or using a more specific regex pattern):

- # Escape special characters for sed
- ESCAPED_CURRENT=$(printf '%s' "$CURRENT_VERSION" | sed -e 's/[\/&]/\\&/g')
- ESCAPED_NEW=$(printf '%s' "$NEW_VERSION" | sed -e 's/[\/&]/\\&/g')
-
- # Replace version in contracts/src/
- find ./contracts/src/ -type d -name '.*' -prune -o \
-   -type f -exec sed -i "s#$ESCAPED_CURRENT#$ESCAPED_NEW#g" {} +
-
- # Replace version in docs/, excluding package-lock.json
- find ./docs/ -type d -name '.*' -prune -o \
-   -type f ! -name 'package-lock.json' -exec sed -i "s#$ESCAPED_CURRENT#$ESCAPED_NEW#g" {} +
+ # Escape special characters for sed
+ ESCAPED_CURRENT=$(printf '%s' "$CURRENT_VERSION" | sed -e 's/[\/&]/\\&/g')
+ ESCAPED_NEW=$(printf '%s' "$NEW_VERSION" | sed -e 's/[\/&]/\\&/g')
+
+ # Replace version in contracts/src/ with a more targeted pattern (e.g., after "version")
+ find ./contracts/src/ -type d -name '.*' -prune -o \
+   -type f -name "*.ts" -o -name "*.js" -exec sed -i "s/\(version['\"]?:\s*['\"]?\)$ESCAPED_CURRENT/\1$ESCAPED_NEW/g" {} +
+
+ # Replace version in docs/ with targeted pattern
+ find ./docs/ -type d -name '.*' -prune -o \
+   -type f ! -name 'package-lock.json' -name "*.md" -o -name "*.json" \
+   -exec sed -i "s/\(version['\"]?:\s*['\"]?\)$ESCAPED_CURRENT/\1$ESCAPED_NEW/g" {} +

Alternatively, use a dedicated version-management tool or scripts that parse and update structured files rather than global string replacement.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c42a334 and 88728ba.

📒 Files selected for processing (10)
  • .github/actions/setup/action.yml (3 hunks)
  • .github/workflows/checks.yml (1 hunks)
  • .github/workflows/codeql.yml (1 hunks)
  • .github/workflows/prepare-release.yml (1 hunks)
  • .github/workflows/release.yml (1 hunks)
  • .github/workflows/test.yml (2 hunks)
  • RELEASING.md (1 hunks)
  • compact/src/Builder.ts (4 hunks)
  • contracts/package.json (1 hunks)
  • contracts/tsconfig.json (1 hunks)
🔇 Additional comments (18)
contracts/tsconfig.json (1)

2-5: LGTM! TypeScript compilation scope appropriately narrowed.

The narrowed include pattern to src/**/witnesses/**/*.ts and explicit exclusion of src/archive/ align well with the new four-step build pipeline, where TypeScript compilation (Step 2) focuses only on witness files while .compact files are handled separately (Step 3).

RELEASING.md (2)

1-11: LGTM! Clear introduction and branch creation steps.

The instructions properly account for both standard releases from main and hotfix scenarios, with clear examples.


31-34: LGTM! GitHub release creation step is clear.

The instructions properly reference the releases page and explain the workflow trigger for npm publishing.

compact/src/Builder.ts (4)

16-40: LGTM! Documentation clearly reflects the new four-step build process.

The updated class description and examples accurately document the new build pipeline and distribution structure.


47-51: LGTM! Clean step is safe and correct.

The rm -rf dist && mkdir -p dist command properly cleans and recreates the distribution directory with appropriate error chaining.


167-169: LGTM! Output guard improves code quality.

The conditional check if (lines.length > 0) before printing colored output prevents empty sections and improves the build output readability.


109-110: LGTM! Build completion message enhances user experience.

The green checkmark with "Build complete!" message provides clear feedback when all build steps finish successfully.

.github/actions/setup/action.yml (5)

1-25: LGTM! Input/output structure and version configuration are correct.

The action properly defines the skip-compact input and version outputs, with environment variables set appropriately for downstream steps.


27-54: LGTM! Cache configuration is correct and efficient.

The caching strategy properly includes Yarn, Turbo, and Compact compiler caches, with appropriate cache keys and conditional execution for the Compact cache based on the skip-compact input.


56-71: LGTM! Node.js and dependency setup follows best practices.

Using .nvmrc for Node version, --immutable for Yarn, and version-pinned Turbo installation with telemetry disabled are all appropriate configuration choices.


73-85: LGTM! Compact installation is secure and well-configured.

The installation step uses appropriate security measures with --proto '=https' and --tlsv1.2, proper error handling with set -euo pipefail, and conditional execution. The trust in COMPACT_INSTALLER_URL from GitHub repository variables is reasonable for this context.


86-108: LGTM! Environment setup and outputs are correctly configured.

The Compact environment setup properly exports variables, validates the installation, and provides outputs for downstream consumption, with appropriate error handling.

contracts/package.json (2)

1-22: LGTM! Package metadata is complete and professional.

The public package metadata is well-structured with appropriate version (0.0.1), clear description, relevant keywords, and correct URLs for repository, documentation, and bug tracking. The MIT license aligns with OpenZeppelin's licensing standards.


23-34: Build script correctly delegates TypeScript compilation to compact-builder.

Removing the explicit tsc call from the build script is correct. The script output confirms that compact-builder now handles TypeScript compilation in Builder.ts Step 2 with tsc --project tsconfig.build.json, and the required tsconfig.build.json configuration file exists at contracts/tsconfig.build.json. The refactoring is complete and properly encapsulates the build process.

.github/workflows/codeql.yml (1)

25-26: LGTM! Environment variable properly configured.

The COMPACT_INSTALLER_URL is correctly sourced from repository variables and made available to the workflow's steps, consistent with the centralized setup approach used across other workflows.

.github/workflows/checks.yml (1)

17-18: LGTM! Environment variable properly configured.

The COMPACT_INSTALLER_URL follows the same correct pattern as other workflows, making the installer URL available from repository variables.

.github/workflows/test.yml (2)

15-16: LGTM! Environment variable properly configured.

The COMPACT_INSTALLER_URL is correctly configured, consistent with the pattern used in other workflows.


27-28: LGTM! Simplified compilation step delegates setup to shared action.

The streamlined compilation step using turbo compact with sequential concurrency (--concurrency=1) is appropriate, and delegating installation to the setup action reduces duplication across workflows.

Copy link
Member Author

@0xisk 0xisk left a comment

Choose a reason for hiding this comment

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

@emnul Could you please review this PR and check if Son comments have been addressed correctly?

Copy link
Contributor

@emnul emnul left a comment

Choose a reason for hiding this comment

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

Let me know what you think about the changes:

  • Updated references to Compact 0.26.0
  • Updated actions to latest versions
  • Updated runner to use pinned version

As well as the proposed change to prerelease.yml

@0xisk
Copy link
Member Author

0xisk commented Nov 7, 2025

@emnul Thank you! Could you please give it a look? But maybe lets merge this PR first #212 and then I will rebase to merge this one.

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.

4 participants