diff --git a/.github/actions/build-sign-and-package-plugin/action.yml b/.github/actions/build-sign-and-package-plugin/action.yml index b4a6321f..e0a9b655 100644 --- a/.github/actions/build-sign-and-package-plugin/action.yml +++ b/.github/actions/build-sign-and-package-plugin/action.yml @@ -7,18 +7,15 @@ inputs: it as the official plugin version. required: true outputs: + authoritative_version_number: + description: "The version number of the plugin used for publishing artifacts" + value: ${{ steps.plugin-version.outputs.version }} artifact_filename: description: "The filename of the plugin artifact" value: ${{ steps.artifact-filename.outputs.filename }} runs: using: "composite" steps: - # This will fetch the secret keys from vault and set them as environment variables for subsequent steps - - name: Get Vault secrets - uses: grafana/shared-workflows/actions/get-vault-secrets@main - with: - repo_secrets: | - GRAFANA_ACCESS_POLICY_TOKEN=github_actions:cloud-access-policy-token - name: Determine official plugin version id: plugin-version shell: bash diff --git a/.github/workflows/on-helm-release-pr-merged.yml b/.github/workflows/on-helm-release-pr-merged.yml index 497a5f07..9f107bfe 100644 --- a/.github/workflows/on-helm-release-pr-merged.yml +++ b/.github/workflows/on-helm-release-pr-merged.yml @@ -8,11 +8,35 @@ on: - helm/oncall/Chart.yaml jobs: + get-irm-app-token: + runs-on: ubuntu-latest + outputs: + token: ${{ steps.generate-token.outputs.token }} + steps: + - name: Get Vault secrets + id: get-secrets + uses: grafana/shared-workflows/actions/get-vault-secrets@main + with: + repo_secrets: | + GH_APP_ID=github-app:app-id + GH_APP_PRIVATE_KEY=github-app:private-key + + - name: Generate Github App token + id: generate-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ env.GH_APP_ID }} + private-key: ${{ env.GH_APP_PRIVATE_KEY }} + owner: grafana + repositories: "helm-charts" + call-update-helm-repo: uses: grafana/helm-charts/.github/workflows/update-helm-repo.yaml@main + needs: + - get-irm-app-token with: charts_dir: helm cr_configfile: helm/cr.yaml ct_configfile: helm/ct.yaml secrets: - helm_repo_token: ${{ secrets.GH_HELM_RELEASE }} + helm_repo_token: ${{ needs.get-irm-app-token.outputs.token }} diff --git a/.github/workflows/on-release-published.yml b/.github/workflows/on-release-published.yml index 82c40e8d..dcb7fae0 100644 --- a/.github/workflows/on-release-published.yml +++ b/.github/workflows/on-release-published.yml @@ -36,6 +36,7 @@ jobs: uses: grafana/shared-workflows/actions/get-vault-secrets@main with: repo_secrets: | + GRAFANA_ACCESS_POLICY_TOKEN=github_actions:cloud-access-policy-token GCS_PLUGIN_PUBLISHER_SERVICE_ACCOUNT_JSON=github_actions:gcs-plugin-publisher - name: Build, sign, and package plugin id: build-sign-and-package-plugin @@ -57,7 +58,7 @@ jobs: id: gcs-artifact-url # yamllint disable rule:line-length run: | - echo url="https://storage.googleapis.com/grafana-oncall-app/releases/grafana-oncall-app-${{ github.ref_name }}.zip" >> $GITHUB_OUTPUT + echo url="https://storage.googleapis.com/grafana-oncall-app/releases/grafana-oncall-app-${{ steps.build-sign-and-package-plugin.outputs.authoritative_version_number }}.zip" >> $GITHUB_OUTPUT - name: Publish plugin to grafana.com run: | curl -f -w "status=%{http_code}" -s -H "Authorization: Bearer ${{ env.GRAFANA_ACCESS_POLICY_TOKEN }}" -d "download[any][url]=${{ steps.gcs-artifact-url.outputs.url }}" -d "download[any][md5]=$(curl -sL ${{ steps.gcs-artifact-url.outputs.url }} | md5sum | cut -d'' '' -f1)" -d url=https://github.com/grafana/oncall/grafana-plugin https://grafana.com/api/plugins diff --git a/docs/sources/oncall-api-reference/integrations.md b/docs/sources/oncall-api-reference/integrations.md index 5ae6d292..0d75e4ca 100644 --- a/docs/sources/oncall-api-reference/integrations.md +++ b/docs/sources/oncall-api-reference/integrations.md @@ -17,6 +17,10 @@ refs: # Integrations HTTP API +{{< admonition type="note" >}} +⚠️ `msteams` templates are only available on Grafana Cloud +{{< /admonition >}} + ## Create an integration ```shell @@ -72,6 +76,10 @@ The above command returns JSON structured in the following way: "message": null, "image_url": null }, + "mobile_app": { + "title": null, + "message": null + }, "email": { "title": null, "message": null @@ -144,6 +152,10 @@ The above command returns JSON structured in the following way: "message": null, "image_url": null }, + "mobile_app": { + "title": null, + "message": null + }, "email": { "title": null, "message": null @@ -220,6 +232,10 @@ The above command returns JSON structured in the following way: "message": null, "image_url": null }, + "mobile_app": { + "title": null, + "message": null + }, "email": { "title": null, "message": null @@ -308,6 +324,10 @@ The above command returns JSON structured in the following way: "title": null, "message": null, "image_url": null + }, + "mobile_app": { + "title": null, + "message": null } } } diff --git a/engine/apps/alerts/models/alert_group.py b/engine/apps/alerts/models/alert_group.py index 44bdab90..489607a4 100644 --- a/engine/apps/alerts/models/alert_group.py +++ b/engine/apps/alerts/models/alert_group.py @@ -129,7 +129,8 @@ class AlertGroupQuerySet(models.QuerySet): pass # If it's an "OK" alert, try to return the latest resolved group - if group_data.is_resolve_signal: + # (only if the channel allows source base resolving and the alert is a resolve signal) + if channel.allow_source_based_resolving and group_data.is_resolve_signal: try: return self.filter(**search_params, resolved=True).latest(), False except self.model.DoesNotExist: diff --git a/engine/apps/alerts/tests/test_alert_group.py b/engine/apps/alerts/tests/test_alert_group.py index ae2aecee..ddafe102 100644 --- a/engine/apps/alerts/tests/test_alert_group.py +++ b/engine/apps/alerts/tests/test_alert_group.py @@ -1,3 +1,4 @@ +import hashlib from unittest.mock import call, patch import pytest @@ -758,3 +759,40 @@ def test_update_state_by_backsync( assert (last_log.action_source, last_log.author, last_log.step_specific_info) == expected_log_data assert last_log.type == to_firing_log_type mock_start_escalation_if_needed.assert_called_once() + + +@pytest.mark.django_db +def test_alert_group_created_if_resolve_condition_but_auto_resolving_disabled( + make_organization, + make_alert_receive_channel, + make_alert_group, +): + organization = make_organization() + # grouping condition will match. resolve condition will evaluate to True, but auto resolving is disabled + grouping_distinction = "abcdef" + alert_receive_channel = make_alert_receive_channel( + organization, + grouping_id_template=grouping_distinction, + resolve_condition_template="True", + allow_source_based_resolving=False, + ) + # existing alert group, resolved, with a matching grouping distinction + resolved_alert_group = make_alert_group( + alert_receive_channel, + resolved=True, + distinction=hashlib.md5(grouping_distinction.encode()).hexdigest(), + ) + + # an alert for the same integration is received + alert = Alert.create( + title="the title", + message="the message", + alert_receive_channel=alert_receive_channel, + raw_request_data={}, + integration_unique_data={}, + image_url=None, + link_to_upstream_details=None, + ) + + # the alert will create a new alert group + assert alert.group != resolved_alert_group diff --git a/helm/oncall/Chart.yaml b/helm/oncall/Chart.yaml index b99b402f..a39062a8 100644 --- a/helm/oncall/Chart.yaml +++ b/helm/oncall/Chart.yaml @@ -22,7 +22,7 @@ dependencies: repository: https://charts.bitnami.com/bitnami condition: rabbitmq.enabled - name: redis - version: 20.0.5 + version: 16.13.2 repository: https://charts.bitnami.com/bitnami condition: redis.enabled - name: grafana