Skip to content

Commit 501c1a8

Browse files
authored
chore: date changelog and cut v0.1.0 release (#102) (#103)
* chore: date changelog and prepare v0.1.0 release (#102) Move accumulated [Unreleased] entries into [0.1.0] - 2026-07-31, document the release workflow in CONTRIBUTING.md, and update SECURITY.md for the first tagged pre-release. * add: release note * docs: tighten release checklist in CONTRIBUTING.md * docs: require tag validation before v0.1.0 release publish * docs: require tag commit match before release publish * docs: name RELEASE_NOTES artifact and standardize on develop branch * docs: peel tag to commit when verifying release target * docs: use tagged clone and non-editable install in v0.1.0 release notes * docs: offer security email unconditionally in SECURITY.md * chore: humanize release docs and apply Jannie cleanup Docs: plain-language release notes, active voice in SECURITY, colon instead of em dash in CONTRIBUTING. Code: walk up for image-registry.yml in run flow, share PLATFORM_CLI_MAP, remove unused helpers.
1 parent 2c804a3 commit 501c1a8

10 files changed

Lines changed: 88 additions & 89 deletions

File tree

CHANGELOG.md

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.1.0] - 2026-07-31
11+
12+
First public pre-release. The CLI package version is `0.1.0` (`cli/pyproject.toml`).
13+
1014
### Added
1115

16+
- `localci` CLI — analyze, list, run, status, logs, images, cache, and config commands
17+
- Configurable workflow patch pipeline for local act execution
18+
- Docker image management and caching (ccache, Boost, CMake, APT)
19+
- CI: ruff lint/format, mypy strict typecheck, unit tests, and act/Docker integration tests
20+
- Runnable validation example under `examples/`
21+
- README yq disambiguation and per-OS install matrix for [mikefarah/yq](https://github.com/mikefarah/yq) v4+
1222
- `CONTRIBUTING.md` — developer onboarding (setup, tests, lint, pre-commit, PR expectations)
1323
- `CHANGELOG.md` — this file
1424
- `.github/CODEOWNERS` — maintainer routing for reviews
@@ -32,19 +42,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3242
- `DependencyResolver.all_dependencies_met` treats `FAILED` and `CANCELLED` dependencies as unmet; dependents no longer start after a failed or cancelled `needs` job.
3343
- `PriorityJobQueue` event listeners run after `self._lock` is released, so callbacks can safely call back into the queue.
3444

35-
## [0.1.0] - TBD
36-
37-
Pre-release baseline. The CLI package version is `0.1.0` (`cli/pyproject.toml`).
38-
39-
### Added
40-
41-
- `localci` CLI — analyze, list, run, status, logs, images, cache, and config commands
42-
- Configurable workflow patch pipeline for local act execution
43-
- Docker image management and caching (ccache, Boost, CMake, APT)
44-
- CI: ruff lint/format, mypy strict typecheck, unit tests, and act/Docker integration tests
45-
- Runnable validation example under `examples/`
46-
- README yq disambiguation and per-OS install matrix for [mikefarah/yq](https://github.com/mikefarah/yq) v4+
47-
4845
### Pre-release stability (before 1.0)
4946

5047
This project is in **0.x** pre-release. Until **1.0.0**:

CONTRIBUTING.md

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,35 @@ pre-commit run -a
9393

9494
## Pull requests
9595

96-
1. Branch from `develop` (or `main` for release fixes).
96+
1. Branch from `develop`.
9797
2. Keep changes focused; link related issues in the PR description.
98-
3. Ensure CI is green lint, typecheck, unit tests, and integration tests must pass.
98+
3. Ensure CI is green: lint, typecheck, unit tests, and integration tests must pass.
9999
4. Request review from at least one maintainer. PRs need **at least one approving review** before merge.
100+
5. Update `CHANGELOG.md` for user-visible changes under `## [Unreleased]`.
101+
102+
## Branching and releases
103+
104+
- `develop` is the default branch where day-to-day work lands and releases are cut from.
105+
- To cut release `X.Y.Z` when `cli/pyproject.toml` already declares that version:
106+
1. Move the `## [Unreleased]` entries in [CHANGELOG.md](CHANGELOG.md) under a new
107+
`## [X.Y.Z] - YYYY-MM-DD` heading, leave `## [Unreleased]` empty, and update
108+
the link references at the bottom.
109+
2. Create `RELEASE_NOTES_vX.Y.Z.md` from the new `## [X.Y.Z]` section (see
110+
[RELEASE_NOTES_v0.1.0.md](RELEASE_NOTES_v0.1.0.md) for the format).
111+
3. Merge the changelog and release-notes update to `develop` via PR; wait for CI
112+
to be green.
113+
4. Create an annotated tag `vX.Y.Z` on the merged `develop` commit and push it
114+
(`git tag -a vX.Y.Z` then `git push origin vX.Y.Z`). If `vX.Y.Z` already
115+
exists, stop and verify `git rev-parse vX.Y.Z^{commit}` matches the merged
116+
release commit (`git rev-parse origin/develop`); do not publish from a tag
117+
that points elsewhere.
118+
5. Validate the tag: confirm `git show vX.Y.Z:CHANGELOG.md` has
119+
`## [X.Y.Z] - YYYY-MM-DD` (not `TBD`) and CI is green on the tagged commit.
120+
6. Publish the GitHub Release
121+
(`gh release create vX.Y.Z --notes-file RELEASE_NOTES_vX.Y.Z.md`) only after
122+
steps 4–5 confirm the tag points to the merged release commit.
123+
7. Confirm the `[Unreleased]` and `[X.Y.Z]` compare links at the bottom of
124+
[CHANGELOG.md](CHANGELOG.md) resolve after the new tag is created.
100125

101126
## Maintainers
102127

RELEASE_NOTES_v0.1.0.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# localci v0.1.0
2+
3+
<!-- Maintainer: merge the release PR to develop, tag v0.1.0 on that commit, confirm
4+
CHANGELOG.md at the tag shows ## [0.1.0] - 2026-07-31 (not TBD) and CI is green,
5+
then publish with: gh release create v0.1.0 --notes-file RELEASE_NOTES_v0.1.0.md -->
6+
7+
First public pre-release of Local CI. Run GitHub Actions workflows locally in Docker via [act](https://github.com/nektos/act).
8+
9+
## Highlights
10+
11+
- `localci` CLI: analyze, list, run, status, logs, images, cache, and config
12+
- Generic patch profile by default; set `profile: capy` for Boost.Capy/B2 workflow patches
13+
- Docker image management and caching (ccache, Boost, CMake, APT)
14+
- Priority-ordered parallel execution with resource limits
15+
- Windows and macOS matrix jobs fail with an explicit Linux-only message instead of running act without an image
16+
17+
## Install
18+
19+
```bash
20+
git clone --branch v0.1.0 https://github.com/cppalliance/local-ci-test-system.git
21+
cd local-ci-test-system/cli
22+
pip install .
23+
```
24+
25+
See [README.md](README.md) for prerequisites (Docker, act, mikefarah/yq v4+).
26+
27+
## Pre-1.0 stability
28+
29+
0.x pre-release: CLI flags, `.localci.yml`, and patch steps may change between minors. Pin a version and read [CHANGELOG.md](CHANGELOG.md) before upgrading.
30+
31+
Full changelog: https://github.com/cppalliance/local-ci-test-system/blob/v0.1.0/CHANGELOG.md

SECURITY.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,19 @@
22

33
## Supported Versions
44

5-
Local CI is in pre-release development. There are no tagged stable releases yet
6-
(`pyproject.toml` declares `0.1.0`, not yet tagged).
5+
| Version | Supported |
6+
| ------- | ------------------ |
7+
| 0.1.x | :white_check_mark: |
78

8-
Security fixes are produced only against the latest commit on the
9+
Security fixes land only on the latest commit on
910
[`develop`](https://github.com/cppalliance/local-ci-test-system/tree/develop)
10-
branch. Once a `v0.1.0` tag is cut, this section will be reformatted as a
11-
semver-style support table.
11+
for the current 0.1.x line.
1212

1313
## Reporting a Vulnerability
1414

1515
**Please do not open a public GitHub issue for security vulnerabilities.**
1616

17-
Report security issues through **[GitHub private vulnerability reporting](https://github.com/cppalliance/local-ci-test-system/security/advisories/new)** (preferred), or email **will@cppalliance.org** if you do not have a GitHub account.
17+
Report security issues through **[GitHub private vulnerability reporting](https://github.com/cppalliance/local-ci-test-system/security/advisories/new)** or email **will@cppalliance.org**.
1818

1919
If you need an encrypted channel, mention this in your initial email and a
2020
maintainer will reply with a current PGP key fingerprint or arrange another

cli/localci/cli/list.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import click
1313

1414
from localci.core.workflow import (
15+
PLATFORM_CLI_MAP,
1516
CompilerFamily,
1617
Platform,
1718
WorkflowAnalyzer,
@@ -29,12 +30,6 @@
2930
# Helpers
3031
# =====================================================================
3132

32-
_PLATFORM_MAP = {
33-
"linux": Platform.LINUX,
34-
"windows": Platform.WINDOWS,
35-
"macos": Platform.MACOS,
36-
}
37-
3833
_COMPILER_MAP = {
3934
"gcc": CompilerFamily.GCC,
4035
"clang": CompilerFamily.CLANG,
@@ -165,7 +160,7 @@ def list_cmd(
165160
entries = wf.all_matrix_entries()
166161

167162
if platform != "all":
168-
target = _PLATFORM_MAP.get(platform)
163+
target = PLATFORM_CLI_MAP.get(platform)
169164
if target:
170165
entries = [e for e in entries if e.platform == target]
171166

cli/localci/cli/run/run_flow.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,10 @@
1313
from localci.core.github_token import resolve_github_token, warn_sentinel_github_token
1414
from localci.core.models import JobEvent, JobEventType
1515
from localci.core.results import ExecutionSummary
16-
from localci.core.workflow import MatrixEntry, Platform, Workflow
16+
from localci.core.workflow import PLATFORM_CLI_MAP, MatrixEntry, Workflow
1717
from localci.errors import ActNotFoundError, DockerNotAvailableError, WorkflowError
1818
from localci.utils.output import print_error, print_info, print_warning
19-
20-
_PLATFORM_MAP = {
21-
"linux": Platform.LINUX,
22-
"windows": Platform.WINDOWS,
23-
"macos": Platform.MACOS,
24-
}
19+
from localci.utils.paths import REGISTRY_FILENAME, find_file_upward
2520

2621

2722
def execute_run(
@@ -73,13 +68,10 @@ def execute_run(
7368
return 0
7469

7570
priority_config = container.priority_config_factory(cfg)
76-
registry_candidate = project_dir / "image-registry.yml"
77-
registry_path: Path | None = (
78-
registry_candidate if registry_candidate.exists() else None
79-
)
71+
registry_path = find_file_upward(REGISTRY_FILENAME, project_dir)
8072

8173
matrix_include, matrix_exclude = _resolve_matrix_filters(options, cfg)
82-
plat_filter = _PLATFORM_MAP.get(options.platform) if options.platform else None
74+
plat_filter = PLATFORM_CLI_MAP.get(options.platform) if options.platform else None
8375
compiler_filter = options.compiler.lower() if options.compiler else None
8476
selected_set = {(jid, e.index) for jid, e in selected}
8577
job_filter_list = list({jid for jid, _ in selected})
@@ -197,7 +189,7 @@ def _filter_matrix_pairs(
197189
) -> list[tuple[str, MatrixEntry]]:
198190
selected = list(all_pairs)
199191
if platform:
200-
target_plat = _PLATFORM_MAP.get(platform)
192+
target_plat = PLATFORM_CLI_MAP.get(platform)
201193
selected = [(jid, e) for jid, e in selected if e.platform == target_plat]
202194

203195
compiler_filter = compiler.lower() if compiler else None

cli/localci/core/patch_registry.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
from importlib.metadata import entry_points
1515
from typing import TYPE_CHECKING
1616

17-
from localci.core.config import PATCH_STEP_NAMES
18-
1917
logger = logging.getLogger(__name__)
2018

2119
if TYPE_CHECKING:
@@ -38,13 +36,3 @@ def get_patch_step_registry() -> dict[str, type[PatchStep]]:
3836
"Failed to load localci.patch_steps entry point %r", ep.name
3937
)
4038
return registry
41-
42-
43-
def clear_patch_step_registry_cache() -> None:
44-
"""Clear the registry cache (for tests that register plugins at runtime)."""
45-
get_patch_step_registry.cache_clear()
46-
47-
48-
def is_builtin_patch_step(name: str) -> bool:
49-
"""Return True when *name* is a built-in (non-plugin) patch step."""
50-
return name in PATCH_STEP_NAMES

cli/localci/core/workflow.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ class Platform(Enum):
4141
UNKNOWN = "unknown"
4242

4343

44+
PLATFORM_CLI_MAP: dict[str, Platform] = {
45+
"linux": Platform.LINUX,
46+
"windows": Platform.WINDOWS,
47+
"macos": Platform.MACOS,
48+
}
49+
50+
4451
class CompilerFamily(Enum):
4552
"""Compiler family classification."""
4653

cli/localci/utils/output.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,3 @@ def make_table(*columns: str, title: str | None = None) -> Table:
105105
for col in columns:
106106
table.add_column(col)
107107
return table
108-
109-
110-
def print_not_implemented(command: str) -> None:
111-
"""Placeholder for commands whose backend is not yet built."""
112-
print_warning(
113-
f"[muted]{command}[/muted] is not yet implemented. "
114-
"It will be available once the corresponding module is built."
115-
)

cli/localci/utils/paths.py

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,34 +9,6 @@
99
from pathlib import Path
1010

1111

12-
def resolve_workflow(
13-
path: str | Path | None, config_workflow: Path | None = None
14-
) -> Path:
15-
"""Resolve a workflow file path.
16-
17-
Priority:
18-
1. Explicit *path* argument from the CLI
19-
2. ``workflow`` value from the loaded config
20-
3. Default ``.github/workflows/ci.yml``
21-
22-
Raises
23-
------
24-
FileNotFoundError
25-
If the resolved path does not exist.
26-
"""
27-
if path is not None:
28-
resolved = Path(path).resolve()
29-
elif config_workflow is not None:
30-
resolved = Path(config_workflow).resolve()
31-
else:
32-
resolved = Path(".github/workflows/ci.yml").resolve()
33-
34-
if not resolved.is_file():
35-
raise FileNotFoundError(f"Workflow file not found: {resolved}")
36-
37-
return resolved
38-
39-
4012
def ensure_directory(path: Path) -> Path:
4113
"""Create directory (and parents) if it does not exist, then return it."""
4214
path.mkdir(parents=True, exist_ok=True)

0 commit comments

Comments
 (0)