diff --git a/.github/PULL_REQUEST_TEMPLATE/default.md b/.github/PULL_REQUEST_TEMPLATE.md similarity index 100% rename from .github/PULL_REQUEST_TEMPLATE/default.md rename to .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/workflows/add-to-docs-project.yml b/.github/workflows/add-to-docs-project.yml index c66ded9cc..85879f973 100644 --- a/.github/workflows/add-to-docs-project.yml +++ b/.github/workflows/add-to-docs-project.yml @@ -7,7 +7,7 @@ on: jobs: main: - if: ${{ github.repository == 'grafana/writers-toolkit' }} + if: ${{ github.repository == 'grafana/writers-toolkit' }} permissions: contents: read id-token: write diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 692ce737f..e2cf8aeb8 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -7,7 +7,7 @@ on: jobs: main: - if: ${{ github.repository == 'grafana/writers-toolkit' }} + if: ${{ github.repository == 'grafana/writers-toolkit' }} permissions: contents: read id-token: write diff --git a/.github/workflows/dictionaries.yml b/.github/workflows/dictionaries.yml index 1f13ed695..38e4453ea 100644 --- a/.github/workflows/dictionaries.yml +++ b/.github/workflows/dictionaries.yml @@ -9,7 +9,7 @@ on: type: boolean jobs: main: - if: ${{ github.repository == 'grafana/writers-toolkit' }} + if: ${{ github.repository == 'grafana/writers-toolkit' }} container: image: bitnami/jsonnet@sha256:3d8b084da1b74f5d38bc35e1ebf02f4a57c0410ec59d4edbc25dd2fec5f5541c runs-on: ubuntu-latest diff --git a/.github/workflows/image.yml b/.github/workflows/image.yml index 8a59df587..23de85889 100644 --- a/.github/workflows/image.yml +++ b/.github/workflows/image.yml @@ -11,7 +11,7 @@ permissions: jobs: build: - if: ${{ github.repository == 'grafana/writers-toolkit' }} + if: ${{ github.repository == 'grafana/writers-toolkit' }} runs-on: ubuntu-latest steps: diff --git a/.github/workflows/prettier.yml b/.github/workflows/prettier.yml index 599510c01..9a1a3f922 100644 --- a/.github/workflows/prettier.yml +++ b/.github/workflows/prettier.yml @@ -9,10 +9,10 @@ on: type: boolean jobs: prettier: - if: ${{ github.repository == 'grafana/writers-toolkit' }} + if: ${{ github.repository == 'grafana/writers-toolkit' }} runs-on: ubuntu-latest steps: - - uses: ./prettier + - uses: grafana/writers-toolkit/prettier@main with: branch: ${{ env.GITHUB_REF }} trace: ${{ inputs.trace }} diff --git a/.github/workflows/test-publish-technical-documentation-release.yml b/.github/workflows/test-publish-technical-documentation-release.yml new file mode 100644 index 000000000..f9ca7ae76 --- /dev/null +++ b/.github/workflows/test-publish-technical-documentation-release.yml @@ -0,0 +1,35 @@ +# To use this workflow to test the publish-technical-documentation-release action: +# 1. Create a branch `test/publish-technical-documentation/v..x`. +# 2. Iterate on the workflow or action. +# 3a. To test push events, push the branch. +# 3b. To test tag events, tag the branch with `test/publish-technical-documentation/v..`. +# 4. Check the workflow output in https://github.com/grafana/writers-toolkit/actions. + +name: test-publish-technical-documentation-release + +on: + push: + branches: + - test/publish-technical-documentation-release/v[0-9]+.[0-9]+.x + tags: + - test/publish-technical-documentation-release/v[0-9]+.[0-9]+.[0-9]+ + workflow_dispatch: +jobs: + sync: + if: github.repository == 'grafana/writers-toolkit' + permissions: + contents: read + id-token: write + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: ./publish-technical-documentation-release + with: + release_tag_regexp: "^test/publish-technical-documentation-release/v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$" + release_branch_regexp: "^test/publish-technical-documentation-release/v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.x$" + release_branch_with_patch_regexp: "^test/publish-technical-documentation-release/v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$" + website_branch: test/publish-technical-documentation-release + website_directory: content/docs/publish-technical-documetation-release + version_suffix: "" diff --git a/.github/workflows/validate-documentation.yml b/.github/workflows/validate-documentation.yml index a4164f0cb..f863b1767 100644 --- a/.github/workflows/validate-documentation.yml +++ b/.github/workflows/validate-documentation.yml @@ -5,7 +5,7 @@ on: workflow_dispatch: jobs: doc-validator: - if: ${{ github.repository == 'grafana/writers-toolkit' }} + if: ${{ github.repository == 'grafana/writers-toolkit' }} runs-on: ubuntu-latest container: image: grafana/doc-validator:v4.0.0 @@ -27,7 +27,7 @@ jobs: env: REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} prettier: - if: ${{ github.repository == 'grafana/writers-toolkit' }} + if: ${{ github.repository == 'grafana/writers-toolkit' }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -59,7 +59,7 @@ jobs: env: REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} test: - if: ${{ github.repository == 'grafana/writers-toolkit' }} + if: ${{ github.repository == 'grafana/writers-toolkit' }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -91,7 +91,7 @@ jobs: REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} report-readability: - if: ${{ github.repository == 'grafana/writers-toolkit' }} + if: ${{ github.repository == 'grafana/writers-toolkit' }} name: Report readability runs-on: ubuntu-latest steps: diff --git a/RELEASE.md b/RELEASE.md index ea28f43fb..178240fca 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -10,6 +10,7 @@ The following directories contain GitHub Actions actions: - [`prettier`](./prettier/) - [`publish-technical-documentation`](./publish-technical-documentation/) - [`publish-technical-documentation-release`](./publish-technical-documentation-release/) +- [`update-make-docs`](./update-make-docs/) You release each action by creating or updating Git tags. The Git tag begins with the action directory, then a slash (`/`), and then the tag version. diff --git a/add-to-docs-project/index.mts b/add-to-docs-project/index.mts index 6eb3b6713..d8c7de557 100644 --- a/add-to-docs-project/index.mts +++ b/add-to-docs-project/index.mts @@ -10,7 +10,7 @@ const PROJECT_ID = "PVT_kwDOAG3Mbc027w"; const ISSUES_QUERY = fs.readFileSync("issues.graphql", "utf8"); const ADD_TO_PROJECT_MUTATION = fs.readFileSync( "add-to-project.graphql", - "utf8" + "utf8", ); async function addIssuesToProject(): Promise> { @@ -26,14 +26,14 @@ async function addIssuesToProject(): Promise> { for (const issue of issues) { console.log( - `Adding issue ${issue.title} (${issue.url}) to the Docs project.` + `Adding issue ${issue.title} (${issue.url}) to the Docs project.`, ); added.push( // https://api.slack.com/reference/surfaces/formatting#escaping `${issue.url}|${issue.title}` .replaceAll("&", "&") .replaceAll("<", "<") - .replaceAll(">", ">") + .replaceAll(">", ">"), ); await octokit.graphql(ADD_TO_PROJECT_MUTATION, { @@ -52,5 +52,5 @@ async function addIssuesToProject(): Promise> { const added = await addIssuesToProject(); core.setOutput( "added", - added.map((issue) => `- <${issue}>`.replaceAll('"', '\\"')).join("\\n") + added.map((issue) => `- <${issue}>`.replaceAll('"', '\\"')).join("\\n"), ); diff --git a/add-to-docs-project/tsconfig.json b/add-to-docs-project/tsconfig.json index 97ef06f7b..124237cb2 100644 --- a/add-to-docs-project/tsconfig.json +++ b/add-to-docs-project/tsconfig.json @@ -11,7 +11,7 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "es2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "es2022" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ @@ -25,9 +25,9 @@ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ /* Modules */ - "module": "nodenext", /* Specify what module code is generated. */ + "module": "nodenext" /* Specify what module code is generated. */, // "rootDir": "./", /* Specify the root folder within your source files. */ - "moduleResolution": "nodenext", /* Specify how TypeScript looks up a file from a given module specifier. */ + "moduleResolution": "nodenext" /* Specify how TypeScript looks up a file from a given module specifier. */, // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ @@ -76,12 +76,12 @@ // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ + "strict": true /* Enable all strict type-checking options. */, // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ @@ -103,6 +103,6 @@ /* Completeness */ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ } } diff --git a/docs/make-docs b/docs/make-docs index 8cf171e34..ba448ce07 100755 --- a/docs/make-docs +++ b/docs/make-docs @@ -6,7 +6,7 @@ # [Semantic versioning](https://semver.org/) is used to help the reader identify the significance of changes. # Changes are relevant to this script and the support docs.mk GNU Make interface. # -# ## 8.2.0 (2024-11-22) +# ## 8.3.0 (2024-12-27) # # ### Added # @@ -14,6 +14,12 @@ # # Useful to inspect if the script is correctly constructing the final command. # +# ## 8.2.0 (2024-12-22) +# +# ### Removed +# +# - Special cases for Oracle and Datadog plugins now that they exist in the plugins monorepo. +# # ## 8.1.0 (2024-08-22) # # ### Added @@ -21,7 +27,7 @@ # - Additional website mounts for projects that use the website repository. # # Mounts are required for `make docs` to work in the website repository or with the website project. -# The Makefile is also mounted for convenient development of the procedure that repository. +# The Makefile is also mounted for convenient development of the procedure in that repository. # # ## 8.0.1 (2024-07-01) # @@ -363,8 +369,6 @@ SOURCES_grafana_cloud_frontend_observability_faro_web_sdk='faro-web-sdk' SOURCES_helm_charts_mimir_distributed='mimir' SOURCES_helm_charts_tempo_distributed='tempo' SOURCES_opentelemetry='opentelemetry-docs' -SOURCES_plugins_grafana_datadog_datasource='datadog-datasource' -SOURCES_plugins_grafana_oracle_datasource='oracle-datasource' SOURCES_resources='website' VERSIONS_as_code='UNVERSIONED' @@ -375,8 +379,6 @@ VERSIONS_grafana_cloud_k6='UNVERSIONED' VERSIONS_grafana_cloud_data_configuration_integrations='UNVERSIONED' VERSIONS_grafana_cloud_frontend_observability_faro_web_sdk='UNVERSIONED' VERSIONS_opentelemetry='UNVERSIONED' -VERSIONS_plugins_grafana_datadog_datasource='latest' -VERSIONS_plugins_grafana_oracle_datasource='latest' VERSIONS_resources='UNVERSIONED' VERSIONS_technical_documentation='UNVERSIONED' VERSIONS_website='UNVERSIONED' @@ -386,8 +388,6 @@ PATHS_grafana_cloud='content/docs/grafana-cloud' PATHS_helm_charts_mimir_distributed='docs/sources/helm-charts/mimir-distributed' PATHS_helm_charts_tempo_distributed='docs/sources/helm-charts/tempo-distributed' PATHS_mimir='docs/sources/mimir' -PATHS_plugins_grafana_datadog_datasource='docs/sources' -PATHS_plugins_grafana_oracle_datasource='docs/sources' PATHS_resources='content' PATHS_tempo='docs/sources/tempo' PATHS_website='content' diff --git a/docs/sources/contribute/release-notes/index.md b/docs/sources/contribute/release-notes/index.md index 085ac0ab2..8bd039b51 100644 --- a/docs/sources/contribute/release-notes/index.md +++ b/docs/sources/contribute/release-notes/index.md @@ -34,185 +34,103 @@ The Grafana Cloud Traces updates are published using the What's new. ## What's new documentation development process -What's new content is published to the website through the website CMS. -To add a new note, browse to the [What's new CMS collection](https://admin.grafana.com/content-admin/#/collections/whats-new). +What's new content is published to the website through the website content management system (CMS). Because this platform is meant to be used by the entire organization, by default anyone can contribute and publish to What's new, without the need for approval. _Quality assurance is a conversation within and between contributing teams and internal stakeholders_, but there are some best practice guidelines described in the last two sections of this topic. -Enter release notes into the CMS two to four weeks before the feature is available, depending on the size of the product or feature. -This gives the Go To Market (GTM) team time for promotion and enablement. -For Grafana versioned releases, have your content entered in the CMS by the cut-off date communicated by the delivery team. -For more information, refer to the [Record Announce Document Ship (RADS) guidelines](https://wiki.grafana-ops.net/w/index.php/Engineering/RADS). +**What does "Published" mean?** It's important to understand that, in the context of the CMS, the word "published" has a slightly different meaning than in general use: -- **Published**: Your entry is complete and in **Published** status. - It's either visible on the external _What's new in Cloud_ page or is going to automatically become visible on the release date. -- **Live**: Your entry is visible on the _What's new in Cloud_ page. +- **Published, but not Live**: Your entry is complete and in **Published** status, but not visible on the _What's new in Cloud_ page. +- **Published and Live**: Your entry is complete and in **Published** status, and visible on the _What's new in Cloud_ page. + +### What's new timing + +Enter release notes into the CMS _two to four weeks before the feature is available_, depending on the size of the product or feature. + +For Grafana versioned releases, have your release notes entered in the CMS _by the cut-off date_ communicated by the delivery team. + +This gives the Go To Market (GTM) team time for promotion and enablement. +For more information, refer to the [Record Announce Document Ship (RADS) guidelines](https://wiki.grafana-ops.net/w/index.php/Engineering/RADS). ### Create a What's new entry -When you're ready to add a What's new entry, complete the following steps: + -1. Fill out the fields: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FieldDescriptionGuidance
FEATURE NAMEShort headline for the feature.For example, Grafana OnCall integration for Alerting.
FEATURE RELEASE DATEDate and time in UTC that you want this note to be live. -

This should also be the feature release date. If the feature is behind a feature toggle and gets rolled out only to a fraction of users the date is when the feature was first available to users opting in.

-

If you've opened a review PR, you must merge it before the date you've added here. If you enter a date that has passed, the website publishes the note on the next build.

-
CONTACTFirst and last name.The contents of this field aren't publicly viewable.
INTERNAL ONLY? (OPTIONAL)Set to true to only post the note on https://admin.grafana.com/whats-new/
TAGS (OPTIONAL)Select category tags that users can use to filter their view.Select as many as apply.
LAUNCH TIER (OPTIONAL)Marketing launch tier, to say how much marketing support this feature needs. -

For examples, refer to the Upcoming Products/Features Tracker + Calendar Google Sheet.

-

If you're not sure what level to use, ask in the #product-marketing Slack channel.

-
CLOUD AVAILABILITYSelect the stage of the feature's Cloud release.If the feature isn't available in Cloud, select None.
CLOUD EDITIONSSelect which account types have access to the feature.If the feature isn't available in Cloud, select None.
SELF-MANAGED AVAILABILITYSelect the stage of the feature's self-managed release.If the feature isn't available in the self-managed product, select None.
SELF-MANAGED EDITIONSSelect the on-premises offerings where this feature is available.If the feature isn't available in the self-managed product, select None.
SELF-MANAGED VERSIONSelect the version of self-managed product that will include the feature. -

If the feature isn't available in the self-managed product, select None.

-

If the version isn't available, select No suitable option and reach out in the #docs Slack channel so that a maintainer can add a new option. -

-
BODYInclude an overview of the feature and the problem it solves. -

If you want to view some best practices around what to write here, refer to Guidelines for What's new content.

-

Add any images and a link to your public YouTube video here.

-

If you need more information on adding an image, refer to Image, diagram, and screenshot guidelines.

-

If you need to mention a feature flag, use this format: To try out Trace to profiles, enable the traceToProfile feature toggle.

-
DOCUMENTATION URL (OPTIONAL)URL to the public documentation for this feature.
ENABLEMENT VIDEO (OPTIONAL)Link to the video used for enablement. -

Enablement videos are perhaps the fastest, most engaging tool for employees and users to learn about your feature. Use them for maximum engagement.

-

Follow these instructions to create and upload a video: Enablement video instructions.

-

When you upload an enablement video, the Content team receives a notification, edits it for the public, and uploads it to YouTube to coincide with your feature's release. They need a few weeks' lead time for this.

-
INTERNAL INFORMATION (OPTIONAL)Information for Grafana Labs employees only. -

For example, ProductDNA, Slack channel, FAQ, training documentation, or videos.

-

Used for training and internal announcements.

-

This is only visible on the internal What's new page, not the public What's New page.

-
+When you're ready to add a What's new entry, complete the following steps: +1. Go to the What's new collection of the [website CMS](https://admin.grafana.com/content-admin/#/collections/whats-new) and click **New Feature** at the top of the page. +1. Fill out [the CMS fields](#cms-fields). 1. Click **Save**. The entry is now in **Draft** status and the CMS opens a pull request in the `grafana/website` repository. - If your entry is future-dated, it won't show up in the website-generated preview or in your local build, but you can see it in the preview of the internal feed. - To do so, remove `/docs/grafana-cloud` from the preview URL and add the heading for your entry at the end of the URL. - It should look something like this: `https://deploy-preview-18347-zb444pucvq-uw.a.run.app/whats-new/#create-subtables-in-table-visualizations`. +1. (Optional) Preview your entry on GitHub. -1. If your entry is ready to publish, proceed to the next step. - If your entry requires review, follow these steps: + While the CMS provides a preview of your entry, it doesn't render video. Previewing your entry on GitHub lets you view videos and see your entry in the context of the website. - 1. In the **Status** drop-down, select **In review.** + - **Release date in the past** - Your entry will be visible in the website-generated preview. - {{< admonition type="note" >}} - _The Documentation Team doesn't automatically review these pull requests; teams that create What's new entries are responsible for determining their own review process._ + - **Release date in the future** - Your entry is only visible in the preview of the _internal feed_. + To see it, in the deploy preview URL, replace `/docs/grafana-cloud` with the heading for your entry. + For example: `https://deploy-preview-18347-zb444pucvq-uw.a.run.app/whats-new/#create-subtables-in-table-visualizations`. - However, there are two weekly Office Hours meetings offered by the Documentation Team that you're welcome to attend for guidance and assistance: - - - [Docs squad office hours (early)](https://docs.google.com/document/d/1QaH9PwIZ_6-6Udhmy7Zhwme72ZZLqSTiX8HYFFi6AE4/edit#heading=h.9o53ccbx7xrw) - - [Docs squad office hours (late)](https://docs.google.com/document/d/12XK3XYEZWU3uIPluq3sn5HSGqWHBHJkktqlyQZHj_Uw/edit#heading=h.9o53ccbx7xrw) - - {{< /admonition >}} +1. If your entry is ready to publish, proceed to the next step. + If your entry requires review, follow these steps: + 1. In the **Status** drop-down, select **In review.** 1. Work with your team to review and finalize the generated pull request. - 1. Merge your PR in time for your feature release date. + {{< admonition type="caution" >}} + The Grafana Labs documentation team doesn't automatically review these pull requests; teams that create What's new entries are responsible for determining their own review process. + {{< /admonition >}} - Merging your PR ensures your entry is live on the date you entered and it automatically updates the status of your entry in the CMS. +1. Publish your entry by the release date you've entered. -1. To publish your entry from the CMS, follow these steps: + - To publish from GitHub, merge your PR. + - To publish from the CMS: 1. In the **Status** drop-down, click **Ready**. 1. In the **Publish** drop-down, click **Publish now**. - The entry appears in [What's new in Cloud](https://grafana.com/docs/grafana-cloud/whats-new/) on the date you entered. + + + +The entry appears in [What's new in Cloud](https://grafana.com/docs/grafana-cloud/whats-new/) on the release date you've entered. If the date is in the past, it appears immediately. For Grafana versioned releases, the content you enter in the CMS is published in the versioned What's new at a later date. To understand the process of creating release notes for Grafana versioned releases, refer to [Create the versioned release notes](#create-the-versioned-release-notes). +{{< admonition type="caution">}} If you add an entry to the CMS after the relevant versioned What's new has already been published, you'll need to open a PR to also add it to the versioned What's new yourself. +{{< /admonition >}} -#### Updated release stage +### CMS fields -If you've previously created a What's new entry for a feature when it was in an early release stage and you want to announce that the feature has moved into a new release stage, create a new entry. -For example, you published a What's new entry when the feature was in public preview and now the feature is in general availability. + + + +| Field | Description | Guidance | +|---|---|---| +| FEATURE NAME | Short headline for the feature. | For example, _Grafana OnCall integration for Alerting_. | +| FEATURE RELEASE DATE | Date and time in UTC that you want this note to be live. |

This should also be the feature release date. If the feature is behind a feature toggle and gets rolled out only to a fraction of users, the date is when the feature was first available to users opting in.

If you've opened a review PR, you must merge it before the date you've added here. If you enter a date that has passed, the website publishes the note on the next build.

| +| CONTACT | First and last name. | The contents of this field aren't publicly viewable. | +| INTERNAL ONLY? (OPTIONAL) | Set to true to only post the note on [https://admin.grafana.com/whats-new/](https://admin.grafana.com/whats-new/) | | +| TAGS (OPTIONAL) | Select category tags that users can use to filter their view. | Select as many as apply. | +| LAUNCH TIER (OPTIONAL) | Marketing launch tier, to say how much marketing support this feature needs. |

For a rubric, refer to the [Release Tier Matrix](https://wiki.grafana-ops.net/w/index.php/Marketing/Product_Marketing/Product_Release_Tier_Matrix).

For examples, refer to the [Upcoming Products/Features Tracker + Calendar Google Sheet](https://docs.google.com/spreadsheets/d/1E81c1OGisYtGWpLlHm7rBMOYKk-0N1akHyNbPqaANFY/edit?gid=801299949#gid=801299949).

If you're not sure what level to use, ask in the **#product-marketing** Slack channel.

| +| CLOUD AVAILABILITY | Select the stage of the feature's Cloud release. | If the feature isn't available in Cloud, select **None**. | +| CLOUD EDITIONS | Select which account types have access to the feature. | If the feature isn't available in Cloud, select **None**. | +| SELF-MANAGED AVAILABILITY | Select the stage of the feature's self-managed release. | If the feature isn't available in the self-managed product, select **None**. | +| SELF-MANAGED EDITIONS | Select the on-premises offerings where this feature is available. | If the feature isn't available in the self-managed product, select **None**. | +| SELF-MANAGED VERSION | Select the version of self-managed product that will include the feature. |

If the feature isn't available in the self-managed product, select **None**.

If the version isn't available, select **No suitable option** and reach out in the **#docs** Slack channel so that a maintainer can add a new option. | +| BODY | Include an overview of the feature and the problem it solves. | If you want to view some best practices around what to write here, refer to [Guidelines for What's new content](#guidelines-for-whats-new-content).

Add any images and a link to your public YouTube video here.

If you need more information on adding an image, refer to [Image, diagram, and screenshot guidelines](https://grafana.com/docs/writers-toolkit/write/image-guidelines/).

If you need to mention a feature flag, use this format: To try out Trace to profiles, enable the `traceToProfile` [feature toggle](https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/feature-toggles/).

| +| DOCUMENTATION URL (OPTIONAL) | URL to the public documentation for this feature. | Use the Cloud docs URL here. Add the self-managed docs URL in the INTERNAL INFORMATION field, if applicable. | +| ENABLEMENT VIDEO (OPTIONAL) | Link to the video used for enablement. |

Enablement videos are perhaps the fastest, most engaging tool for employees and users to learn about your feature. Use them for maximum engagement.

Follow these instructions to create and upload a video: [Enablement video instructions](https://docs.google.com/document/d/1nCiG62FxJ9J_qLTnlzNopSsT-VEAlxCUCsrAEpWL68U/edit#heading=h.fierz9i4q8ft).

When you upload an enablement video, the Content team receives a notification, edits it for the public, and uploads it to YouTube to coincide with your feature's release. They need a few weeks' lead time for this. | +| INTERNAL INFORMATION (OPTIONAL) | Information for Grafana Labs employees only. | For example, ProductDNA, Slack channel, FAQ, training documentation, or videos.

Used for training and internal announcements.

This is only visible on the [internal What's new page](https://admin.grafana.com/whats-new/), not the [public What's New page](https://grafana.com/docs/grafana-cloud/whats-new/).

| + + -You don't have to make the new entry as robust as the previous one. -Instead, you can keep the new entry brief by referring to or linking to the previous entry. + ### Edit What's new entries @@ -237,6 +155,14 @@ If your entry is already live in both _What's new in Cloud_ and it's between the If your entry requires an update after it's live in both the Cloud and self-managed What's new, you'll need to update both entries. +### Features in a new release stage + +If you've previously created a What's new entry for a feature when it was in an early release stage and you want to announce that the feature has moved into a new release stage, create a new entry. +For example, you published a What's new entry when the feature was in public preview and now the feature is in general availability. + +You don't have to make the new entry as robust as the previous one. +Instead, you can keep the new entry brief by referring to or linking to the previous entry. + ### Create the versioned release notes The following instructions are for the person directly responsible for creating the versioned release notes. diff --git a/docs/sources/structure/topic-types/section/index.md b/docs/sources/structure/topic-types/section/index.md index f9b18e56a..077fe75f8 100644 --- a/docs/sources/structure/topic-types/section/index.md +++ b/docs/sources/structure/topic-types/section/index.md @@ -53,4 +53,4 @@ Refer to the following pages for section page examples: ## Section template -When you're ready to write, make a copy of the [Section template](https://github.com/grafana/writers-toolkit/blob/main/docs/static/templates/section-template.md) and add your content. +When you're ready to write, make a copy of the [Section template](https://github.com/grafana/writers-toolkit/blob/main/docs/static/templates/section.md) and add your content. diff --git a/publish-technical-documentation-release/action.yaml b/publish-technical-documentation-release/action.yaml index af4c46e3f..8af35fa46 100644 --- a/publish-technical-documentation-release/action.yaml +++ b/publish-technical-documentation-release/action.yaml @@ -21,26 +21,30 @@ inputs: type: boolean release_branch_regexp: description: | - A regular expression with capture groups for major, and minor versions. - For example, '^release-(0|[1-9]\d*)\.(0|[1-9]\d*)$'. + A regular expression using Extended Regular Expression syntax with capture groups for major, and minor versions. + For example, '^release-(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'. For more information, refer to https://github.com/grafana/grafana-github-actions/blob/main/has-matching-release-tag/action.yaml#L28-L33. required: true release_branch_with_patch_regexp: default: "" description: | - A regular expression with capture groups for major, minor, and patch versions. - For example, '^release-(0|[1-9]\d*)\.(0|[1-9]\d*)$'. + A regular expression using Extended Regular Expression syntax with capture groups for major, minor, and patch versions. + For example, '^release-(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'. For more information, refer to https://github.com/grafana/grafana-github-actions/blob/main/has-matching-release-tag/action.yaml#L34-L40. required: false release_tag_regexp: description: | - A regular expression with capture groups for major, minor, and patch versions. - For example, '^v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$'. + A regular expression using Extended Regular Expression syntax with capture groups for major, minor, and patch versions. + For example, '^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'. For more information, refer to https://github.com/grafana/grafana-github-actions/blob/main/has-matching-release-tag/action.yaml#L22-L27. required: true source_directory: default: docs/sources description: Path to source directory, relative to the project root, to sync documentation from. + website_branch: + default: master + description: | + Website repository branch to sync the documentation to. website_directory: description: | Website directory to sync the documentation to. @@ -54,6 +58,25 @@ inputs: runs: using: composite steps: + - name: Switch to HEAD of branch for tags + # Tags aren't necessarily made to the HEAD of the branch. + # The documentation to be published is always on the HEAD of the branch. + if: github.ref_type == 'tag' + env: + GITHUB_REF: ${{ github.ref }} + RELEASE_BRANCH_REGEXP: ${{ inputs.release_branch_regexp }} + run: | + branch="$(./publish-technical-documentation-release/determine-release-branch "${RELEASE_BRANCH_REGEXP}" "${GITHUB_REF}")" + + if [[ -z "${branch}" ]]; then + echo "No release branch found for tag ${GITHUB_REF} matching ${RELEASE_BRANCH_REGEXP}. Exiting." + + exit 1 + fi + + git switch --detach "origin/${branch}" + shell: bash + - name: Build website shell: bash run: | @@ -102,32 +125,13 @@ runs: with: ref_name: ${{ github.ref_name }} - - name: Switch to HEAD of version branch for tags - # Tags aren't necessarily made to the HEAD of the version branch. - # The documentation to be published is always on the HEAD of the release branch. - if: steps.has-matching-release-tag.outputs.bool == 'true' && github.ref_type == 'tag' - env: - GITHUB_REF: ${{ github.ref }} - RELEASE_BRANCH_REGEXP: ${{ inputs.release_branch_regexp }} - run: | - branch="$(./publish-technical-documentation-release/determine-release-branch "${RELEASE_BRANCH_REGEXP}" "${GITHUB_REF}")" - - if [[ -z "${branch}" ]]; then - echo "No release branch found for tag ${GITHUB_REF} matching ${RELEASE_BRANCH_REGEXP}. Exiting." - - exit 1 - fi - - git switch --detach "origin/${branch}" - shell: bash - - name: Sync to the website repository (release) if: steps.has-matching-release-tag.outputs.bool == 'true' uses: ./.github/actions/website-sync id: publish-release with: repository: grafana/website - branch: master + branch: ${{ inputs.website_branch }} host: github.com github_pat: grafanabot:${{ env.PUBLISH_TO_WEBSITE_TOKEN }} source_folder: ${{ inputs.source_directory }} diff --git a/publish-technical-documentation-release/determine-release-branch b/publish-technical-documentation-release/determine-release-branch index 0e2c80c46..cb512c9d1 100755 --- a/publish-technical-documentation-release/determine-release-branch +++ b/publish-technical-documentation-release/determine-release-branch @@ -21,10 +21,12 @@ if [[ $# -ne 2 ]]; then fi BRANCH_REGEXP="$1" -TAG="$2" +TAG="${2#refs/tags/}" -for branch in $(git branch -a --contains "tags/${TAG}"); do +contains="$(git branch -a --contains "tags/${TAG}")" +for branch in ${contains}; do branch="${branch#remotes/origin/}"; + echo "Checking branch ${branch} against ${BRANCH_REGEXP}." >&2 if [[ "${branch}" =~ ${BRANCH_REGEXP} ]]; then echo "${branch}"; @@ -33,4 +35,7 @@ for branch in $(git branch -a --contains "tags/${TAG}"); do fi; done +echo "No release branch found for tag ${TAG} matching ${BRANCH_REGEXP}. Exiting." >&2 +echo "Branches containing tag ${TAG}:" >&2 +echo "${contains}" >&2 exit 1 diff --git a/vale/Grafana/Paragraphs.yml b/vale/Grafana/Paragraphs.yml new file mode 100644 index 000000000..24dc6bb7d --- /dev/null +++ b/vale/Grafana/Paragraphs.yml @@ -0,0 +1,7 @@ +extends: script +scope: raw +level: error +link: https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-br-element +message: | + br elements must be used only for line breaks that are actually part of the content, as in poems or addresses. +script: Paragraphs.tengo diff --git a/vale/Grafana/styles/config/scripts/Paragraphs.tengo b/vale/Grafana/styles/config/scripts/Paragraphs.tengo new file mode 100644 index 000000000..53819ca3e --- /dev/null +++ b/vale/Grafana/styles/config/scripts/Paragraphs.tengo @@ -0,0 +1,36 @@ +DEBUG := false + +fmt := import("fmt") +text := import("text") + +matches := [] +ruleActive := true + +cursor := 0 +for line in text.split(scope, "\n") { + if DEBUG { + fmt.println(text.pad_left(text.itoa(cursor), 3, " "), ": ", text.quote(line), " ", len(line)) + } + + if text.re_find(``, line, -1) { + ruleActive = false + } + + if text.re_find(``, line, -1) { + ruleActive = true + } + + if ruleActive { + for match in text.re_find(`
`, line, -1) { + matches = append(matches, {begin: cursor + match[0].begin, end: cursor + match[0].end}) + } + } + + cursor += len(line) + 1 +} + +if DEBUG { + for match in matches { + fmt.println(match) + } +} \ No newline at end of file diff --git a/vale/Grafana/styles/config/scripts/Paragraphs_test.go b/vale/Grafana/styles/config/scripts/Paragraphs_test.go new file mode 100644 index 000000000..ac5f92f17 --- /dev/null +++ b/vale/Grafana/styles/config/scripts/Paragraphs_test.go @@ -0,0 +1,87 @@ +package test + +import ( + "context" + "os" + "regexp" + "testing" + + "github.com/d5/tengo/v2" + "github.com/d5/tengo/v2/stdlib" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestParagraphs(t *testing.T) { + t.Run("don't use", func(t *testing.T) { + src := `Don't use: + +-
+-
+-
+` + data, err := os.ReadFile("Paragraphs.tengo") + require.NoError(t, err) + + data = regexp.MustCompile(`DEBUG := false`).ReplaceAll(data, []byte(`DEBUG := true`)) + + script := tengo.NewScript(data) + script.SetImports(stdlib.GetModuleMap("text", "fmt", "math")) + + err = script.Add("scope", src) + require.NoError(t, err) + + compiled, err := script.RunContext(context.Background()) + require.NoError(t, err) + + want := []map[string]int{ + {"begin": 14, "end": 18}, + {"begin": 21, "end": 27}, + {"begin": 30, "end": 35}, + } + + assert.Equal(t, want, mustParseMatches(compiled.Get("matches").Array())) + }) + + t.Run("with exclusions", func(t *testing.T) { + src := ` +Test exclusions: + + + +-
+-
+-
+ + + +Don't use: + +-
+-
+-
+` + + data, err := os.ReadFile("Paragraphs.tengo") + require.NoError(t, err) + + data = regexp.MustCompile(`DEBUG := false`).ReplaceAll(data, []byte(`DEBUG := true`)) + + script := tengo.NewScript(data) + script.SetImports(stdlib.GetModuleMap("text", "fmt", "math")) + + err = script.Add("scope", src) + require.NoError(t, err) + + compiled, err := script.RunContext(context.Background()) + require.NoError(t, err) + + want := []map[string]int{ + {"begin": 137, "end": 141}, + {"begin": 144, "end": 150}, + {"begin": 153, "end": 158}, + } + + assert.Equal(t, want, mustParseMatches(compiled.Get("matches").Array())) + }) +} diff --git a/vale/Grafana/styles/config/scripts/SmartQuotes_test.go b/vale/Grafana/styles/config/scripts/SmartQuotes_test.go index e4c99ef2e..0ad3bc692 100644 --- a/vale/Grafana/styles/config/scripts/SmartQuotes_test.go +++ b/vale/Grafana/styles/config/scripts/SmartQuotes_test.go @@ -13,22 +13,6 @@ import ( "github.com/stretchr/testify/require" ) -func mustParseMatches(a []interface{}) []map[string]int { - matches := []map[string]int{} - - for _, i := range a { - m, _ := i.(map[string]any) - match := map[string]int{ - "begin": int(m["begin"].(int64)), - "end": int(m["end"].(int64)), - } - - matches = append(matches, match) - } - - return matches -} - func TestSmartQuotes(t *testing.T) { t.Run("don't use", func(t *testing.T) { src := `Don't use: diff --git a/vale/Grafana/styles/config/scripts/tengo.go b/vale/Grafana/styles/config/scripts/tengo.go new file mode 100644 index 000000000..8d5357d0e --- /dev/null +++ b/vale/Grafana/styles/config/scripts/tengo.go @@ -0,0 +1,17 @@ +package test + +func mustParseMatches(a []interface{}) []map[string]int { + matches := []map[string]int{} + + for _, i := range a { + m, _ := i.(map[string]any) + match := map[string]int{ + "begin": int(m["begin"].(int64)), + "end": int(m["end"].(int64)), + } + + matches = append(matches, match) + } + + return matches +}