.. _JOBTMPL/PublishReleaseNotes: PublishReleaseNotes ################### This template creates a GitHub Release Page and uploads assets to that page. .. topic:: Features * Assembly a release description from various sources: * Description file in the repository. * Description via job template parameter. * Description from associated pull-request. * Download artifact and upload selected files as assets to the release page. * Add an inventory file in JSON format as asset to each release. * Replace placeholders with variable contents. * Override the release's title. * Create draft releases. * Create pre-release release. * Create nightly/rolling releases. .. topic:: Behavior 1. Checkout repository. 2. Install dependencies. 3. Check if it's a full release or nightly release (rolling release). 4. Delete old release. 5. Assemble release notes. 6. Create a new or recreate the release page as draft. 7. Attach files from artifacts as assets: 1. Download artifact 2. Optionally, create compressed archives of that content. 3. Upload assets to release page. 8. Remove draft state from new release page. .. topic:: Job Execution .. image:: ../../_static/pyTooling-Actions-PublishReleaseNotes.png :width: 600px .. topic:: Dependencies * :gh:`actions/checkout` * ``gh`` (GitHub command line interface) * ``jq`` (JSON processing) * apt * zstd .. _JOBTMPL/PublishReleaseNotes/Instantiation: Instantiation ************* .. code-block:: yaml jobs: Prepare: uses: pyTooling/Actions/.github/workflows/PrepareJob.yml@r5 Release: uses: pyTooling/Actions/.github/workflows/PublishReleaseNotes.yml@r5 needs: - Prepare if: needs.Prepare.outputs.is_release_tag == 'true' permissions: contents: write actions: write with: tag: ${{ needs.Prepare.outputs.version }} secrets: inherit .. _JOBTMPL/PublishReleaseNotes/ReleaseNotes: Release Notes ************* Providing a release description (a.k.a release page content) can be achieved from various sources. These sources can also be combined to a single description. Moreover, the resulting description can contain placeholders which can be replaced by values provided via parameter :ref:`JOBTMPL/PublishReleaseNotes/Input/replacements`. Description text from file in the repository The job template's parameter :ref:`JOBTMPL/PublishReleaseNotes/Input/description_file` provides a way to read a predefined content from a file within the repository. This allows sharing the same text between nightly releases and full releases. .. note:: This file can't be computed/modified at pipeline runtime, because a fixed Git commit is checked out for this job template run. Descriptions text from pipeline parameter The job template's parameter :ref:`JOBTMPL/PublishReleaseNotes/Input/description` provides a way to either hard code a release description in YAML code, or connect a GitHub Action variable ``${{ ... }}`` to that parameter. The content is available in replacement variable ``%%DESCRIPTION%%``. Description text from associated PullRequest If an associated pull-request can be identified for a merge-commit, the pull-requests description can be used as a release description. The content is available in replacement variable ``%%PULLREQUEST%%``. Additional text from :ref:`JOBTMPL/PublishReleaseNotes/Input/description_footer` Additionally, a footer text is provided. The content is available in replacement variable ``%%FOOTER%%``. .. topic:: Order of Processing 1. If :ref:`JOBTMPL/PublishReleaseNotes/Input/description_file` exists and is not empty, it will serve as the main description. If the description contains ``%%...%%`` placeholders, these placeholders will be replaced accordingly. If description contains ``%...%`` placeholders, replacement rules provided by :ref:`JOBTMPL/PublishReleaseNotes/Input/replacements` will be applied. 2. If :ref:`JOBTMPL/PublishReleaseNotes/Input/description` is not empty, it will serve as the main description. If the description contains ``%%...%%`` placeholders, these placeholders will be replaced accordingly. If description contains ``%...%`` placeholders, replacement rules provided by :ref:`JOBTMPL/PublishReleaseNotes/Input/replacements` will be applied. 3. If the associated pull-request exists and is not empty, it's description will serve as the main description. If the description contains ``%%...%%`` placeholders, these placeholders will be replaced accordingly. If description contains ``%...%`` placeholders, replacement rules provided by :ref:`JOBTMPL/PublishReleaseNotes/Input/replacements` will be applied. 4. Otherwise, an error is raised. .. topic:: Replacements ``%%DESCRIPTION%%`` Replaces the placeholder with the content from :ref:`JOBTMPL/PublishReleaseNotes/Input/description`. ``%%PULLREQUEST%%``, ``%%PULLREQUEST+0%%``, ``%%PULLREQUEST+1%%``, ``%%PULLREQUEST+2%%``, ``%%PULLREQUEST+3%%`` Replaces the content by the associated pull-requests description text. If an indentation level +N (``+1``, ``+2``, ``+3``) is specified, headlines in the pull-request description will be moved by N levels down. ``%%FOOTER%%`` Replaces the placeholder with the content from :ref:`JOBTMPL/PublishReleaseNotes/Input/description_footer`. ``%%gh_server%%`` Replaced by the GitHub server URL. |br| The value is derived from ``${{ github.server_url }}``. ``%%gh_workflow_name%%`` Replaced by the workflow name. |br| The value is derived from ``${{ github.workflow }}``. ``%%gh_owner%%`` Replaced by the repository owner, which is either the name of a GitHub organisation or a GitHub user account. |br| The value is derived from ``${{ github.repository_owner }}``. ``%%gh_repo%%`` Replaced by the repository name. |br| The value is derived from ``${{ github.repository }}`` by splitting namespace and repository name into the ``${repo}`` variable. ``%%gh_owner_repo%%`` Replaced by the repository slug, which is either the name of a GitHub organisation or a GitHub user account followed by the repository name concatenated by the slash character. |br| The value is derived from ``${{ github.repository }}``. ``%%gh_pages%%`` Replaced by the URL to the associated GitHub Pages webspace. |br| The value is formatted as ``https://${{ github.repository_owner }}.github.io/${repo}``. ``%%gh_runid%%`` Replaced by the pipelines ID. |br| The value is derived from ``${{ github.run_id }}`` ``%%gh_actor%%`` Replaced by the actor (user or bot), who launched the pipeline. |br| The value is derived from ``${{ github.actor }}``. ``%%gh_sha%%`` Replaced by the associated commit's SHA. |br| The value is derived from ``${{ github.sha }}`` ``%%date%%`` Replaced by the current date. |br| The value is formatted as ``$(date '+%Y-%m-%d')``. ``%%time%%`` Replaced by the current date. |br| The value is formatted as ``$(date '+%H:%M:%S %Z')``. ``%%datetime%%`` Replaced by the current date. |br| The value is formatted as ``$(date '+%Y-%m-%d %H:%M:%S %Z')``. Examples ======== .. todo:: * GHDL - uses description_file and description * pyTooling - uses pullrequest .. _JOBTMPL/PublishReleaseNotes/Assets: Assets ****** .. todo:: PublishReleaseNotes::Assets Describe artifact to asset transformation Format: ``artifact:file:title`` See also: :ref:`JOBTMPL/PublishReleaseNotes/Input/replacements` .. _JOBTMPL/PublishReleaseNotes/Inventory: Inventory ********* .. todo:: PublishReleaseNotes::Inventory Describe how inventory files are created. .. _JOBTMPL/PublishReleaseNotes/Parameters: Parameter Summary ***************** .. rubric:: Goto :ref:`input parameters ` +-------------------------------------------------------------------------+----------+----------+-------------------------------------------------------------------+ | Parameter Name | Required | Type | Default | +=========================================================================+==========+==========+===================================================================+ | :ref:`JOBTMPL/PublishReleaseNotes/Input/ubuntu_image` | no | string | ``'ubuntu-24.04'`` | +-------------------------------------------------------------------------+----------+----------+-------------------------------------------------------------------+ | :ref:`JOBTMPL/PublishReleaseNotes/Input/release_branch` | no | string | ``'main'`` | +-------------------------------------------------------------------------+----------+----------+-------------------------------------------------------------------+ | :ref:`JOBTMPL/PublishReleaseNotes/Input/mode` | no | string | ``'release'`` | +-------------------------------------------------------------------------+----------+----------+-------------------------------------------------------------------+ | :ref:`JOBTMPL/PublishReleaseNotes/Input/tag` | yes | string | — — — — | +-------------------------------------------------------------------------+----------+----------+-------------------------------------------------------------------+ | :ref:`JOBTMPL/PublishReleaseNotes/Input/title` | no | string | ``''`` | +-------------------------------------------------------------------------+----------+----------+-------------------------------------------------------------------+ | :ref:`JOBTMPL/PublishReleaseNotes/Input/description` | no | string | ``''`` | +-------------------------------------------------------------------------+----------+----------+-------------------------------------------------------------------+ | :ref:`JOBTMPL/PublishReleaseNotes/Input/description_file` | no | string | ``''`` | +-------------------------------------------------------------------------+----------+----------+-------------------------------------------------------------------+ | :ref:`JOBTMPL/PublishReleaseNotes/Input/description_footer` | no | string | see parameter details | +-------------------------------------------------------------------------+----------+----------+-------------------------------------------------------------------+ | :ref:`JOBTMPL/PublishReleaseNotes/Input/draft` | no | boolean | ``false`` | +-------------------------------------------------------------------------+----------+----------+-------------------------------------------------------------------+ | :ref:`JOBTMPL/PublishReleaseNotes/Input/prerelease` | no | boolean | ``false`` | +-------------------------------------------------------------------------+----------+----------+-------------------------------------------------------------------+ | :ref:`JOBTMPL/PublishReleaseNotes/Input/latest` | no | boolean | ``false`` | +-------------------------------------------------------------------------+----------+----------+-------------------------------------------------------------------+ | :ref:`JOBTMPL/PublishReleaseNotes/Input/replacements` | no | string | ``''`` | +-------------------------------------------------------------------------+----------+----------+-------------------------------------------------------------------+ | :ref:`JOBTMPL/PublishReleaseNotes/Input/assets` | no | string | ``''`` | +-------------------------------------------------------------------------+----------+----------+-------------------------------------------------------------------+ | :ref:`JOBTMPL/PublishReleaseNotes/Input/inventory-json` | no | string | ``''`` | +-------------------------------------------------------------------------+----------+----------+-------------------------------------------------------------------+ | :ref:`JOBTMPL/PublishReleaseNotes/Input/inventory-version` | no | string | ``''`` | +-------------------------------------------------------------------------+----------+----------+-------------------------------------------------------------------+ | :ref:`JOBTMPL/PublishReleaseNotes/Input/inventory-categories` | no | string | ``''`` | +-------------------------------------------------------------------------+----------+----------+-------------------------------------------------------------------+ | :ref:`JOBTMPL/PublishReleaseNotes/Input/tarball-name` | no | string | ``'__pyTooling_upload_artifact__.tar'`` | +-------------------------------------------------------------------------+----------+----------+-------------------------------------------------------------------+ | :ref:`JOBTMPL/PublishReleaseNotes/Input/can-fail` | no | boolean | ``false`` | +-------------------------------------------------------------------------+----------+----------+-------------------------------------------------------------------+ .. rubric:: Goto :ref:`secrets ` This job template needs no secrets. .. rubric:: Goto :ref:`output parameters ` This job template has no output parameters. .. _JOBTMPL/PublishReleaseNotes/Inputs: Input Parameters **************** .. _JOBTMPL/PublishReleaseNotes/Input/ubuntu_image: ubuntu_image ============ :Type: string :Required: usually no :Default Value: ``'ubuntu-24.04'`` :Possible Values: See `actions/runner-images - Available Images `__ for available Ubuntu image versions. :Description: Name of the Ubuntu image used to run a job. .. _JOBTMPL/PublishReleaseNotes/Input/release_branch: release_branch ============== :Type: string :Required: no :Default Value: ``'main'`` :Possible Values: Any valid Git branch name. :Description: Name of the branch containing releases. .. _JOBTMPL/PublishReleaseNotes/Input/mode: mode ==== :Type: string :Required: no :Default Value: ``'release'`` :Possible Values: ``'release'``, ``'nightly'`` :Description: The release mode, which is either *nightly* (a.k.a *rolling* release) or *release*. .. _JOBTMPL/PublishReleaseNotes/Input/tag: tag === :Type: string :Required: yes :Default Value: — — — — :Possible Values: Any valid Git tag name. :Description: Name of the release (tag). :Condition: It must match an existing tag name in the repository. .. _JOBTMPL/PublishReleaseNotes/Input/title: title ===== :Type: string :Required: no :Default Value: ``''`` :Possible Values: Any valid string suitable for a release title (headline). :Description: If this parameter is not empty, the releases title is set, which overrides the default title inferred from the associated tag name. .. _JOBTMPL/PublishReleaseNotes/Input/description: description =========== :Type: string :Required: no :Default Value: ``''`` :Possible Values: Any valid (multi-line) Markdown string. :Description: The description of the release usually used to render the *release notes*. |br| See :ref:`JOBTMPL/PublishReleaseNotes/ReleaseNotes` for more details. .. _JOBTMPL/PublishReleaseNotes/Input/description_file: description_file ================ :Type: string :Required: no :Default Value: ``''`` :Possible Values: Any valid Markdown file. |br| Suggested value: :file:`.github/ReleaseDescription.md`. :Description: Path to a Markdown file used for the release description. |br| See :ref:`JOBTMPL/PublishReleaseNotes/ReleaseNotes` for more details. .. _JOBTMPL/PublishReleaseNotes/Input/description_footer: description_footer ================== :Type: string :Required: no :Default Value: .. code-block:: -------- Published from [%%gh_workflow_name%%](%%gh_server%%/%%gh_owner_repo%%/actions/runs/%%gh_runid%%) workflow triggered by %%gh_actor%% on %%datetime%%. This automatic release was created by [pyTooling/Actions](http://github.com/pyTooling/Actions)::Release.yml :Possible Values: Any valid (multi-line) Markdown text. :Description: A footer added to the description. |br| See :ref:`JOBTMPL/PublishReleaseNotes/ReleaseNotes` for more details. .. _JOBTMPL/PublishReleaseNotes/Input/draft: draft ===== :Type: :red:`boolean` :Required: no :Default Value: ``false`` :Possible Values: ``false``, ``true`` :Description: If *true*, the release is kept in *draft* state. .. note:: GitHub doesn't send e-mail notifications to subscribed users for draft releases. .. _JOBTMPL/PublishReleaseNotes/Input/prerelease: prerelease ========== :Type: :red:`boolean` :Required: no :Default Value: ``false`` :Possible Values: ``false``, ``true`` :Description: If *true*, the release is marked as a *pre-release*. .. _JOBTMPL/PublishReleaseNotes/Input/latest: latest ====== :Type: :red:`boolean` :Required: no :Default Value: ``false`` :Possible Values: ``false``, ``true`` :Description: If *true*, the release is marked as *latest release*. .. _JOBTMPL/PublishReleaseNotes/Input/replacements: replacements ============ :Type: string :Required: no :Default Value: ``''`` :Possible Values: Any valid multi-line string of format ``search=replace`` patterns. :Description: The given replacements are used to replace placeholders in :ref:`JOBTMPL/PublishReleaseNotes/Input/description`, :ref:`JOBTMPL/PublishReleaseNotes/Input/description_file`, :ref:`JOBTMPL/PublishReleaseNotes/Input/description_footer`. |br| See :ref:`JOBTMPL/PublishReleaseNotes/ReleaseNotes` for more details. :Example: The following example replaces the placeholder ``%version%`` with the actual version number (inferred from tag name by :ref:`JOBTMPL/PrepareJob`. .. code-block:: yaml ReleasePage: uses: pyTooling/Actions/.github/workflows/PublishReleaseNotes.yml@r5 needs: - Prepare if: needs.Prepare.outputs.is_release_tag == 'true' permissions: contents: write actions: write with: tag: ${{ needs.Prepare.outputs.version }} description: | # myPackage %version% This is the latest release of myPackage. replacements: | version=${{ needs.Prepare.outputs.version }} .. _JOBTMPL/PublishReleaseNotes/Input/assets: assets ====== :Type: string :Required: no :Default Value: ``''`` :Possible Values: Any valid multi-line string containing artifact to asset transformations. |br| The ``artifact:file:title`` format is explained at :ref:`JOBTMPL/PublishReleaseNotes/Assets` :Description: Each line describes which artifacts to download and extract as well as which extracted file to upload as a release asset. The files title can be changed. |br| Replacement rules from parameter :ref:`JOBTMPL/PublishReleaseNotes/Input/replacements` can be used, too. |br| See :ref:`JOBTMPL/PublishReleaseNotes/Assets` for more details. .. _JOBTMPL/PublishReleaseNotes/Input/inventory-json: inventory-json ============== :Type: string :Required: no :Default Value: ``''`` :Possible Values: Any valid JSON filename. |br| Suggested value: :file:`inventory.json`. :Description: If this parameter is not empty, an inventory of all assets will be created and attached as a JSON file to the release. |br| See :ref:`JOBTMPL/PublishReleaseNotes/Inventory` for more details. .. _JOBTMPL/PublishReleaseNotes/Input/inventory-version: inventory-version ================= :Type: string :Required: no :Default Value: ``''`` :Possible Values: Any valid version string. :Description: If this parameter is not empty, the version field in the inventory JSON is set to this value. |br| See :ref:`JOBTMPL/PublishReleaseNotes/Inventory` for more details. .. hint:: Especially for *nightly*/*rolling* releases, the used Git tag is a name rather then a version number. Therefore, a version number must be provided thus a nightly release can be identified as ``vX.Y.Z``. .. _JOBTMPL/PublishReleaseNotes/Input/inventory-categories: inventory-categories ==================== :Type: string :Required: no :Default Value: ``''`` :Possible Values: A colon separated list of identifiers used as category names in an inventory JSON. :Description: For decoding hierarchy levels (categories) in an inventory JSON, the hierarchy of categories can be added to the inventoy JSON. |br| See :ref:`JOBTMPL/PublishReleaseNotes/Inventory` for more details. .. _JOBTMPL/PublishReleaseNotes/Input/tarball-name: tarball-name ============ :Type: string :Required: no :Default Value: ``'__pyTooling_upload_artifact__.tar'`` :Possible Values: Any valid name for a tarball file. :Description: .. todo:: PublishReleaseNotes::tarball-name Needs documentation. .. _JOBTMPL/PublishReleaseNotes/Input/can-fail: can-fail ======== :Type: :red:`boolean` :Required: no :Default Value: ``false`` :Possible Values: ``false``, ``true`` :Description: .. todo:: PublishReleaseNotes::can-fail Needs documentation. .. _JOBTMPL/PublishReleaseNotes/Secrets: Secrets ******* This job template needs no secrets. .. _JOBTMPL/PublishReleaseNotes/Outputs: Outputs ******* .. _JOBTMPL/PublishReleaseNotes/Output/release-page: release-page ============ :Type: string :Description: Returns the URL to the release page. :Example: ``tbd`` .. _JOBTMPL/PublishReleaseNotes/Optimizations: Optimizations ************* This template offers no optimizations (reduced job runtime).