# Allure Report Trend Graph Empty, No History — The Cause and the Fix

Canonical: https://commareports.com/fix/allure-report-history-trend-missing
Published: 2026-11-02

> Allure's Trend widget is empty and the History tab says nothing because the history/ folder from the last report never made it into allure-results. How to carry it between CI runs, and why test names break it.

# Allure report has no history or trend

The Trend widget on the Overview page is empty, or shows a single dot.
Open any test and the History tab is blank, and the Retries tab never
lists the earlier attempt you know happened.

The report is fine. Allure simply never saw a previous run.

## Where Allure 2 gets history from

Allure does not keep a database. Every generate is stateless, and the
past arrives through one folder:

```
allure-results/
├── *-result.json         ← this run
├── *-container.json
└── history/              ← the past — only if you put it here
    ├── history.json
    ├── history-trend.json
    ├── duration-trend.json
    ├── categories-trend.json
    └── retry-trend.json
```

`allure generate` reads `allure-results/history/`, merges in the current
run, and writes the updated folder to `allure-report/history/`. The
loop only closes if you copy that output folder back into the next run's
results:

```bash
cp -r allure-report/history allure-results/history   # before generating
allure generate allure-results --clean -o allure-report
```

Locally, this works by accident as long as the old report is still on
disk. In CI it never works by accident: every job starts on a clean
runner, `allure-report/` does not exist, and every report is the first.

## Carrying history between CI runs

Store `history/` somewhere that outlives the job, restore it before
generating, save the new one after. On GitHub Actions the cache is the
least plumbing:

```yaml
- name: Restore Allure history
  uses: actions/cache@v4
  with:
    path: allure-history
    key: allure-history-${{ github.ref_name }}-${{ github.run_id }}
    restore-keys: allure-history-${{ github.ref_name }}-

- name: Generate report with history
  if: always()
  run: |
    mkdir -p allure-results/history
    cp -r allure-history/. allure-results/history/ 2>/dev/null || true
    allure generate allure-results --clean -o allure-report
    rm -rf allure-history && cp -r allure-report/history allure-history
```

The unique key plus a prefix `restore-keys` means every run restores the
newest history and saves its own. Two caveats: GitHub evicts caches not
read for 7 days, and caches are scoped to a branch (plus the default
branch), so a feature branch starts from `main`'s trend.

The same shape works with a build artifact or with the `gh-pages` branch
that hosts the report — what matters is restore, generate, save, in
that order. `if: always()` matters too: the run you most want in the
trend is the one where tests failed, and a failing test step skips
everything after it by default.

## Tests that never get history

If the trend fills in but some tests still show no history, the problem
is identity, not storage. Allure matches a test across runs by its
`historyId`, computed from the full name **and the parameters**.

Any parameter that changes per run gives the test a new identity every
time:

- a timestamp or generated id in a parametrized test
- a temp directory path passed in as a parameter
- a test name that includes the build number

Exclude the volatile parameter from the identity instead of dropping it
from the report. In allure-pytest:

```python
allure.dynamic.parameter("workdir", str(tmp_path), excluded=True)
```

Allure Java has the same switch on `Allure.parameter(...)`. Renaming a
test or moving it to another class also resets its history — expected,
but it surprises people after a refactor.

## Label the trend: executor.json

A trend without build labels is a row of anonymous dots. Write
`allure-results/executor.json` before generating:

```json
{
  "name": "GitHub Actions",
  "type": "github",
  "buildOrder": 482,
  "buildName": "CI #482",
  "buildUrl": "https://github.com/acme/app/actions/runs/123",
  "reportUrl": "https://commareports.com/p/YOUR_REPORT_ID"
}
```

`buildOrder` becomes the x-axis and `reportUrl` makes each trend point
clickable back to that run's report — which only helps if that URL still
works next month.

## Allure 3

Allure 3 drops the folder. History lives in one file set by
`historyPath` in the `allurerc` config, and each generate appends to it.
The CI pattern is the same — restore the file, generate, save it — with
one file instead of five.

## The other half of history: the reports themselves

The trend tells you a test went red on build 482. To find out why you
need build 482's report, and in most pipelines that report was a
[build artifact](/glossary/build-artifact) that expired under
[retention](/glossary/artifact-retention) weeks ago.

Publish the generated `allure-report/` directory to the same report on
every run and each build becomes a revision: one stable link, with
earlier runs still openable from the revision history. The `data/` and
`widgets/` JSON upload alongside `index.html`, so the report loads over
HTTPS instead of going [blank from `file://`](/fix/allure-report-blank-page).
Reviewers can then comment on the failing test itself rather than
pasting the stack trace into chat ([comment on HTML](/comment-on-html)).

**Limits:** entry HTML 5 MB; assets 25 MB per file, 250 MB and 500 files
per report. Large Allure runs have one JSON per test case — watch the
file count, or use `--single-file`.

## Try it

Comma is free — unlimited reports, unlimited commenters, unlimited
revision history.

**[Publish an Allure report →](https://commareports.com/)**

### Related

- [Allure report is a blank page](/fix/allure-report-blank-page)
- [Share an Allure report](/share-allure-report)
- [Flaky test](/glossary/flaky-test) · [Test quarantine](/glossary/test-quarantine)
- [The CI artifact link expired](/fix/ci-artifact-expired)
- [Publish from CI](/docs/ci)
