Skip to content
Open
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
28 changes: 26 additions & 2 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ jobs:
- name: Run unit tests with coverage
run: npm run test:coverage

- name: Comment coverage on PR
- name: Comment ngx coverage on PR
uses: ArtiomTr/jest-coverage-report-action@262a7bb0b20c4d1d6b6b026af0f008f78da72788 # v2.3.1
if: github.event_name == 'pull_request'
continue-on-error: true
with:
custom-title: Coverage report
custom-title: Ngx coverage report
coverage-file: ./coverage/report.json
# Tests already ran above; the action only formats the report.
skip-step: all
Expand Down Expand Up @@ -105,6 +105,30 @@ jobs:
- name: Smoke-test the packed packages
run: npm run smoke

release:
name: Release config
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v7
with:
# The release check compares bootstrap-sha with the tagged commit.
fetch-tags: true

- name: Setup Node.js
uses: actions/setup-node@v7
with:
node-version: 22.x

# Plain Node: neither needs the workspace's dependencies.
- name: Test the publish script and the release workflow's wiring
run: npm run test:release

# Replays releases through the Release Please version the release
# workflow runs, on this repository's config.
- name: Check the release config
run: npm run release:check

lint:
name: Lint and format
runs-on: ubuntu-latest
Expand Down
22 changes: 17 additions & 5 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,22 @@ on:
push:
branches:
- main
# Retries a failed or partial publish: run it on the release tag,
# e.g. `gh workflow run release-please.yml --ref ngx-ui-watchtower-v0.5.0`.
workflow_dispatch:

permissions: {}

jobs:
release-please:
if: github.event_name == 'push'
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
outputs:
release_created: ${{ steps.release.outputs['projects/ngx-ui-watchtower--release_created'] }}
core_release_created: ${{ steps.release.outputs['projects/ui-watchtower--release_created'] }}
ngx_release_created: ${{ steps.release.outputs['projects/ngx-ui-watchtower--release_created'] }}
steps:
- uses: googleapis/release-please-action@v5
id: release
Expand All @@ -26,7 +31,13 @@ jobs:

publish:
needs: release-please
if: ${{ needs.release-please.outputs.release_created == 'true' }}
# After a release of either package, or when run by hand to retry. On a
# manual run release-please is skipped, which !cancelled() lets through.
if: >-
${{ !cancelled() && (
github.event_name == 'workflow_dispatch' ||
needs.release-please.outputs.core_release_created == 'true' ||
needs.release-please.outputs.ngx_release_created == 'true') }}
runs-on: ubuntu-latest
permissions:
# Required for npm trusted publishing (OIDC). No npm token needed.
Expand All @@ -48,9 +59,10 @@ jobs:
- name: Install dependencies
run: npm ci

- name: Build library
- name: Build both packages
run: npm run build

# The core, then the Angular package: each only if its release tag
# points at this commit and the version isn't on npm yet.
- name: Publish to npm
working-directory: dist/ngx-ui-watchtower
run: npm publish
run: node scripts/publish-packages.mjs
154 changes: 115 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="assets/logo/logo-stacked-dark.svg">
<source media="(prefers-color-scheme: light)" srcset="assets/logo/logo-stacked-light.svg">
<img src="assets/logo/logo-stacked-auto.svg" alt="Angular UI Watchtower" width="280">
</picture>
<img src="assets/logo/logo-stacked-light.svg#gh-light-mode-only" alt="UI Watchtower" width="280">
<img src="assets/logo/logo-stacked-dark.svg#gh-dark-mode-only" alt="UI Watchtower" width="280">
</p>

# Angular UI Watchtower
# UI Watchtower

Source of [`@absaoss-cps/ngx-ui-watchtower`](https://www.npmjs.com/package/@absaoss-cps/ngx-ui-watchtower),
a telemetry library for Angular apps: scenarios (user end-to-end journeys or specific functional workflows through an app), BI events and
logs, with an optional AWS CloudWatch RUM sink. It builds on
[`@absaoss-cps/ui-watchtower`](projects/ui-watchtower/README.md), the
framework-independent engine, which lives here too.
Telemetry for frontend applications, in three parts:

How to use the library: [projects/ngx-ui-watchtower/README.md](projects/ngx-ui-watchtower/README.md)
(also the npm page).
How it is designed: [projects/ngx-ui-watchtower/DESIGN.md](projects/ngx-ui-watchtower/DESIGN.md).
- **Scenarios** — did a user journey or a workflow succeed, and how long did
it take?
- **BI events** — which features are used?
- **Logs** — what exactly happened?

Events go to AWS CloudWatch RUM or another destination you choose; logs go
to a backend you provide.

It comes as two packages, each with its own version:

| Package | Use it in | Guide |
| ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------- |
| [`@absaoss-cps/ui-watchtower`](https://www.npmjs.com/package/@absaoss-cps/ui-watchtower) | Any frontend: plain JavaScript or TypeScript, or any framework. Framework adapters are built on it ([how](docs/ADAPTERS.md)). | [README](projects/ui-watchtower/README.md) |
| [`@absaoss-cps/ngx-ui-watchtower`](https://www.npmjs.com/package/@absaoss-cps/ngx-ui-watchtower) | Angular applications. A thin adapter over `@absaoss-cps/ui-watchtower`: Angular providers, injectable services and Observables around the same engine. | [README](projects/ngx-ui-watchtower/README.md) |

Each guide is also the package's npm page. How it is designed:
[projects/ngx-ui-watchtower/DESIGN.md](projects/ngx-ui-watchtower/DESIGN.md).

## Layout

Expand All @@ -35,10 +42,13 @@ projects/ngx-ui-watchtower/
README.md usage guide, published to npm
DESIGN.md full design
package.json the published package's manifest
scripts/ the public API snapshot, and the packaging smoke test
docs/ ADAPTERS.md: how to write a framework adapter
scripts/ the public API snapshot, the packaging smoke test, and publishing
```

The Angular package depends on the core, never the other way round.
The Angular package depends on the core, never the other way round. Each
package has its own version; a core release also releases the Angular
package, with its dependency moved (see [Releases](#releases)).

## Getting started

Expand All @@ -56,20 +66,22 @@ application does. Tests and the typecheck read the core's source.

## Scripts

| Script | What it does |
| ----------------------- | -------------------------------------------------------------- |
| `npm run build` | Builds both packages (production), the core first |
| `npm run watch` | Builds the core, then rebuilds the Angular package on change |
| `npm run test` | Runs the unit tests of both packages (Jest) |
| `npm run test:core` | Runs the core's unit tests only: plain Jest, no Angular |
| `npm run test:coverage` | Runs the unit tests with coverage, as CI does |
| `npm run typecheck` | Builds the core, then type-checks every tsconfig and type test |
| `npm run api:check` | Builds both packages, then compares their public APIs |
| `npm run api:update` | Builds both packages, then rewrites their snapshots |
| `npm run smoke` | Installs the built packages, packed, into throwaway consumers |
| `npm run lint` | ESLint, no warnings allowed |
| `npm run format` | Formats with Prettier |
| `npm run format:check` | Checks formatting without writing |
| Script | What it does |
| ----------------------- | ---------------------------------------------------------------- |
| `npm run build` | Builds both packages (production), the core first |
| `npm run watch` | Builds the core, then rebuilds the Angular package on change |
| `npm run test` | Runs the unit tests of both packages (Jest), then `test:release` |
| `npm run test:core` | Runs the core's unit tests only: plain Jest, no Angular |
| `npm run test:release` | Tests the publish script and the release workflow's wiring |
| `npm run test:coverage` | Runs the unit tests with coverage, as CI does; fails below 90% |
| `npm run typecheck` | Builds the core, then type-checks every tsconfig and type test |
| `npm run api:check` | Builds both packages, then compares their public APIs |
| `npm run api:update` | Builds both packages, then rewrites their snapshots |
| `npm run smoke` | Installs the built packages, packed, into throwaway consumers |
| `npm run release:check` | Replays releases through Release Please on the release config |
| `npm run lint` | ESLint, no warnings allowed |
| `npm run format` | Formats with Prettier |
| `npm run format:check` | Checks formatting without writing |

Four checks guard what consumers depend on:

Expand Down Expand Up @@ -106,6 +118,7 @@ npm run format:check
npm run build
npm run api:check
npm run smoke
npm run release:check
```

CI runs the same checks on every pull request and every push to `main`.
Expand All @@ -124,15 +137,78 @@ Squash-merge pull requests: the title then becomes the commit message on
## Releases

Releases are automated with [release-please](https://github.com/googleapis/release-please)
— don't publish by hand.

1. Every push to `main` updates a release PR. `feat` bumps the minor version,
`fix`, `perf` and `revert` the patch; until 1.0, a breaking change bumps
the minor. Other types don't trigger a release.
2. The release PR holds the version bump and the `CHANGELOG.md` entry.
3. Merging it tags the release, creates the GitHub release and publishes the
package to npm from GitHub Actions through trusted publishing — no npm
token.
— don't publish by hand. Each package has its own version and changelog, and
is released when it changes:

| A change to | Releases |
| ------------------- | ------------------------------------------------------------------------------------------ |
| The Angular package | The Angular package |
| The core | The core, and a patch of the Angular package that moves its dependency to `^` the new core |
| Both | Each, with its own bump |

1. Every push to `main` updates one release PR, for every package with
changes. `feat` bumps the minor version, `fix`, `perf` and `revert` the
patch; until 1.0, a breaking change bumps the minor. Other types don't
trigger a release.
2. The release PR holds each released package's version bump and
`CHANGELOG.md` entry. When the core is released, Release Please's
`node-workspace` plugin also moves the Angular package's dependency on the
core and releases it as a patch, so it always depends on the core it was
built against.
3. Merging it tags each release, `ui-watchtower-v<version>` or
`ngx-ui-watchtower-v<version>` (until 0.4.0, the Angular package's tags
were `v<version>`), and creates its GitHub release. GitHub Actions then
publishes what was released, the core before the Angular package, through
trusted publishing — no npm token.

**A failed publish** stops before the next package, so the Angular package
never depends on a core that isn't on npm. To finish a partial release, run
the workflow again on the release tag:

```bash
gh workflow run release-please.yml --ref ngx-ui-watchtower-v<version>
```

[`scripts/publish-packages.mjs`](scripts/publish-packages.mjs) publishes a
package only if its release tag points at that commit and npm doesn't have
the version yet; any other answer from npm stops it.

**The core's first release is 0.1.0, and its first publish is by hand.** The
core's `initial-version` in `release-please-config.json` sets that version.
npm sets up trusted publishing only for a package that exists. Before the
first release PR that releases the core is merged, an `@absaoss-cps` owner
publishes the core from that PR's branch:

```bash
npm login
git fetch origin
git switch release-please--branches--main
npm ci && npm run build
npm publish dist/ui-watchtower
```

Then, on npmjs.com, in the package's settings, add the trusted publisher the
Angular package has: GitHub Actions, `AbsaOSS/ui-watchtower`, workflow
`release-please.yml`. After the merge, publishing finds 0.1.0 on npm, skips
it, and publishes the Angular package. If the release PR is merged first,
publishing stops at the core; publish it as above from the
`ui-watchtower-v0.1.0` tag, then run the workflow on the release tag.

`bootstrap-sha` in `release-please-config.json` is the commit tagged
`v0.4.0`: it keeps what that release shipped out of the first changelogs,
and is read only until both packages have a release. If another `v` release
reaches `main` first, set it to that release's commit. `npm run release:check`
compares the two.

`npm run release:check` replays releases through the Release Please version
the workflow runs, on this config:

- the first release, with the core at 0.1.0;
- an Angular-only change releasing only the Angular package;
- a core change also releasing the Angular package, with its dependency moved;
- merging creating the tags publishing looks for.

It installs Release Please, so it needs a network.

## License

Expand Down
Loading
Loading