diff --git a/.github/workflows/release-binaries.yml b/.github/workflows/release-binaries.yml index 287e9a78..86625438 100644 --- a/.github/workflows/release-binaries.yml +++ b/.github/workflows/release-binaries.yml @@ -96,6 +96,16 @@ jobs: dist/embed-code-macos-arm64 \ dist/embed-code-macos-x64 + # Publish Linux as a ZIP so Unix executable permissions survive extraction. + - name: Package Linux Binary + if: steps.release.outputs.publish == 'true' + shell: bash + run: | + pushd dist >/dev/null + zip -q embed-code-linux.zip embed-code-linux + rm embed-code-linux + popd >/dev/null + # Notarize the macOS ZIPs that will be published as release assets. - name: Notarize macOS Binaries if: steps.release.outputs.publish == 'true' @@ -121,7 +131,7 @@ jobs: const path = require('path'); const releaseTag = process.env.RELEASE_TAG; - const releaseNotes = `Embed Code ${releaseTag}\n\nThis release contains pre-built Embed Code binaries for macOS ARM64, macOS x64, Linux, and Windows.`; + const releaseNotes = `Embed Code ${releaseTag}\n\nThis release contains pre-built Embed Code binaries for macOS ARM64, macOS x64, Linux, and Windows. Linux and macOS binaries are published as ZIP archives.`; const release = await github.rest.repos.createRelease({ owner: context.repo.owner, repo: context.repo.repo, diff --git a/PROJECT.md b/PROJECT.md index 76886b56..658add55 100644 --- a/PROJECT.md +++ b/PROJECT.md @@ -39,7 +39,9 @@ them inside code fences, and checks whether existing snippets are up-to-date. - `README.md`: project entry point, short run/build instructions, and links to the complete guide. -- `showcase/README.md`: complete user guide entry point and runnable workflow. +- `showcase/README.md`: complete user guide entry point and guide map. +- `showcase/quick-start/README.md`: smallest runnable setup for new users. +- `showcase/end-to-end-tests.md`: commands for validating the executable showcase. - `showcase/configuration/README.md`: command-line flags, YAML configuration, source roots, include/exclude patterns, and multiple embedding targets. - `showcase/embedding/README.md`: `` instruction syntax, source @@ -62,9 +64,10 @@ This repository is configured with these GitHub workflows: `master` to populate base coverage for later pull-request diffs and the README badge; `master` pushes do not have a coverage status gate by design. - `release-binaries`: reads `VERSION`, builds Linux, macOS, and Windows - binaries, signs and notarizes the macOS ARM64 and x64 ZIPs, and creates the - matching GitHub Release on pushes to `master`. It runs on a self-hosted macOS - ARM64 runner because Apple signing and notarization require macOS tooling. + binaries, packages Linux and macOS as ZIP archives, signs and notarizes the + macOS ARM64 and x64 ZIPs, and creates the matching GitHub Release on pushes + to `master`. It runs on a self-hosted macOS ARM64 runner because Apple + signing and notarization require macOS tooling. The release tag is `v` from `VERSION`. When the release already exists, the workflow emits a warning and finishes successfully without rebuilding or diff --git a/README.md b/README.md index ff149d76..1cf17f75 100644 --- a/README.md +++ b/README.md @@ -2,72 +2,117 @@ [![Coverage](https://codecov.io/gh/SpineEventEngine/embed-code-go/branch/master/graph/badge.svg)](https://codecov.io/gh/SpineEventEngine/embed-code-go) -Embed Code is a Go command-line tool that keeps documentation snippets in sync -with source files. It scans Markdown and HTML documents for `` -instructions, resolves the requested source content, and manages the following -code fence. +Embed Code helps keep code examples in Markdown and HTML documentation up to +date without manual copying. It takes snippets directly from source files and +reports when embedded content no longer matches the source. -This project replaces the earlier [`embed-code` utility for Ruby/Jekyll][embed-code-jekyll]. +## Typical Usage -## Start Here +For example, consider a simple project with a Java source file and Markdown documentation: -The complete usage guide lives in the [showcase](showcase/README.md). It covers -configuration, embedding instructions, check mode, embed mode, expected -failures, and runnable examples. +```text +. +|-- src/ +| `-- com/example/Greeting.java +`-- docs/ + `-- greeting.md +``` -## What It Does +The project contains `src/com/example/Greeting.java`: -- Embeds whole files, named fragments, source ranges, or matching source lines. -- Supports multiple named source roots for one documentation tree. -- Filters comments when examples should omit implementation notes. -- Processes Markdown and HTML documents. -- Runs in `check` mode for CI and `embed` mode to update documentation. +```java +package com.example; -## Run +public final class Greeting { + public static String message() { + return "Hello from Embed Code"; + } +} +``` -Download the asset for your platform from [GitHub Releases][releases]. +In `docs/greeting.md`, add an instruction `` followed by an empty code fence: -On Linux, for example: +````markdown +# Greeting -```bash -./embed-code-linux -mode=check -config-path=showcase/embedding/embed-code.yml +How to use our Greeting system: + +```java ``` -> It may be necessary to give the executable permission with `chmod +x` on Unix-like systems: -> ```bash -> chmod +x embed-code-linux -> ``` +Additional documentation. +```` -On macOS, download `embed-code-macos-arm64.zip` for Apple silicon or -`embed-code-macos-x64.zip` for Intel Macs. Then unzip it and run the binary: +The configured embed-code application run embeds code into the documentation file: -```bash -unzip embed-code-macos-arm64.zip -./embed-code-macos-arm64 -mode=check -config-path=showcase/embedding/embed-code.yml -``` +````markdown +# Greeting -Or run it with Go: +How to use our Greeting system: + +```java +package com.example; -```bash -go run ./main.go -mode=check -config-path=showcase/embedding/embed-code.yml +public final class Greeting { + public static String message() { + return "Hello from Embed Code"; + } +} ``` -Use `-mode=embed` when documentation should be rewritten with current source -content. See the [configuration guide](showcase/configuration/README.md) for -all command-line flags and YAML options. +Additional documentation. +```` + +## Language Support + +Embed Code works with any programming language, provided its source files use +valid UTF-8 text. Basic embedding treats source files as text and does not +require a language compiler or parser. + +## Next Steps -## Build +- Run the [quick start](showcase/quick-start/README.md) for a complete example + with source, configuration, and documentation files. +- Use the [showcase](showcase/README.md) as the entry point for all user guides + and runnable examples. +- Read the [configuration guide](showcase/configuration/README.md) for direct + command-line paths, YAML options, named source roots, document selection, and + multiple documentation targets. +- Read the [embedding guide](showcase/embedding/README.md) for fragments, line + and range patterns, comment filtering, and instruction attributes. -Use Go `1.26.4`. +## Download + +Download the asset for your platform from [GitHub Releases][releases]. +You do not need to install Go to use a release binary. + +| Platform | Release asset | Executable | +|---------------------|------------------------------|--------------------------| +| Linux x64 | `embed-code-linux.zip` | `embed-code-linux` | +| macOS Apple silicon | `embed-code-macos-arm64.zip` | `embed-code-macos-arm64` | +| macOS Intel | `embed-code-macos-x64.zip` | `embed-code-macos-x64` | +| Windows x64 | `embed-code-windows.exe` | `embed-code-windows.exe` | + +## Build From Source + +Using Embed Code does not require Go. +To build the application from this repository, install Go `1.26.4` and run: ```bash go build -trimpath -o embed-code main.go ``` -This creates `embed-code` on Unix-like systems or `embed-code.exe` on Windows. +This creates an executable named `embed-code`. +On Windows, use`-o embed-code.exe` to give it the standard `.exe` suffix. The `-trimpath` flag prevents local absolute paths from appearing in stack traces. -## Development +You can also run the application directly from the source checkout: + +```bash +go run ./main.go -mode=check -config-path=showcase/embedding/embed-code.yml +``` + +## Testing Run the normal test suite: @@ -103,5 +148,7 @@ Launch the GoDoc server: Open the package link printed by the script. +This project replaces the earlier [`embed-code` utility for Ruby/Jekyll][embed-code-jekyll]. + [embed-code-jekyll]: https://github.com/SpineEventEngine/embed-code [releases]: https://github.com/SpineEventEngine/embed-code-go/releases diff --git a/showcase/README.md b/showcase/README.md index 8a151999..cedee60e 100644 --- a/showcase/README.md +++ b/showcase/README.md @@ -1,53 +1,21 @@ # Embed Code Showcase -This is the complete usage guide for `embed-code-go`. It is also executable: -the showcase test runs the examples through the real CLI so the guide stays in -sync with the application. +This showcase explains how to use the Embed Code application to embed code +samples into Markdown or HTML documentation. -## Workflow +Embed Code can read any text-based source: Java, JavaScript, Python, plain text, +or any other format used by your project. -1. Configure source roots and documentation roots. -2. Add an `` instruction followed by a managed code fence. -3. Run check mode in CI to detect stale snippets. -4. Run embed mode when documentation should be rewritten from source. +The examples in this showcase use `go run` so they can execute directly from +the project source tree. In other projects, the intended workflow is to use a +downloaded [release binary](https://github.com/SpineEventEngine/embed-code-go/releases) +with the same configuration shapes shown here. ## Guide Map +- [Quick start](quick-start/README.md): the smallest runnable setup for a project. - [Configuration](configuration/README.md): how the CLI finds source files and documentation files. - [Embedding](embedding/README.md): how instructions select and render source content. - [Positive examples](embedding/positive): runnable examples that should pass. - [Negative examples](embedding/negative/docs): intentionally broken examples that document diagnostics. - -## Run the Showcase - -Run commands from the repository root. - -The end-to-end suite checks positive examples, expected failures, and all -configuration shapes: - -```bash -go test -tags showcase ./showcase -``` - -Check the positive embedding examples directly: - -```bash -go run ./main.go -mode=check -config-path=showcase/embedding/embed-code.yml -``` - -Check the configuration examples directly: - -```bash -go run ./main.go -mode=check -config-path=showcase/configuration/single-source.yml -go run ./main.go -mode=check -config-path=showcase/configuration/named-sources.yml -go run ./main.go -mode=check -config-path=showcase/configuration/include-exclude.yml -go run ./main.go -mode=check -config-path=showcase/configuration/multiple-embeddings.yml -``` - -The negative examples are intentionally broken, so these commands should fail: - -```bash -go run ./main.go -mode=check -config-path=showcase/embedding/negative/processing-errors.yml -go run ./main.go -mode=check -config-path=showcase/embedding/negative/stale.yml -``` diff --git a/showcase/configuration/README.md b/showcase/configuration/README.md index 6d493fd3..d205e87f 100644 --- a/showcase/configuration/README.md +++ b/showcase/configuration/README.md @@ -15,6 +15,10 @@ one of these ways: Do not combine direct roots with `-config-path`. +Source roots can contain any text files that your documentation embeds. +The examples use Java, Kotlin, and plain text so the configuration stays independent +of the programming language used by the project. + ## Command-Line Arguments - `-mode`: required execution mode, either `embed` or `check`. diff --git a/showcase/end-to-end-tests.md b/showcase/end-to-end-tests.md new file mode 100644 index 00000000..9b45f713 --- /dev/null +++ b/showcase/end-to-end-tests.md @@ -0,0 +1,43 @@ +# Showcase End-to-End Tests + +The showcase can also run as an end-to-end test suite. These steps are intended +for Embed Code application developers and are not part of the application usage +guide. + +Run commands from the repository root. + +The end-to-end suite checks positive examples, expected failures, and all +configuration shapes: + +```bash +go test -tags showcase ./showcase +``` + +Check the quick start directly: + +```bash +cd showcase/quick-start +go run ../../main.go -mode=check -config-path=config.yml +``` + +Check the positive embedding examples directly: + +```bash +go run ./main.go -mode=check -config-path=showcase/embedding/embed-code.yml +``` + +Check the configuration examples directly: + +```bash +go run ./main.go -mode=check -config-path=showcase/configuration/single-source.yml +go run ./main.go -mode=check -config-path=showcase/configuration/named-sources.yml +go run ./main.go -mode=check -config-path=showcase/configuration/include-exclude.yml +go run ./main.go -mode=check -config-path=showcase/configuration/multiple-embeddings.yml +``` + +The negative examples are intentionally broken, so these commands should fail: + +```bash +go run ./main.go -mode=check -config-path=showcase/embedding/negative/processing-errors.yml +go run ./main.go -mode=check -config-path=showcase/embedding/negative/stale.yml +``` diff --git a/showcase/quick-start/README.md b/showcase/quick-start/README.md new file mode 100644 index 00000000..3f429b0e --- /dev/null +++ b/showcase/quick-start/README.md @@ -0,0 +1,73 @@ +# Quick Start + +This folder is the smallest runnable Embed Code application setup. It contains: + +- [config.yml](config.yml): connects the source and target folders. +- [source](source): source files that can be embedded into documentation. +- [target](target): Markdown or HTML files with `` instructions. + +## Run + +Download the latest release for your platform from +[GitHub Releases](https://github.com/SpineEventEngine/embed-code-go/releases). +Extract binary file from archive, if necessary, and place it to the `quick-start` folder. + +Open this folder before running the example: + +```bash +cd showcase/quick-start +``` + +For this example the `embed-code-linux` binary is used, +but it is the same usage for all other binaries. + +Run check mode: + +```bash +./embed-code-linux -mode=check -config-path=config.yml +``` + +When working from this repository's source checkout, the same config can be run +with `go run`: + +```bash +go run ../../main.go -mode=check -config-path=config.yml +``` + +Check mode is read-only. It fails when a rendered snippet in `target` no longer +matches the source file. + +Run embed mode to fill or refresh snippets: + +```bash +./embed-code-linux -mode=embed -config-path=config.yml +``` + +> You can try modifying the source file and re-running the embedding to see the changes. + +## How It Works + +[config.yml](config.yml) points `code-path` at [source](source) and `docs-path` +at [target](target): + +```yaml +code-path: source +docs-path: target +``` + +[target/greeting.md](target/greeting.md) contains an embedding instruction +followed by a managed code fence: + +````markdown + +```java +``` +```` + +The `file` value is a relative path resolved from `code-path`, so this instruction reads +[source/com/example/Greeting.java](source/com/example/Greeting.java). +Embed mode writes the current source content into the managed fence. +Check mode verifies that the fence is already up-to-date. + +For more source/target configuration see [Configuration guide](../configuration/README.md). +For more embed-code instructions see [Embedding guide](../embedding/README.md). diff --git a/showcase/quick-start/config.yml b/showcase/quick-start/config.yml new file mode 100644 index 00000000..925ee347 --- /dev/null +++ b/showcase/quick-start/config.yml @@ -0,0 +1,2 @@ +code-path: source +docs-path: target diff --git a/showcase/quick-start/source/com/example/Greeting.java b/showcase/quick-start/source/com/example/Greeting.java new file mode 100644 index 00000000..a546a283 --- /dev/null +++ b/showcase/quick-start/source/com/example/Greeting.java @@ -0,0 +1,10 @@ +package com.example; + +public final class Greeting { + private Greeting() { + } + + public static void main(String[] args) { + System.out.println("Hello from Embed Code"); + } +} diff --git a/showcase/quick-start/target/greeting.md b/showcase/quick-start/target/greeting.md new file mode 100644 index 00000000..928ae998 --- /dev/null +++ b/showcase/quick-start/target/greeting.md @@ -0,0 +1,17 @@ +# Greeting + +This page embeds the complete `Greeting.java` source file. + + +```java +package com.example; + +public final class Greeting { + private Greeting() { + } + + public static void main(String[] args) { + System.out.println("Hello from Embed Code"); + } +} +``` diff --git a/showcase/showcase_test.go b/showcase/showcase_test.go index f3f85dea..bffedfa2 100644 --- a/showcase/showcase_test.go +++ b/showcase/showcase_test.go @@ -100,6 +100,20 @@ var _ = Describe("Showcase", func() { }) }) + Describe("quick start", func() { + It("should check the quick-start target", func() { + quickStartRoot := filepath.Join(repoRoot, "showcase", "quick-start") + + output, err := runEmbedCodeFromDir( + quickStartRoot, + filepath.Join("..", "..", "main.go"), + "check", + "config.yml", + ) + Expect(err).ShouldNot(HaveOccurred(), "expected quick-start example to pass:\n%s", output) + }) + }) + Describe("configuration examples", func() { for _, config := range []string{ "single-source.yml", @@ -326,8 +340,15 @@ func writeConfig( func runEmbedCode(repoRoot string, mode string, configPath string) (string, error) { GinkgoHelper() - cmd := exec.Command("go", "run", "./main.go", "-mode="+mode, "-config-path="+configPath) - cmd.Dir = repoRoot + return runEmbedCodeFromDir(repoRoot, "./main.go", mode, configPath) +} + +// runEmbedCodeFromDir executes the CLI through `go run` from workDir. +func runEmbedCodeFromDir(workDir string, mainPath string, mode string, configPath string) (string, error) { + GinkgoHelper() + + cmd := exec.Command("go", "run", mainPath, "-mode="+mode, "-config-path="+configPath) + cmd.Dir = workDir output, err := cmd.CombinedOutput() return string(output), err