diff --git a/.github/agents/code-review.agent.md b/.github/agents/code-review.agent.md index 26e08991f..cc4327814 100644 --- a/.github/agents/code-review.agent.md +++ b/.github/agents/code-review.agent.md @@ -161,7 +161,7 @@ Follow these stages sequentially to perform a complete review. Do not skip stage - **How-to guides**: `docs/how-to/*.rst` - **Explanation articles**: `docs/explanation/**/*.rst` - **Release notes**: `docs/release-notes/*.md` (for recent features) - - **README/Contributing**: `docs/readme.rst`, `docs/contributing.rst` + - **README/Contributing**: `docs/readme.rst`, `docs/contributing.rst`, `docs/contributing/development.rst` - **Definition file references**: `docs/reference/definition-files/*.rst` 3. **Record Evidence for Each Finding** (internal validation only): @@ -252,7 +252,7 @@ Follow these stages sequentially to perform a complete review. Do not skip stage ### Stage 7: Commit Message & PR Description Review **Intent**: Ensure commit messages and PR descriptions follow project conventions. -**Inputs**: Commit messages, PR description, [`docs/contributing.rst`](../../docs/contributing.rst). +**Inputs**: Commit messages, PR description, [`docs/contributing/development.rst`](../../docs/contributing/development.rst). **Actions**: - **Commit Message Format**: - Start with capitalized summary (no type prefix for code commits) @@ -389,7 +389,7 @@ All changed entities are properly documented across appropriate Diátaxis pillar ### Always Do - **Reference `docs/coding-style-guide.md`** when making style suggestions. -- Check commit message format against [`docs/contributing.rst`](../../docs/contributing.rst). +- Check commit message format against [`docs/contributing/development.rst`](../../docs/contributing/development.rst). - Use the coverage mechanism (`docs/.coverage.yaml` and `docs/coverage.md`) to identify documentation gaps. - **Complete verification pass (Stage 6, Sub-stage B)** before reporting documentation findings — search actual docs corpus with ≥2 query variants. - **Provide evidence for all documentation claims**: Include search terms, file paths, line numbers, or explicit "no matches" statements. diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index e92ae406b..2e07c22fb 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -2,7 +2,7 @@ This file provides general project context for GitHub Copilot. For review-specific guidance, see: - **Code Review**: `.github/agents/code-review.agent.md` -- **Documentation Review**: `.github/agents/doc-review.agent.md` +- **Documentation Review**: `.github/skills/documentation-review/SKILL.md` ## Project Overview @@ -37,7 +37,7 @@ Workshop is a tool for defining and handling ephemeral development environments. ## Coding Guidelines -See [`docs/contributing.rst`](../docs/contributing.rst) for detailed standards. Key points: +See [`docs/coding-style-guide.md`](../docs/coding-style-guide.md) for detailed standards. Key points: - **Error messages**: Lowercase, no trailing punctuation, actionable (`what was attempted: why it went wrong`) - **Error handling**: Consistent `if err := f(); err != nil { return err }` pattern @@ -63,11 +63,11 @@ See [`docs/contributing.rst`](../docs/contributing.rst) for detailed standards. ## Available Resources -- **Contributing Guide**: [`docs/contributing.rst`](../docs/contributing.rst) — Setup, standards, workflow +- **Contributing Guide**: [`docs/contributing/development.rst`](../docs/contributing/development.rst) — Setup, testing, workflow - **Documentation Style**: [`docs/doc-style-guide.md`](../docs/doc-style-guide.md) — reST/Markdown conventions - **PR Template**: [`.github/pull_request_template.md`](.github/pull_request_template.md) — Self-review checklist - **Code Review Agent**: [`.github/agents/code-review.agent.md`](.github/agents/code-review.agent.md) — For PR code reviews -- **Docs Review Agent**: [`.github/agents/doc-review.agent.md`](.github/agents/doc-review.agent.md) — For PR documentation reviews +- **Documentation Review Skill**: [`.github/skills/documentation-review/SKILL.md`](skills/documentation-review/SKILL.md) — For documentation reviews ## Related Repositories @@ -85,15 +85,17 @@ These external repositories provide authoritative context for the Workshop proje - `cover.yaml` — Coverage reports - `automatic-doc-checks.yml` — Sphinx builds (fail on warnings) - `doc-cover.yaml` — Documentation coverage map generation +- `doc-update-sdk-schema.yml` — Updates SDK schema in docs +- `fix-redirected-links.yml` — Updates selected redirecting documentation links - `release.yaml` — Builds release snaps + generates CLI reference PR - `fixup.yaml` — Commit message format validation - `scanning.yml` — Security scanning -- `sphinx-python-dependency-build-checks.yml` — Ensures Sphinx venv builds -- `markdown-style-checks.yml` — Checks style, spelling, and links +- `markdown-style-checks.yml` — Markdown linting - `build-deps.yaml` — Build dependencies check -- `doc-update-sdk-schema.yml` — Updates SDK schema in docs -- `lxd-candidate-check.yml` — Checks LXD candidate channel -- `update-starter-pack.yml` — Updates documentation starter pack +- `lxd-candidate-check.yaml` — Checks LXD candidate channel +- `staging.yaml` — Rejects staged test SDKs +- `update-sphinx-stack.yaml` — Updates Sphinx Stack files and documentation dependencies +- `zizmor.yaml` — Audits GitHub Actions workflows ## Evolution Note diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index f1f35ac0c..3ef0ee264 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -23,7 +23,7 @@ * [ ] Put variable declaration and initialisation together. * [ ] Divide large expressions into digestable and self-explanatory ones. Use multiple variables if required. * [ ] Put a blank line between two logically different chunks of code. - * [ ] Follow the [style guide](https://github.com/canonical/workshop/tree/main/docs/contributing.rst#error-messages) for new error messages. + * [ ] Follow the [style guide](https://github.com/canonical/workshop/tree/main/docs/coding-style-guide.md#error-handling) for new error messages. ## Docs diff --git a/docs/.custom_wordlist.txt b/docs/.custom_wordlist.txt index cbca09707..b4c52276b 100644 --- a/docs/.custom_wordlist.txt +++ b/docs/.custom_wordlist.txt @@ -198,6 +198,7 @@ subcommand subcommands subdirectory subgraph +subshell sudo symlinked symlinks diff --git a/docs/coding-style-guide.md b/docs/coding-style-guide.md index 0756e2a65..05c1736f0 100644 --- a/docs/coding-style-guide.md +++ b/docs/coding-style-guide.md @@ -84,7 +84,7 @@ return fmt.Errorf("%s must be a map or one of the shortcuts 'true' or 'false'", return fmt.Errorf("workshop %s not found", name) ``` -**Rationale**: `%q` is backed by `strconv.Quote`, the same primitive as `strutil.Quoted`, so dynamic values render consistently across error messages, log output, and list helpers. Reserving backticks as Go raw-string delimiters and double quotes for both literals and `%q` output keeps every quoted artifact in the final message visually uniform. The `docs/contributing.rst` Error messages guidance (path and identifier double-quoting) is the precedent. +**Rationale**: `%q` is backed by `strconv.Quote`, the same primitive as `strutil.Quoted`, so dynamic values render consistently across error messages, log output, and list helpers. Reserving backticks as Go raw-string delimiters and double quotes for both literals and `%q` output keeps every quoted artifact in the final message visually uniform. The same path and identifier double-quoting applies across Workshop's error messages. --- @@ -1516,4 +1516,4 @@ When contributing code: 5. Keep changes focused and atomic 6. Write clear commit messages -For detailed contribution guidelines, see the [Contributing Guide](contributing.rst) in the documentation. +For detailed contribution guidelines, see {ref}`Contribute to development `. diff --git a/docs/contributing.rst b/docs/contributing.rst index 1936c7327..fdda6a146 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -1,13 +1,12 @@ .. _contributing: .. meta:: - :description: Guide on contributing to the Workshop project, detailing - why and how to join the community, including instructions for - code contributions, documentation improvements, releases, - and testing opportunities. + :description: Contribute to the Workshop project. View the contribution + process, standards, and the ways to get involved as a + developer or a documentation author. -How to contribute -================= +Contribute +========== We believe everyone has something valuable to contribute, whether you're a coder, a writer, or a tester. @@ -26,656 +25,50 @@ Here's how and why you could get involved: improve documentation, or be among the first testers. Your presence matters, regardless of experience or the scale of your input. -The guidelines below will keep your contributions effective and meaningful. +Standards and expectations +-------------------------- +|ws_markup| is an emergent project +stewarded by the DevEx department at Canonical. +Before you start, familiarize yourself with two documents: -Environment setup ------------------ -#. ``Workshop`` has a client-server architecture. - Its ``workshopd`` daemon exposes a RESTful API (see ``internal/daemon/api.go``) to the clients. +- The `Ubuntu Code of Conduct `__ + sets the standard for respectful collaboration across the community. - The recommended way to run the current sources is the ``try`` - dev tool wired into ``go.mod``: +- The `license `__ + governs how the project's code is used and distributed. - .. code-block:: console - go tool try +Ways to contribute +------------------ - This builds ``./cmd/...`` into a temporary session directory under - ``try_sessions/``, starts ``workshopd`` against it, and drops you - into a subshell with ``WORKSHOP``, ``WORKSHOP_CACHE``, - ``WORKSHOP_SOCKET`` and ``PATH`` pre-configured. Exit the shell to - tear the session down; pass ``--keep`` to retain the session - directory for inspection. Re-run ``go tool try`` from inside the - shell to rebuild and restart ``workshopd`` in place. +Pick the path that matches the work you want to do: - If you'd rather drive ``workshopd`` directly: +- :ref:`contributing_development` takes a code change from a local + environment through to a merged pull request. - .. code-block:: console +- :ref:`contributing_documentation` follows the same arc for changes to + this documentation. - go install ./cmd/... - export WORKSHOP=~/workshop - export WORKSHOP_CACHE=~/workshop-cache - export WORKSHOP_DEBUG=1 - workshopd run --create-dirs +- Report a bug or share feedback through the + `issue tracker `__. - The client can connect using the daemon's Unix domain socket: +Maintainers can find the release process, automation, and repository tooling +in :ref:`contributing_maintenance`. - .. code-block:: console - export WORKSHOP=~/workshop - workshop list +Feedback and issues +------------------- -#. ``Spread`` is the end-to-end testing tool for ``workshop``. - Install it from `GitHub `__: +Before opening a new issue, search the +`existing issues `__ +to avoid duplicates and to see whether the topic is already being worked on. - .. code-block:: console - git clone https://github.com/canonical/spread - cd spread - go install ./... +.. toctree:: + :hidden: - - Make sure the ``$GOPATH/bin`` directory is included in ``$PATH``. - After successful installation, you should see the help message by running: - - .. code-block:: console - - spread -h - - To run the end-to-end test suite ``tests/documentation/``, - download the latest SDKcraft release from the `repository `_ - and move it to the ``tests/`` directory. - -Coding ------- - -In Workshop, commit messages differ from conventional commits in capitalization: - -.. code-block:: none - - Ensure correct permissions and ownership for the content mounts - - * Work around an LXD issue regarding empty dirs: - https://github.com/canonical/lxd/issues/12648 - - * Ensure the source directory is owned by the user running a workshop. - - Links: - - ... - - ... - - -The messages rarely, if ever, state the type of the commit -(e.g., ``fix``, ``feat``, etc.); -these are used for branch naming, for example: - -- ``feat/workspace-start`` -- ``fix/spread-tests-github`` -- ``chore/update-lxd`` - - -Commits that focus on docs must use the ``Doc:`` type prefix -with an optional scope in square brackets: - -.. code-block:: none - - Doc[chore]: Align references - - -PR descriptions should follow the PR template checklist, -which largely reiterates this section. - - -After receiving review comments, -optimize for commit history clarity. -Address review comments with -`fixup commits `_ -and rebase using -`autosquash `_ -when reasonable. - - -Reversibility -~~~~~~~~~~~~~ - -When making decisions that might be costly to reverse, -explicitly state the rationale in the PR description. -This helps to understand the reasoning and collaborate better. - - -Coding standards -~~~~~~~~~~~~~~~~ - -- **Avoid nested conditions**: - Refrain from nesting conditions to enhance readability and maintainability. - -- **Eliminate dead code and redundant comments**: - Remove unused or obsolete code and comments. - This promotes a cleaner code base and reduces confusion. - -- **Normalize symmetries**: - Handle identical operations consistently, using a uniform approach. - This also improves consistency and readability. - - -Error handling -~~~~~~~~~~~~~~ - -When handling errors or multiple returns, -follow a consistent pattern: - -.. code-block:: go - - // one way to handle errors - if err := f(); err != nil { - ... - } - - // one way to handle multiple returns - val, err := f() - if err != nil { - ... - } - - -Error messages -~~~~~~~~~~~~~~ - -- **Be consistent**: - Try to match the style of existing error messages. - Most of these can be found by searching for ``fmt.Errorf`` and ``errors.New``. - Paths and other identifiers should be double-quoted if possible. - -- **Quote values consistently**: - Use ``%q`` for interpolated identifiers - and ``"..."`` inside backtick raw strings for literal flag and command references. - See :ref:`coding_style_guide` for details. - -- **Consider the user experience**: - Error messages should be clear and actionable. - -- **Be specific**: - For example, if a file was not found, the error message should include its path. - -- **Mind the nesting**: - Start in lowercase and avoid trailing punctuation. - Avoid excessively long or repetitive error chains. - A common template is: ``what was attempted: why it went wrong``. - - -Code structure -~~~~~~~~~~~~~~ - -- **Check coupled code elements**: - Verify that coupled code elements, files and directories are adjacent. - For instance, store test data close to the corresponding test code. - -- **Group variable declaration and initialization**: - Declare and initialize variables together - to improve code organization and readability. - -- **Divide large expressions**: - Break down large expressions - into smaller self-explanatory parts. - Use multiple variables if necessary - to make the code more understandable - and choose names to reflect their purpose. - -- **Use blank lines for logical separation**: - Insert a blank line between two logically distinct sections of code. - This improves its structure and makes it easier to comprehend. - - -Linting -------- - -Code should be formatted consistently -and avoid common pitfalls. -Contributions will be checked for some of these issues -using `golangci-lint `_. -To run these checks locally: - -.. code-block:: console - - golangci-lint run - - -Some issues can be fixed automatically: - -.. code-block:: console - - golangci-lint run --fix - - -If `pre-commit `_ is available, -``git`` can run these checks on every commit: - -.. code-block:: console - - pre-commit install - - -Testing -------- - -Make sure to run unit and integration tests before submitting a PR. -We use a ``go test``-compatible -`gocheck `_: - -.. code-block:: console - - go test ./... - go test -check.f - - -To run end-to-end tests and integration tests with -`Spread `__: - -.. code-block:: console - - spread tests/ - - -To check code coverage: - -.. code-block:: console - - go test -coverpkg=<./...|package> -covermode= -coverprofile= <./...|package> - - -For example, to measure coverage using all tests: - -.. code-block:: console - - go test -covermode=count -coverpkg=./... -coverprofile=cover.out ./... - -To generate an HTML representation: - -.. code-block:: console - - go tool cover -html= -o - - -For example: - -.. code-block:: console - - go tool cover -html=cover.out -o cover.html - - -The output flag can be omitted to open in the default browser: - -.. code-block:: console - - go tool cover -html=cover.out - - -The above will work for unit and integration tests instrumented directly with -`go test`. Integration tests run using `spread` will create the coverprofile -automatically, however the artifacts will need to be collected from the VM. -This can be accomplished by using the `-artifacts` flag when running `spread`. - -.. code-block:: console - - spread -artifacts= tests/integration/ - - -Releases --------- - -See the :ref:`release notes ` -for more information on our general approach. -The steps to produce a Workshop release are as follows. - - -Build the snaps locally -~~~~~~~~~~~~~~~~~~~~~~~ - -`Snapcraft `_ -is used to build, package, and publish ``workshop`` snaps. -All these processes run in a self-launched -`LXD `_ container. -To be able to run the build, install ``snapcraft`` and ``lxd`` using ``snap``: - -.. code-block:: console - - sudo snap install --classic snapcraft - sudo snap install --channel=6/stable lxd - - -Add the current user to the ``lxd`` group -to give permission to access its resources: - -.. code-block:: console - - sudo usermod -a -G lxd $USER - - -Log out and reopen your user session for the new group to become active, -then initialize LXD: - -.. code-block:: console - - lxd init - - -Publish the release -~~~~~~~~~~~~~~~~~~~ - -Here's the publishing checklist to follow: - -- Merge and close the outstanding pull requests from the release scope - -- Make sure the unit, integration, and documentation tests are green; - see `Testing`_ for details - -- Update the documentation; - see the `Release documentation`_ section for the full checklist - -- Create and push a new release tag with ``git``, - using `semantic versioning `_ - -- Run the `release workflow - `_ - on GitHub; - this builds the release snaps for the supported architectures - to be published on GitHub - and adds a pull request to update the - :ref:`CLI reference ` - -- Generate the - `change log `_ - on GitHub - - -.. _contributing_copilot: - -Copilot configuration ---------------------- - -The repository includes configurations -to help GitHub Copilot provide assistance; -these are located in the ``.github/`` directory -and include general instructions -as well as customized agent prompts for specific tasks. - - -Copilot instructions -~~~~~~~~~~~~~~~~~~~~ - -The ``.github/copilot-instructions.md`` file -provides general project context to GitHub Copilot. - -Also, there are documentation- and code-specific instructions -in ``.github/docs.instructions.md`` and ``.github/go.instructions.md``, -tailored to guide Copilot when assisting with documentation and Go code tasks, -respectively. - - -Custom agents -~~~~~~~~~~~~~ - -The ``.github/agents/`` subdirectory contains -`custom agent prompts -`__ -for specific review and maintenance tasks: - -- ``code-review.agent.md``: - A code review specialist that enforces commit message standards, - coding conventions, and error handling patterns, - referencing this contribution guide - and the :ref:`coding style guide `. - -- ``doc-review.agent.md``: - A technical documentation reviewer - that performs a multistage review process - including build validation, content analysis, and style checking, - referencing this contribution guide - and the :ref:`documentation style guide `. - -- ``doc-schema-update.agent.md``: - A specialized agent for reconciling - the JSON schema in ``docs/reference/definition-files/schema.json`` - with the validation logic in ``internal/workshop/workshop_file.go``. - - -These agents provide structured, actionable feedback -and help maintain consistency across contributions. - - -.. _contributing_doc: - -Documentation -------------- - -All documentation resides in the ``docs/`` directory. -To build and run it at ``127.0.0.1:8000``: - -.. code-block:: console - - workshop launch - workshop run docs-run - - -To suggest changes, -submit a `pull request `_, -limiting it to the ``docs/`` directory -and prefixing the title with ``Doc:``. - - -.. _contributing_doc_structure: - -Structure and style -~~~~~~~~~~~~~~~~~~~ - -We use the `Canonical documentation starter pack -`_ -together with a custom Workshop in-project SDK in ``.workshop/`` -to run and build our documentation; -our preferred markup is reStructuredText (reST), -with some opinionated style choices evident in the source. - -See the relevant documentation before making changes: - -- :doc:`Workshop documentation style guide ` - (project-specific conventions and patterns) - -- `Starter pack - `_ - -- `reST style guide - `_ - -- `reST cheat sheet - `_ - - -.. _contributing_doc_dependencies: - -Dependency management -~~~~~~~~~~~~~~~~~~~~~ - -The documentation build requires Python 3.11 or later. - -Documentation dependencies are managed using ``uv``: - -- ``docs/requirements.in`` contains dependencies specific to Workshop docs -- ``docs/requirements.txt`` is the final, resolved dependency file - - -The final file is generated by the ``update-starter-pack`` workflow, -listed in :ref:`contributing_cicd`. - - -.. _contributing_doc_generation: - -CLI reference -~~~~~~~~~~~~~ - -The :ref:`command-line reference ` for Workshop -is produced directly from the Cobra command tree: - -.. code-block:: console - - go run ./cmd/workshop generate-docs - - -The helper in ``cmd/workshop/gendocs.go`` -uses the `Gencodo `_ Go module -to convert the command metadata into ``.rst`` files with clever templates. - -In particular, this is used during the -:ref:`release workflow `. - ---- - -The :ref:`command-line reference ` for SDKcraft -can be generated in the SDKcraft repository; -run ``gendocs.py`` there to generate the files. -Current implementation relies on -`craft-application `__ -and doesn't fully integrate with Workshop documentation yet. - - -.. _contributing_doc_release: - -Release documentation -~~~~~~~~~~~~~~~~~~~~~ - -At every release, remember to: - -- Merge the auto-generated CLI reference pull request. - -- Bump the snap revision used across the docs. - -- Refresh the three schema files under ``docs/reference/definition-files/``. - - Regenerate ``schema-sdk.json`` and ``schema-sdkcraft.json`` - in a local SDKcraft repository checkout and copy the outputs over: - - .. code-block:: console - - $ cd - $ uv run python sdkcraft/models/metadata.py - $ uv run python sdkcraft/models/project.py - $ cp schema-sdk.json schema-sdkcraft.json \ - /docs/reference/definition-files/ - - The workshop ``schema.json`` is hand-audited against - ``internal/workshop/workshop_file.go``. - - -- Update the `release notes `_ - with relevant details, following the established format; - for an SDKcraft release, update the respective section in the same manner. - -- Copy the release notes to the documentation under ``docs/release-notes/`` - and update the latest version in ``docs/release-notes/index.rst``; - the recent version lists should contain versions from the last 6 months. - -- Refresh the - `coverage map `_ - by running the ``.github/workflows/doc-cover.yaml`` workflow - and merging the resulting pull request. - -- Copy the auto-generated SDKcraft CLI reference - from the `SDKcraft repository `__ - to ``docs/reference/cli/sdkcraft/``, - making sure the updated documentation builds properly. - - -.. _contributing_cicd: - -CI/CD ------ - -Multiple -`GitHub Actions -`_ -workflows, -defined in the ``.github/workflows/`` directory, -automate testing, building, documentation, and release processes. - -Some of these workflows come from the -:ref:`starter pack ` (marked SP), -while others are custom-made for Workshop's needs. - - -Documentation workflows: - -.. list-table:: - :header-rows: 1 - :widths: 60 40 - - * - Workflow - - Purpose - - * - ``automatic-doc-checks.yml`` (SP) - - Build the documentation and fail on Sphinx warnings. - - * - ``doc-cover.yaml`` - - Generate and update the documentation coverage map. - - * - ``doc-update-sdk-schema.yml`` - - Update SDK schema files from the SDKcraft repository. - - * - ``markdown-style-checks.yml`` (SP) - - Check style, spelling, and links in Markdown documentation files. - - * - ``sphinx-python-dependency-build-checks.yml`` (SP) - - Ensure the Sphinx virtual environment can be built from source. - - * - ``update-starter-pack.yaml`` - - Update documentation starter pack files weekly and on demand. - - -Code quality and testing workflows: - -.. list-table:: - :header-rows: 1 - :widths: 60 40 - - * - Workflow - - Purpose - - * - ``cover.yaml`` - - Orchestrates ``spread.yaml`` and ``unit-tests.yaml``; - aggregates coverage reports. - - * - ``fixup.yaml`` - - Check for fixup and squash commits in pull requests. - - * - ``lint.yaml`` - - Run ``golangci-lint`` on Go code. - - * - ``scanning.yml`` - - Scan for known security vulnerabilities using Trivy. - - * - ``spread.yaml`` - - Run end-to-end tests with Spread (reusable workflow). - - * - ``unit-tests.yaml`` - - Run Go unit tests and check for race conditions (reusable workflow). - - -Build and release workflows: - -.. list-table:: - :header-rows: 1 - :widths: 60 40 - - * - Workflow - - Purpose - - * - ``build-deps.yaml`` - - Build and cache Workshop snap (reusable workflow). - - * - ``lxd-candidate-check.yaml`` - - Test Workshop against LXD candidate channel daily; - uses ``build-deps.yaml``. - - * - ``release.yaml`` - - Build release snaps for ARM64 and X64; - create GitHub release and trigger CLI docs update PR. + Development + Documentation + Maintenance diff --git a/docs/contributing/development.rst b/docs/contributing/development.rst new file mode 100644 index 000000000..8dbde92a6 --- /dev/null +++ b/docs/contributing/development.rst @@ -0,0 +1,420 @@ +:relatedlinks: [Spread](https://github.com/canonical/spread), [golangci-lint](https://golangci-lint.run/), [gocheck](https://pkg.go.dev/gopkg.in/check.v1#section-readme) + +.. _contributing_development: + +.. meta:: + :description: Make a code change to Workshop. Set up, develop, test, and + review your change within the project's standard workflow. + +Contribute to development +========================= + +A code change to |ws_markup| moves from a local development environment, +through testing and review, to a merged pull request. + + +Set up your work environment +---------------------------- + +|ws_markup| has a client-server architecture. +Its :program:`workshopd` daemon exposes a RESTful API +(see :file:`internal/daemon/api.go`) +to the clients. + +|ws_markup| also develops itself in a workshop. +The repository is a :ref:`project ` +whose :file:`.workshop/dev.yaml` definition +describes a workshop named :samp:`dev`. +It carries the Go toolchain and the linters, +pinned to the versions the project checks against, +and packages them as :ref:`actions `. + +Your work is split across two environments: + +.. list-table:: + :header-rows: 1 + :widths: 25 75 + + * - Environment + - What runs there + + * - The :samp:`dev` workshop + - Go builds, :program:`golangci-lint`, :program:`shellcheck`, + unit tests and coverage, + and the documentation build, preview, and checks. + + * - The host + - :program:`workshopd`, the :program:`spread` suites, + and the LXD integration tests. + +:program:`workshopd` connects to LXD +and expects the ZFS storage driver, +neither of which the :samp:`dev` workshop ships, +so the host-side commands run outside it. + + +.. _contributing_dev_workshop: + +Launch the dev workshop +~~~~~~~~~~~~~~~~~~~~~~~ + +Install |ws_markup| and LXD first +(see :ref:`tut_install`), +then launch the workshop from the repository root: + +.. code-block:: console + + $ workshop launch dev + +The definition pins the toolchain +to the versions the project checks against: + +- The :samp:`go` SDK tracks :samp:`1.26/stable`, + matching the :samp:`go` directive in :file:`go.mod`. + +- :program:`golangci-lint` is pinned to v2.11.3, + matching the :samp:`rev` in :file:`.pre-commit-config.yaml`; + the linting workflow in :file:`.github/workflows/lint.yaml` + tracks the same v2.11 minor version. + +Linting in the workshop therefore uses the same version +as the linting workflow, +without installing the linters on your host. + +The tooling comes from an :ref:`in-project SDK ` +in :file:`.workshop/tools/`, +which the definition lists as :samp:`project-tools`; +the :samp:`project-` prefix selects the in-project source +(see :ref:`ref_workshop_definition_sdk_entry`). +Its :ref:`hooks ` install :program:`make`, +:program:`shellcheck`, :program:`golangci-lint`, and snapd-testing-tools, +and report the workshop unhealthy +when :program:`golangci-lint` is missing +(see :ref:`exp_workshopctl_health`). +The SDK also slots a :ref:`tunnel ` +that the :ref:`system SDK ` plugs +to publish the documentation preview +on the host at :samp:`127.0.0.1:8000` +(see :ref:`how_forward_ports`). + +List the available actions and run one: + +.. code-block:: console + + $ workshop actions dev + $ workshop run dev lint + +Because :samp:`dev` is the only definition in :file:`.workshop/`, +you can omit its name. +See :ref:`ref_workshop_actions` and :ref:`ref_workshop_run`. + +Open an interactive shell with :ref:`workshop shell `, +run a single command with :ref:`workshop exec `, +and apply edits to :file:`.workshop/dev.yaml` +or to the SDK in :file:`.workshop/tools/` +with :ref:`workshop refresh `. + + +Run the daemon on the host +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The recommended way to run the current sources +is the :command:`go tool try` development tool +wired into :file:`go.mod`: + +.. code-block:: console + + $ go tool try + +This builds :file:`./cmd/...` +into a temporary session directory under :file:`try_sessions/`, +starts :program:`workshopd` against it, +and drops you into a subshell +with :envvar:`WORKSHOP`, :envvar:`WORKSHOP_CACHE`, +:envvar:`WORKSHOP_SOCKET`, and :envvar:`PATH` pre-configured. +Exit the shell to tear the session down. +Pass :option:`!--keep` to retain the session directory for inspection. +Run :command:`go tool try` again from inside the shell +to rebuild and restart :program:`workshopd` in place. + +To run :program:`workshopd` directly: + +.. code-block:: console + + $ go install ./cmd/... + $ export WORKSHOP=~/workshop + $ export WORKSHOP_CACHE=~/workshop-cache + $ export WORKSHOP_DEBUG=1 + $ workshopd run --create-dirs + +The client can connect using the daemon's Unix domain socket: + +.. code-block:: console + + $ export WORKSHOP=~/workshop + $ workshop list + + +Install Spread +~~~~~~~~~~~~~~ + +`Spread `__ is the end-to-end testing tool +for |ws_markup|. +It launches its own LXD containers, +so install and run it on the host: + +.. code-block:: console + + $ git clone https://github.com/canonical/spread + $ cd spread + $ go install ./... + +Make sure the :file:`$GOPATH/bin/` directory +is included in :envvar:`PATH`. +After successful installation, you should see the help message by running: + +.. code-block:: console + + $ spread -h + +Run the documentation end-to-end test suites with: + +.. code-block:: console + + $ spread tests/docs-tutorial/ + $ spread tests/docs-how-to/ + + + +Choose a task +------------- + +Work is tracked in the project's +`issue tracker `__. +Browse the open issues and comment on one to signal that you're taking it on. + +For a small, self-contained fix, you can open a pull request directly. +For a larger or more involved change, open an issue first +to agree on the approach with the maintainers +before you invest time in the implementation. + + +Draft your work +--------------- + +Create a branch +~~~~~~~~~~~~~~~ + +Name your branch after the type of change and a short description. +|ws_markup| uses the commit type as a branch prefix, for example: + +- :samp:`feat/workspace-start` +- :samp:`fix/spread-tests-github` +- :samp:`chore/update-lxd` + + +Develop +~~~~~~~ + +Keep each change focused and reversible. +When a decision might be costly to reverse, +state the rationale in the pull request description +so reviewers can follow the reasoning and collaborate on it. + +|ws_markup| follows a set of Go conventions for naming, error handling, +error messages, and code structure. +See the :ref:`coding_style_guide` for the full set of patterns and their rationale. + + +Test +~~~~ + +Run the checks before submitting a pull request. +The :samp:`dev` workshop runs them +with the tool versions the project pins +(see :ref:`contributing_dev_workshop`); +each check also has a host-native equivalent +if you have the tools installed. + +|ws_markup| tests use +`gocheck `_, +which integrates with :command:`go test`. +Run the unit tests with coverage: + +.. code-block:: console + + $ workshop run dev cover + +Or on the host: + +.. code-block:: console + + $ go test ./... + $ go test -covermode=count -coverpkg=./... -coverprofile=coverage.out ./... + +To run a single test or suite, name the package first: + +.. code-block:: console + + $ workshop exec dev -- go test -check.f + +To control the coverage scope and mode: + +.. code-block:: console + + $ workshop exec dev -- go test -coverpkg=<./...|PACKAGE> \ + -covermode= \ + -coverprofile= <./...|PACKAGE> + +The :samp:`cover` action writes its profile to :file:`coverage.out`. +Because the project directory is mounted into the workshop at :file:`/project/`, +you can render the profile on the host: + +.. code-block:: console + + $ go tool cover -html= -o + +The output flag can be omitted to open in the default browser: + +.. code-block:: console + + $ go tool cover -html=coverage.out + +Formatting and common pitfalls are checked with +`golangci-lint `_. +Lint the sources in both the full and the incremental configuration: + +.. code-block:: console + + $ workshop run dev lint + +Or on the host: + +.. code-block:: console + + $ golangci-lint run + $ golangci-lint run --new-from-rev='HEAD~' --config=.golangci.incremental.yaml + +Some issues can be fixed automatically: + +.. code-block:: console + + $ workshop exec dev -- golangci-lint run --fix + +Or on the host: + +.. code-block:: console + + $ golangci-lint run --fix + +Check the shell scripts and the :program:`spread` task definitions: + +.. code-block:: console + + $ workshop run dev shellcheck + +If `pre-commit `_ is available, +:program:`git` can run the linters on every commit +using the same pinned :program:`golangci-lint`: + +.. code-block:: console + + $ pre-commit install + +The LXD integration tests sit behind a build tag +and drive LXD directly, so run them on the host: + +.. code-block:: console + + $ go test -tags=integration ./internal/workshop/lxd/tests/integration/ + +Run the end-to-end suites with +`Spread `__, also on the host: + +.. code-block:: console + + $ spread tests/ + +Integration tests run through :program:`spread` +create the coverage profile automatically, +but the artifacts need to be collected from the VM +with the :option:`!-artifacts` flag: + +.. code-block:: console + + $ spread -artifacts= tests/integration/ + + +Document your work +~~~~~~~~~~~~~~~~~~ + +Update the documentation to match your change: +new behavior, changed flags, or removed features all belong in the docs. +See :ref:`contributing_documentation` for how to write, build, and test them. + + +Commit +~~~~~~ + +|ws_markup| commit messages differ +from conventional commits in capitalization: + +.. code-block:: none + + Ensure correct permissions and ownership for the content mounts + + * Work around an LXD issue regarding empty dirs: + https://github.com/canonical/lxd/issues/12648 + + * Ensure the source directory is owned by the user running a workshop. + + Links: + - ... + - ... + +The messages rarely, if ever, state the type of the commit +(:samp:`fix`, :samp:`feat`, and so on); +these are used for branch naming instead. + + +Review with the team +-------------------- + +Send for review +~~~~~~~~~~~~~~~ + +Open a `pull request `_ +against the repository. +Fill in the pull request template checklist, +which largely reiterates the expectations covered here. + + +Address quality concerns +~~~~~~~~~~~~~~~~~~~~~~~~ + +Your pull request runs a set of automatic checks for linting, unit tests, +end-to-end tests, and security scanning. +For the full catalog of workflows, see :ref:`contributing_cicd`. + +After receiving review comments, optimize for commit history clarity. +Address them with +`fixup commits `_ +and rebase using +`autosquash `_ +when reasonable. + + +Wrap up the review +~~~~~~~~~~~~~~~~~~ + +Once the checks pass and a maintainer approves the change, +it's merged into the target branch. +Keep an eye on the pull request in case follow-up questions come up. + + +Get help and support +-------------------- + +If you get stuck, ask on the issue you're working on, +or open a new one in the +`issue tracker `__. diff --git a/docs/contributing/documentation.rst b/docs/contributing/documentation.rst new file mode 100644 index 000000000..0b2997cc2 --- /dev/null +++ b/docs/contributing/documentation.rst @@ -0,0 +1,174 @@ +:relatedlinks: [Diátaxis](https://diataxis.fr/), [Documentation starter pack](https://documentation.ubuntu.com/sphinx-stack/latest/), [reST style guide](https://documentation.ubuntu.com/sphinx-stack/latest/reference/style-guide/) + +.. _contributing_documentation: +.. _contributing_doc: + +.. meta:: + :description: Make a documentation change to Workshop. Set up, write, build, + and review documentation within the project's standard workflow. + +Contribute to this documentation +================================ + +|ws_markup|'s documentation lives in the :file:`docs/` directory. +A documentation change follows the same arc as a code change, +from a local preview through to a merged pull request. + + +Set up your work environment +---------------------------- + +All documentation resides in the :file:`docs/` directory. +To build and serve it at :samp:`127.0.0.1:8000`: + +.. code-block:: console + + $ workshop launch dev + $ workshop run dev docs-run + +The workshop is the same one code contributions use; +see :ref:`contributing_dev_workshop`. + + +.. _contributing_doc_dependencies: + +Dependencies +~~~~~~~~~~~~ + +The documentation build requires Python 3.11 or later. + +Documentation dependencies are managed using :program:`uv`: + +- :file:`docs/requirements.in` + contains dependencies specific to |ws_markup| documentation. + +- :file:`docs/requirements.txt` + is the final, resolved dependency file. + +The :file:`.github/workflows/update-sphinx-stack.yaml` workflow +generates the final file. +For more information about the workflow, +see :ref:`contributing_cicd`. + + +Choose a task +------------- + +Trivial fixes such as spelling, grammar, and punctuation need no planning: +open a pull request directly. + +For a larger change, such as restructuring a section or a bulk edit, +open an issue in the +`issue tracker `__ first +to agree on the approach. + + +Draft your work +--------------- + +Create a branch +~~~~~~~~~~~~~~~ + +Name your branch after the change, +following the same prefix convention as code contributions +(see :ref:`contributing_development`). +Documentation branches commonly use a :samp:`docs/` prefix, +for example :samp:`docs/contributing`. + + +.. _contributing_doc_structure: + +Write +~~~~~ + +|ws_markup| uses the `Canonical documentation starter pack +`_ +together with a custom |ws_markup| in-project SDK in :file:`.workshop/` +to run and build its documentation; +the preferred markup is reStructuredText (reST), +with some opinionated style choices evident in the source. + +See the relevant references before making changes: + +- :ref:`doc_style_guide` + (project-specific conventions and patterns) + +- `Starter pack + `_ + +- `reST style guide + `_ + +- `reST cheat sheet + `_ + +The :ref:`command-line reference ` pages under +:file:`docs/reference/cli/` +are generated from the source, not edited by hand. +See :ref:`contributing_doc_generation` for how they're produced. + + +Test +~~~~ + +Build the documentation +and open the local preview at :samp:`127.0.0.1:8000`. +Check that your changes render as expected, +including tables, admonitions, and cross-references. + +Run the remaining documentation checks, +which cover Markdown style, spelling, inclusive language, and links: + +.. code-block:: console + + $ workshop run dev docs-check + +For the workflows that run the same checks on your pull request, +see :ref:`contributing_cicd`. + + +Commit +~~~~~~ + +Prefix documentation commits with the :samp:`Doc:` type +and an optional scope in square brackets: + +.. code-block:: none + + Doc[chore]: Align references + + +Review with the team +-------------------- + +Send for review +~~~~~~~~~~~~~~~ + +Submit a `pull request `_, +limiting it to documentation-related files +and prefixing the title with :samp:`Doc:`. + + +Address quality concerns +~~~~~~~~~~~~~~~~~~~~~~~~ + +Your pull request runs the documentation checks: +a Sphinx build that fails on warnings, plus style, spelling, and link checks. +For the full catalog, see :ref:`contributing_cicd`. +Address any failures and push follow-up commits until the checks pass. + + +Wrap up the review +~~~~~~~~~~~~~~~~~~ + +Once the checks pass and a maintainer approves the change, +it's merged and published with the next documentation build. + + +Get help and support +-------------------- + +For documentation questions, open an issue in the +`issue tracker `__, +or reach the wider documentation community in the +`Ubuntu documentation Matrix channel `__. diff --git a/docs/contributing/maintenance.rst b/docs/contributing/maintenance.rst new file mode 100644 index 000000000..da38690b8 --- /dev/null +++ b/docs/contributing/maintenance.rst @@ -0,0 +1,315 @@ +.. _contributing_maintenance: + +.. meta:: + :description: Maintainer guide for Workshop, combining release procedures + with reference information about documentation, continuous + integration, and repository tooling. + +Maintain the project +==================== + +This maintainer guide combines +task-oriented release and documentation procedures +with reference information about automation and repository tooling. +Use it for work that sits outside the day-to-day contribution flow. + + +Releases +-------- + +See the :ref:`release notes ` +for more information on the general approach. +The steps to produce a |ws_markup| release are as follows. + + +Build the snaps locally +~~~~~~~~~~~~~~~~~~~~~~~ + +`Snapcraft `_ +is used to build, package, and publish :program:`workshop` snaps. +All these processes run in a self-launched +`LXD `_ container. +To run the build, +install :program:`snapcraft` and :program:`lxd` using :program:`snap`: + +.. code-block:: console + + $ sudo snap install --classic snapcraft + $ sudo snap install --channel=6/stable lxd + +Add the current user to the :samp:`lxd` group +to give permission to access its resources: + +.. code-block:: console + + $ sudo usermod -a -G lxd $USER + +Log out and reopen your user session for the new group to become active, +then initialize LXD: + +.. code-block:: console + + $ lxd init + + +Publish the release +~~~~~~~~~~~~~~~~~~~ + +Here's the publishing checklist to follow: + +- Merge and close the outstanding pull requests from the release scope + +- Make sure the unit, integration, and documentation tests are green; + see :ref:`contributing_development` and :ref:`contributing_documentation` for details + +- Update the documentation; + see :ref:`contributing_doc_release` for the full checklist + +- Create and push a new release tag with :program:`git`, + using `semantic versioning `_ + +- Run the `release workflow + `_ + on GitHub; + this builds and publishes release snaps + for the supported architectures, + creates a GitHub release, + and adds a pull request to update the + :ref:`CLI reference ` + +- Generate the + `change log `_ + on GitHub + + +.. _contributing_doc_release: + +Release documentation +--------------------- + +At every release, remember to: + +- Merge the auto-generated CLI reference pull request. + +- Bump the snap revision used across the docs. + +- Refresh the three schema files + under :file:`docs/reference/definition-files/`. + + Regenerate :file:`schema-sdk.json` and :file:`schema-sdkcraft.json` + in a local |sdk_markup| repository checkout + and copy the outputs over: + + .. code-block:: console + + $ cd + $ uv run python sdkcraft/models/metadata.py + $ uv run python sdkcraft/models/project.py + $ cp schema-sdk.json schema-sdkcraft.json \ + /docs/reference/definition-files/ + + The |ws_markup| :file:`schema.json` is hand-audited + against :file:`internal/workshop/workshop_file.go`. + +- Update the `release notes `_ + with relevant details, following the established format; + for an |sdk_markup| release, + update the respective section in the same manner. + +- Copy the release notes + to the documentation under :file:`docs/release-notes/` + and update the latest version in :file:`docs/release-notes/index.rst`; + the recent version lists should contain versions from the last 6 months. + +- Refresh the + `coverage map `_ + by running the :file:`.github/workflows/doc-cover.yaml` workflow + and merging the resulting pull request. + +- Copy the auto-generated |sdk_markup| CLI reference + from the `SDKcraft repository `__ + to :file:`docs/reference/cli/` as :file:`sdkcraft*.rst`, + making sure the updated documentation builds properly. + + +.. _contributing_doc_generation: + +CLI reference generation +------------------------ + +The :ref:`command-line reference ` for |ws_markup| +is produced directly from the Cobra command tree: + +.. code-block:: console + + $ go run ./cmd/workshop generate-docs + +The helper in :file:`cmd/workshop/gendocs.go` +uses the `Gencodo `_ Go module +to convert the command metadata into :file:`*.rst` files with templates. +In particular, this is used during the +:ref:`release workflow `. + +The :ref:`command-line reference ` for |sdk_markup| +can be generated in the |sdk_markup| repository. +Run :file:`gendocs.py` there to generate the files. +The current implementation relies on +`craft-application `__ +and doesn't fully integrate with |ws_markup| documentation yet. + + +.. _contributing_cicd: + +CI/CD +----- + +Multiple +`GitHub Actions +`_ +workflows, +defined in the :file:`.github/workflows/` directory, +automate testing, building, documentation, and release processes. + +Some of these workflows come from the +:ref:`starter pack ` (marked SP), +while others are custom-made for |ws_markup|'s needs. + +Documentation workflows: + +.. list-table:: + :header-rows: 1 + :widths: 60 40 + + * - Workflow + - Purpose + + * - :file:`automatic-doc-checks.yml` (SP) + - Build the documentation and fail on Sphinx warnings. + + * - :file:`doc-cover.yaml` + - Generate and update the documentation coverage map. + + * - :file:`doc-update-sdk-schema.yml` + - Update SDK schema files from the |sdk_markup| repository. + + * - :file:`fix-redirected-links.yml` + - Update selected redirecting documentation links and open a pull request. + + * - :file:`markdown-style-checks.yml` (SP) + - Lint Markdown documentation files. + + * - :file:`update-sphinx-stack.yaml` + - Update Sphinx Stack files and documentation dependencies weekly + and on demand. + + +Code quality and testing workflows: + +.. list-table:: + :header-rows: 1 + :widths: 60 40 + + * - Workflow + - Purpose + + * - :file:`cover.yaml` + - Orchestrates :file:`spread.yaml` and :file:`unit-tests.yaml`; + aggregates coverage reports. + + * - :file:`fixup.yaml` + - Check for fixup and squash commits in pull requests. + + * - :file:`lint.yaml` + - Run :program:`golangci-lint` on Go code. + + * - :file:`scanning.yml` + - Scan for known security vulnerabilities using Trivy. + + * - :file:`spread.yaml` + - Run end-to-end tests with Spread (reusable workflow). + + * - :file:`staging.yaml` + - Prevent staged test SDKs from being merged. + + * - :file:`unit-tests.yaml` + - Run Go unit tests and check for race conditions (reusable workflow). + + * - :file:`zizmor.yaml` + - Audit GitHub Actions workflows for security issues. + + +Build and release workflows: + +.. list-table:: + :header-rows: 1 + :widths: 60 40 + + * - Workflow + - Purpose + + * - :file:`build-deps.yaml` + - Build and cache the |ws_markup| snap (reusable workflow). + + * - :file:`lxd-candidate-check.yaml` + - Test |ws_markup| against the LXD candidate channel daily; + uses :file:`build-deps.yaml`. + + * - :file:`release.yaml` + - Build release snaps for ARM64 and X64; + create GitHub release and trigger CLI docs update PR. + + +.. _contributing_copilot: + +Copilot configuration +--------------------- + +The repository includes configurations +to help GitHub Copilot provide assistance; +these are located in the :file:`.github/` directory +and include general instructions +as well as custom agents and reusable skills for specific tasks. + + +Copilot instructions +~~~~~~~~~~~~~~~~~~~~ + +The :file:`.github/copilot-instructions.md` file +provides general project context to GitHub Copilot. + +Also, there are documentation- and code-specific instructions +in :file:`.github/docs.instructions.md` +and :file:`.github/go.instructions.md`, +tailored to guide Copilot when assisting with documentation and Go code tasks, +respectively. + + +Agents and skills +~~~~~~~~~~~~~~~~~ + +The :file:`.github/agents/` subdirectory contains +`custom agent prompts +`__ +for review and maintenance tasks: + +- :file:`code-review.agent.md`: + A code review specialist that enforces commit message standards, + coding conventions, and error handling patterns, + referencing the :ref:`development contribution guide ` + and the :ref:`coding style guide `. + +- :file:`doc-schema-update.agent.md`: + A specialized agent for reconciling + the JSON schema in :file:`docs/reference/definition-files/schema.json` + with the validation logic + in :file:`internal/workshop/workshop_file.go`. + +The :file:`.github/skills/` subdirectory contains reusable skills. +The :file:`.github/skills/documentation-review/SKILL.md` skill +orchestrates build validation, +content analysis, accuracy verification, structure checks, and style review +using the :ref:`documentation contribution guide ` +and the :ref:`documentation style guide `. + +These agents and skills provide structured, actionable feedback +and help maintain consistency across contributions. diff --git a/docs/index.rst b/docs/index.rst index 2ba8ba07f..60058f5f9 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -18,9 +18,14 @@ how-to/index reference/index explanation/index + +.. toctree:: + :hidden: + Release notes + Contribute Security - Contribution + **Workshops are secure, fast, and composable development environments @@ -196,7 +201,9 @@ and implemented with .. rubric:: Get involved -- :ref:`Contribution and participation ` +- :ref:`Contribute ` +- :ref:`Contribute to development ` +- :ref:`Contribute to this documentation ` .. rubric:: Releases and roadmap