release: prepare 1.0.0-rc.1

This commit is contained in:
vorotamoroz
2026-07-27 03:37:46 +00:00
parent 3ce6ccf7a6
commit d5a40a7e3d
15 changed files with 81 additions and 22 deletions
+8 -1
View File
@@ -101,8 +101,15 @@ jobs:
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ github.token }}
VERSION: ${{ inputs.version }} VERSION: ${{ inputs.version }}
PRERELEASE: ${{ inputs.prerelease }} PRERELEASE: ${{ inputs.prerelease }}
PUBLISH_CLI: ${{ inputs.publish_cli }}
run: | run: |
set -euo pipefail set -euo pipefail
if [[ "${PUBLISH_CLI}" == "true" ]]; then
gh workflow run cli-docker.yml \
--ref "${VERSION}-cli" \
--field dry_run=false \
--field force=false
fi
gh workflow run release.yml \ gh workflow run release.yml \
--ref "${VERSION}" \ --ref "${VERSION}" \
--field tag="${VERSION}" \ --field tag="${VERSION}" \
@@ -118,7 +125,7 @@ jobs:
{ {
echo "Ensured the plug-in tag \`${VERSION}\` points to the reviewed release commit." echo "Ensured the plug-in tag \`${VERSION}\` points to the reviewed release commit."
if [[ "${PUBLISH_CLI}" == "true" ]]; then if [[ "${PUBLISH_CLI}" == "true" ]]; then
echo "The CLI tag \`${VERSION}-cli\` was also created; its tag event starts the container workflow." echo "The CLI tag \`${VERSION}-cli\` was also created, and finalisation explicitly dispatched the CLI container workflow."
else else
echo "CLI publication was omitted." echo "CLI publication was omitted."
fi fi
+3 -3
View File
@@ -264,8 +264,8 @@ The `Finalise Release Tags` and `Release Obsidian Plugin` workflows use the `rel
- Run the `Prepare Release PR` workflow with the target version and selected base branch. It creates the release branch, updates versions, confirms that Commonlib is locked to an immutable package version, moves the `## Unreleased` notes to the target version, commits the release preparation, pushes the branch, and opens a draft release PR. The base branch may already select the target development version; the workflow still runs the version lifecycle so that release-only metadata such as `versions.json` is recorded in the release commit. - Run the `Prepare Release PR` workflow with the target version and selected base branch. It creates the release branch, updates versions, confirms that Commonlib is locked to an immutable package version, moves the `## Unreleased` notes to the target version, commits the release preparation, pushes the branch, and opens a draft release PR. The base branch may already select the target development version; the workflow still runs the version lifecycle so that release-only metadata such as `versions.json` is recorded in the release commit.
- Do not tag the release branch when the PR is first created. Polish the release PR first, especially `updates.md`. - Do not tag the release branch when the PR is first created. Polish the release PR first, especially `updates.md`.
- Once the release PR head is fixed, run the `Finalise Release Tags` workflow with its full head commit SHA. It validates the release branch, ensures that the plug-in tag points to that commit, optionally creates the corresponding CLI tag, and dispatches the plug-in release workflow. A CLI tag starts its own container workflow. The finalisation workflow can be retried when existing tags already point to the reviewed commit, but stops if a selected tag points elsewhere. - Once the release PR head is fixed, run the `Finalise Release Tags` workflow with its full head commit SHA. It validates the release branch, ensures that the plug-in tag points to that commit, optionally creates the corresponding CLI tag, and explicitly dispatches the selected plug-in and CLI release workflows. The finalisation workflow can be retried when existing tags already point to the reviewed commit, but stops if a selected tag points elsewhere.
- The plug-in publishing workflow is intentionally dispatch-only. Pushing a plug-in tag directly does not publish a GitHub Release; use `Finalise Release Tags`, or dispatch `Release Obsidian Plugin` explicitly for recovery or a pre-release. The CLI Docker workflow retains its documented branch, tag, and manual triggers. - The plug-in publishing workflow is intentionally dispatch-only. Pushing a plug-in tag directly does not publish a GitHub Release; use `Finalise Release Tags`, or dispatch `Release Obsidian Plugin` explicitly for recovery or a pre-release. When CLI publication is selected, finalisation dispatches the CLI Docker workflow against the reviewed CLI tag instead of relying on a tag created by `GITHUB_TOKEN` to start another workflow.
- For a hyphenated pre-release, run finalisation with `prerelease=true`; CLI publication remains optional. For a stable version awaiting BRAT validation, use `prerelease=true` and `publish_cli=false`. - For a hyphenated pre-release, run finalisation with `prerelease=true`; CLI publication remains optional. For a stable version awaiting BRAT validation, use `prerelease=true` and `publish_cli=false`.
- Approve the `Release Obsidian Plugin` workflow for the `release` environment, then inspect the generated draft GitHub Release. When a hyphenated pre-release includes the CLI, confirm that it received only its immutable version and SHA-qualified image tags. - Approve the `Release Obsidian Plugin` workflow for the `release` environment, then inspect the generated draft GitHub Release. When a hyphenated pre-release includes the CLI, confirm that it received only its immutable version and SHA-qualified image tags.
- Publish the draft as a GitHub pre-release without replacing the latest stable release. Keep its release pull request in draft and leave its base branch unchanged throughout BRAT validation. Record that state in the pull request. - Publish the draft as a GitHub pre-release without replacing the latest stable release. Keep its release pull request in draft and leave its base branch unchanged throughout BRAT validation. Record that state in the pull request.
@@ -297,7 +297,7 @@ The `Finalise Release Tags` and `Release Obsidian Plugin` workflows use the `rel
- `prerelease`: enable for a version such as `1.0.0-rc.0`, and also when staging a stable version for BRAT. - `prerelease`: enable for a version such as `1.0.0-rc.0`, and also when staging a stable version for BRAT.
- `publish_cli`: optional for a hyphenated pre-release, but disable it when staging a stable version. - `publish_cli`: optional for a hyphenated pre-release, but disable it when staging a stable version.
5. Approve the `Release Obsidian Plugin` workflow for the `release` environment, then check the generated draft GitHub Release. 5. Approve the `Release Obsidian Plugin` workflow for the `release` environment, then check the generated draft GitHub Release.
6. If a hyphenated pre-release includes the CLI, confirm that the CLI tag event published only immutable version and SHA-qualified image tags. 6. If a hyphenated pre-release includes the CLI, confirm that the explicitly dispatched CLI workflow published only immutable version and SHA-qualified image tags.
7. Publish the draft as a GitHub pre-release without replacing the latest stable release, but keep the release PR in draft and leave its base branch unchanged. 7. Publish the draft as a GitHub pre-release without replacing the latest stable release, but keep the release PR in draft and leave its base branch unchanged.
8. Update the PR state message to describe the published pre-release and state that merging remains on hold. 8. Update the PR state message to describe the published pre-release and state that merging remains on hold.
9. Validate the published release through BRAT, including start-up, ordinary bidirectional synchronisation, and any release-specific regression scenario. 9. Validate the published release through BRAT, including start-up, ordinary bidirectional synchronisation, and any release-specific regression scenario.
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"id": "obsidian-livesync", "id": "obsidian-livesync",
"name": "Self-hosted LiveSync", "name": "Self-hosted LiveSync",
"version": "1.0.0-rc.0", "version": "1.0.0-rc.1",
"minAppVersion": "1.7.2", "minAppVersion": "1.7.2",
"description": "Community implementation of self-hosted livesync. Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.", "description": "Community implementation of self-hosted livesync. Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.",
"author": "vorotamoroz", "author": "vorotamoroz",
+5 -5
View File
@@ -1,12 +1,12 @@
{ {
"name": "obsidian-livesync", "name": "obsidian-livesync",
"version": "1.0.0-rc.0", "version": "1.0.0-rc.1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "obsidian-livesync", "name": "obsidian-livesync",
"version": "1.0.0-rc.0", "version": "1.0.0-rc.1",
"license": "MIT", "license": "MIT",
"workspaces": [ "workspaces": [
"src/apps/cli", "src/apps/cli",
@@ -15913,7 +15913,7 @@
}, },
"src/apps/cli": { "src/apps/cli": {
"name": "self-hosted-livesync-cli", "name": "self-hosted-livesync-cli",
"version": "1.0.0-rc.0-cli", "version": "1.0.0-rc.1-cli",
"dependencies": { "dependencies": {
"chokidar": "^4.0.0", "chokidar": "^4.0.0",
"minimatch": "^10.2.5", "minimatch": "^10.2.5",
@@ -15938,7 +15938,7 @@
}, },
"src/apps/webapp": { "src/apps/webapp": {
"name": "livesync-webapp", "name": "livesync-webapp",
"version": "1.0.0-rc.0-webapp", "version": "1.0.0-rc.1-webapp",
"dependencies": { "dependencies": {
"octagonal-wheels": "^0.1.51" "octagonal-wheels": "^0.1.51"
}, },
@@ -15950,7 +15950,7 @@
} }
}, },
"src/apps/webpeer": { "src/apps/webpeer": {
"version": "1.0.0-rc.0-webpeer", "version": "1.0.0-rc.1-webpeer",
"dependencies": { "dependencies": {
"octagonal-wheels": "^0.1.51" "octagonal-wheels": "^0.1.51"
}, },
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "obsidian-livesync", "name": "obsidian-livesync",
"version": "1.0.0-rc.0", "version": "1.0.0-rc.1",
"description": "Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.", "description": "Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.",
"main": "main.js", "main": "main.js",
"type": "module", "type": "module",
+3 -3
View File
@@ -101,9 +101,9 @@ COPY --from=runtime-deps /deps/node_modules ./node_modules
# Copy the built CLI bundle from builder stage # Copy the built CLI bundle from builder stage
COPY --from=builder /build/src/apps/cli/dist ./dist COPY --from=builder /build/src/apps/cli/dist ./dist
# Install entrypoint wrapper # Install the entrypoint wrapper with a deterministic mode, regardless of
COPY src/apps/cli/docker-entrypoint.sh /usr/local/bin/livesync-cli # source checkout permissions.
RUN chmod +x /usr/local/bin/livesync-cli COPY --chmod=755 src/apps/cli/docker-entrypoint.sh /usr/local/bin/livesync-cli
# Mount your vault / local database directory here # Mount your vault / local database directory here
VOLUME ["/data"] VOLUME ["/data"]
+11
View File
@@ -0,0 +1,11 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const dockerfile = readFileSync(new URL("./Dockerfile", import.meta.url), "utf8");
describe("CLI Docker image", () => {
it("sets a deterministic readable and executable entrypoint mode", () => {
expect(dockerfile).toContain("COPY --chmod=755 src/apps/cli/docker-entrypoint.sh /usr/local/bin/livesync-cli");
expect(dockerfile).not.toContain("RUN chmod +x /usr/local/bin/livesync-cli");
});
});
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "self-hosted-livesync-cli", "name": "self-hosted-livesync-cli",
"private": true, "private": true,
"version": "1.0.0-rc.0-cli", "version": "1.0.0-rc.1-cli",
"main": "dist/index.cjs", "main": "dist/index.cjs",
"type": "module", "type": "module",
"scripts": { "scripts": {
@@ -0,0 +1,11 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const setupPutCatHelper = readFileSync(new URL("./test/test-setup-put-cat-linux.sh", import.meta.url), "utf8");
describe("CLI setup URI E2E helper", () => {
it("evaluates Commonlib package imports as ESM", () => {
expect(setupPutCatHelper).toContain("node --input-type=module -e");
expect(setupPutCatHelper).not.toContain("npx tsx -e");
});
});
@@ -27,7 +27,7 @@ cli_test_init_settings_file "$SETTINGS_FILE"
echo "[INFO] creating setup URI from settings" echo "[INFO] creating setup URI from settings"
SETUP_URI="$( SETUP_URI="$(
SETTINGS_FILE="$SETTINGS_FILE" SETUP_PASSPHRASE="$SETUP_PASSPHRASE" npx tsx -e ' SETTINGS_FILE="$SETTINGS_FILE" SETUP_PASSPHRASE="$SETUP_PASSPHRASE" node --input-type=module -e '
import { fs } from "@vrtmrz/livesync-commonlib/node"; import { fs } from "@vrtmrz/livesync-commonlib/node";
import { encodeSettingsToSetupURI } from "@vrtmrz/livesync-commonlib/compat/API/processSetting"; import { encodeSettingsToSetupURI } from "@vrtmrz/livesync-commonlib/compat/API/processSetting";
(async () => { (async () => {
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "livesync-webapp", "name": "livesync-webapp",
"private": true, "private": true,
"version": "1.0.0-rc.0-webapp", "version": "1.0.0-rc.1-webapp",
"type": "module", "type": "module",
"description": "Browser-based Self-hosted LiveSync using FileSystem API", "description": "Browser-based Self-hosted LiveSync using FileSystem API",
"scripts": { "scripts": {
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "webpeer", "name": "webpeer",
"private": true, "private": true,
"version": "1.0.0-rc.0-webpeer", "version": "1.0.0-rc.1-webpeer",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
+24
View File
@@ -12,6 +12,30 @@ Earlier releases remain available in the 0.25 release history and the legacy rel
## Unreleased ## Unreleased
## 1.0.0-rc.1
27th July, 2026
The work towards 1.0 has become so substantial that I have written [an article about it](https://fancy-syncing.vrtmrz.net/blog/0036-livesync-1_0_0-en.html) (linked again here).
### Important
- This candidate retains the plug-in behaviour prepared for rc.0. The version was advanced because release tags are immutable; rc.0 was stopped during CLI validation before a plug-in release was published.
- This remains an opt-in pre-release for BRAT validation and does not replace the latest stable release. The exact rc.1 plug-in and CLI artefacts will be validated separately after publication.
### CLI and release validation
- CLI release validation now generates Setup URIs through the supported ESM package interface, allowing the Docker test to reach the CLI container instead of stopping during test preparation.
- The CLI Docker image now assigns its entrypoint permissions explicitly, so non-root execution does not depend on permissions inherited from the source checkout.
- Release finalisation now explicitly dispatches the CLI container workflow when CLI publication is selected, rather than relying on a workflow-created tag to start another workflow.
- Focused regression tests guard the ESM execution mode and deterministic container entrypoint permissions, while the existing release-workflow tests now require explicit CLI dispatch with non-dry-run, immutable-tag inputs.
### Testing
- The native CLI setup, put, cat, list, information, deletion, conflict-resolution, and revision-retrieval scenario completed with the packaged Commonlib dependency.
- The same scenario completed through the rebuilt non-root Docker image.
- The focused CLI and release-workflow unit tests passed after first demonstrating all three regressions against the unmodified implementation.
## 1.0.0-rc.0 ## 1.0.0-rc.0
27th July, 2026 27th July, 2026
+8 -3
View File
@@ -234,16 +234,21 @@ describe("release workflow", () => {
); );
}); });
it("dispatches the plug-in workflow and lets the CLI tag trigger its own workflow", () => { it("dispatches the selected plug-in and CLI workflows explicitly", () => {
const workflow = readFileSync(finaliseReleaseWorkflow, "utf8"); const workflow = readFileSync(finaliseReleaseWorkflow, "utf8");
expect(workflow).toContain("actions: write"); expect(workflow).toContain("actions: write");
expect(workflow).toContain('node utils/release-tags.mjs ensure "${VERSION}" "${EXPECTED_HEAD_SHA}"'); expect(workflow).toContain('node utils/release-tags.mjs ensure "${VERSION}" "${EXPECTED_HEAD_SHA}"');
expect(workflow).toContain('git push --atomic origin "refs/tags/${VERSION}" "refs/tags/${VERSION}-cli"'); expect(workflow).toContain('git push --atomic origin "refs/tags/${VERSION}" "refs/tags/${VERSION}-cli"');
expect(workflow).not.toContain("Tag already exists"); expect(workflow).not.toContain("Tag already exists");
expect(workflow).toContain("PUBLISH_CLI: ${{ inputs.publish_cli }}");
expect(workflow).toContain('if [[ "${PUBLISH_CLI}" == "true" ]]; then');
expect(workflow).toContain("gh workflow run cli-docker.yml");
expect(workflow).toContain('--ref "${VERSION}-cli"');
expect(workflow).toContain("--field dry_run=false");
expect(workflow).toContain("--field force=false");
expect(workflow).toContain("gh workflow run release.yml"); expect(workflow).toContain("gh workflow run release.yml");
expect(workflow).not.toContain("gh workflow run cli-docker.yml"); expect(workflow).toContain("explicitly dispatched the CLI container workflow");
expect(workflow).toContain("its tag event starts the container workflow");
}); });
it("publishes only by explicit dispatch and validates the selected release", () => { it("publishes only by explicit dispatch and validates the selected release", () => {
+2 -1
View File
@@ -12,5 +12,6 @@
"1.0.0-beta.3": "1.7.2", "1.0.0-beta.3": "1.7.2",
"1.0.0-beta.4": "1.7.2", "1.0.0-beta.4": "1.7.2",
"1.0.0-beta.5": "1.7.2", "1.0.0-beta.5": "1.7.2",
"1.0.0-rc.0": "1.7.2" "1.0.0-rc.0": "1.7.2",
"1.0.0-rc.1": "1.7.2"
} }