Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,19 @@ jobs:
- run: pnpm verify
- run: pnpm test:package

- name: Verify committed action bundle is fresh
run: |
pnpm --filter @lukasparke/diffler build:action
git diff --exit-code packages/diffler/dist-action

- name: Install ffmpeg
run: |
sudo apt-get update
sudo apt-get install -y ffmpeg

- name: Smoke test animated card rendering
env:
STATS_JSON_URL: https://raw.githubusercontent.com/LukasParke/stats/main/github-user-stats.json
STATS_JSON_FILE: packages/remotion/fixtures/github-user-stats.json
RENDER_CARD_CONCURRENCY: 1
REMOTION_CONCURRENCY: 4
run: pnpm --filter @lukasparke/diffler-remotion test:render
34 changes: 28 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ Self-contained monorepo for generating animated GitHub profile READMEs with live
# Install all workspace dependencies
pnpm install --frozen-lockfile

# Run tests (resolves workspace sources directly; no build needed)
pnpm test

# Build all packages
pnpm build

# Run diffler CLI
pnpm diffler -- collect --config .github/diffler.yml

# Run tests across all packages
pnpm test
```

## Workspaces
Expand All @@ -50,9 +50,31 @@ pnpm --filter @lukasparke/diffler-remotion test
└─────────────────┘ └──────────────────┘ └─────────────────┘
```

1. **diffler** collects comprehensive GitHub stats via GraphQL + REST and package install stats through registry adapters
2. Provider-specific package data is normalized alongside GitHub data in the v2 JSON schema
3. **@lukasparke/diffler-remotion** reads the JSON and renders animated profile cards
1. **diffler** collects comprehensive GitHub stats via GraphQL + REST and package install stats through registry adapters, writing the canonical v2 schema defined in `@lukasparke/diffler-schemas`
2. Provider-specific package data is normalized alongside GitHub data in the v2 JSON schema; multi-profile outputs are merged by the shared `mergeStatsOutputs` in the schemas package
3. **@lukasparke/diffler-remotion** validates the JSON against the shared Zod schema and renders animated profile cards

## Using the GitHub Action

The action runs a committed single-file bundle (`packages/diffler/dist-action/`), so consumer workflows need no install or build step. Because the action commits and pushes README updates, the consuming workflow needs:

```yaml
permissions:
contents: write
```

The bundle is verified against its sources in CI; run `pnpm --filter @lukasparke/diffler build:action` after CLI changes and commit the result.

## Releasing

Package versions move in lockstep (enforced by `scripts/publish-release.mjs`):

```bash
node scripts/bump-version.mjs 1.0.0 # bumps all packages + refreshes the lockfile
git commit -am "release: v1.0.0" && git tag v1.0.0 && git push --tags
```

Pushing a `v*` tag runs the release workflow, which publishes all packages to npm.

## GitHub Actions

Expand Down
11 changes: 8 additions & 3 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ rendering.
- [x] Scoped, independently publishable npm packages
- [x] GitHub Pages asset deployment
- [x] Packed CLI smoke test
- [x] Canonical v2 output schema (no legacy aliases), shared merge, and a
schema-validated renderer adapter
- [x] Hermetic GitHub Action (committed bundle, git identity configured)
- [x] Template data-source helpers render prefetched data synchronously
- [ ] Publish the first npm release from a version tag
- [ ] Move the `v1` tag after the release workflow succeeds
- [ ] Migrate `LukasParke/LukasParke` from readme-scribe to Diffler
Expand All @@ -20,7 +24,8 @@ rendering.
## Next

- Add a PyPI package-stats adapter using the normalized package metrics seam.
- Add a consumer fixture that exercises the released GitHub Action.
- Consolidate the three Remotion export commands.
- Add a consumer fixture that exercises the released GitHub Action end to end
(the render smoke test already runs from a committed fixture).
- Measure and reduce stats collection and animation render time; templates now
opt out of traffic/contributor backfill they do not reference.
- Add image-link validation to the profile repository.
- Measure and reduce stats collection and animation render time.
28 changes: 14 additions & 14 deletions packages/diffler/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ outputs:
description: Whether the README was changed
value: ${{ steps.render.outputs.changed }}

# Composite action that runs the committed single-file CLI bundle
# (dist-action/index.js). CI verifies the bundle is fresh on every change, so
# no install/build steps are needed here — the action is hermetic and fast.
# Consumer workflows need `permissions: contents: write` to allow the push.
runs:
using: composite
steps:
Expand All @@ -76,17 +80,6 @@ runs:
with:
node-version: "20"

- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10.34.5

- name: Build Diffler action
shell: bash
run: |
pnpm --dir "$GITHUB_ACTION_PATH/../.." install --frozen-lockfile
pnpm --dir "$GITHUB_ACTION_PATH/../.." --filter @lukasparke/diffler... build

- name: Collect stats (optional)
id: collect
if: inputs.collect-stats == 'true'
Expand All @@ -98,14 +91,21 @@ runs:
export DIFFLER_GITHUB_USERNAME="${{ inputs.username }}"
fi

node "$GITHUB_ACTION_PATH/dist/cli.js" collect \
node "$GITHUB_ACTION_PATH/dist-action/index.js" collect \
--config "${{ inputs.config }}" \
--output-path "${{ inputs.stats-output-path }}" \
--cache-path "${{ inputs.stats-cache-path }}" \
--volatile-cache-path "${{ inputs.stats-volatile-cache-path }}" \
--backfill-mode "${{ inputs.stats-backfill-mode }}" \
${{ inputs.stats-include-private == 'true' && '--include-private' || '' }}

- name: Configure git identity
if: inputs.dry-run != 'true'
shell: bash
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

- name: Render profile README
id: render
shell: bash
Expand All @@ -116,11 +116,11 @@ runs:
export DIFFLER_GITHUB_USERNAME="${{ inputs.username }}"
fi

node "$GITHUB_ACTION_PATH/dist/cli.js" render --config "${{ inputs.config }}" --output "${{ inputs.output }}"
node "$GITHUB_ACTION_PATH/dist-action/index.js" render --config "${{ inputs.config }}" --output "${{ inputs.output }}"

if [ -n "${{ inputs.remotion-output }}" ]; then
echo "Generating remotion config..."
node "$GITHUB_ACTION_PATH/dist/cli.js" export-remotion --config "${{ inputs.config }}" --output "${{ inputs.remotion-output }}"
node "$GITHUB_ACTION_PATH/dist-action/index.js" export-remotion --config "${{ inputs.config }}" --output "${{ inputs.remotion-output }}"
fi

if [ "${{ inputs.dry-run }}" = "true" ]; then
Expand Down
Loading
Loading