From 32b95db6f714cbdd886125d439a82dbe6999c5f6 Mon Sep 17 00:00:00 2001 From: Mike Stemle Date: Thu, 21 Dec 2023 08:23:48 -0500 Subject: [PATCH] Support v2.2 (#76) * Updated dependencies. * Initial support commit for v2.2. - Added the fields - Fixed broken tests - The `uuid` dependency was added because `@actions/core` requires it now * Finished updating the field versions, tests pass now. * Adding a bit of debug code. * building, and adding debug. * Adding org rules file support for `type` and `language`. * Updating snapshots. * Adding some minor tests, and updating docs. - Also added `ci-pipeline-fingerprints` support in `action.yml` - Prepping to release. --- .github/workflows/automated-testing.yml | 7 +- CHANGELOG.md | 12 + README.md | 44 ++- .../datadog-service-catalog-schema-v2.2.json | 218 +++++++++++ .../fieldMappings-schema.test.cjs.snap | 41 +- .../__snapshots__/fieldMappings.test.cjs.snap | 41 +- .../input-validation.test.cjs.snap | 3 + __tests__/lib/input-validation.test.cjs | 8 +- __tests__/lib/org-rules-extra.test.cjs | 66 +++- __tests__/lib/org-rules.test.cjs | 60 ++- __tests__/self-workflow-validation.test.cjs | 35 +- action.yml | 13 +- dist/index.cjs | 350 ++++++++---------- lib/fieldMappings.cjs | 217 +++++++---- lib/org-rules.cjs | 84 +++-- package-lock.json | 248 +++++++------ package.json | 11 +- 17 files changed, 974 insertions(+), 484 deletions(-) create mode 100644 __tests__/data/datadog-service-catalog-schema-v2.2.json create mode 100644 __tests__/lib/__snapshots__/input-validation.test.cjs.snap diff --git a/.github/workflows/automated-testing.yml b/.github/workflows/automated-testing.yml index 0682367..5e762ff 100644 --- a/.github/workflows/automated-testing.yml +++ b/.github/workflows/automated-testing.yml @@ -28,7 +28,7 @@ jobs: - name: Datadog Service Catalog Metadata Provider Manual Test uses: ./ with: - schema-version: v2.1 + schema-version: v2.2 github-token: ${{ secrets.GITHUB_TOKEN }} datadog-hostname: api.us5.datadoghq.com datadog-key: ${{ secrets.DATADOG_API_KEY }} @@ -38,6 +38,11 @@ jobs: description: This is a test of the Datadog Service Catalog Metadata Provider lifecycle: production tier: p3 + type: function + languages: | + - javascript + - hopes + - dreams team: Team Name Here email: team-name-here@fakeemaildomainthatdoesntexist.com slack-support-channel: 'https://fakeorg.slack.com/archives/A0000000000' diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b39b51..ce76b39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog], and this project adheres to [Semantic Versioning]. +## [2.2.0] - unreleased + +### Added + +- Added support for schema version v2.2 +- Added the `uuid` dependency since `@actions/core` insists +- Added some more edge case tests + +### Changed + +- Updated dependencies + ## [2.1.0] - 2023-10-20 ### Added diff --git a/README.md b/README.md index a534d9c..5730600 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ At this time, this GitHub Action supports the following versions of the Service - `v2` - `v2.1` +- `v2.2` ## Wait, but why? @@ -69,35 +70,38 @@ Using a field which is not supported in the schema version you've selected will | Field | Description | Required | Default | Schema Versions | | --- | --- | --- | --- | --- | -| `service-name` | The name of the service. This must be unique across all services. | Yes | | `v2`, `v2.1` | -| `team` | The team that owns the service. | Yes | | `v2`, `v2.1` | -| `description` | A description of the service. | No | | `v2.1` | -| `application` | The application that the service belongs to. | No | | `v2.1` | -| `tier` | The importance tier of the service. This is an unconstrained text field where you can use your own tiering definitions. Examples would be `High`, `Critical`, or however you or your organization classify criticality tiers. | No | | `v2.1` | -| `lifecycle` | This is the lifecycle of the service. This text field is unconstrained, and some examples are `production`, `development`, `staging`. | No | | `v2.1` | -| `contacts` | The list of contacts for the service. Each of these contacts is an object. Keep in mind that `email` and `slack-support-channel` are already included as contacts. This list should be in addition to that. These values are supplied as objects, but due to the limitations of GitHub Actions, please supply these object properties as a multi-line string. | No | `[]` | `v2`, `v2.1` | -| `contacts[].name` | The name of the contact. | Yes | | `v2`, `v2.1` | -| `contacts[].type` | The type of the contact. Acceptable values are: `email`, `slack`, and `microsoft-teams` | Yes | | `v2`, `v2.1` | -| `contacts[].contact` | The actual contact information for the contact. For example, if the type is `email`, this would be the email address. | Yes | | `v2`, `v2.1` | +| `service-name` | The name of the service. This must be unique across all services. | Yes | | `v2`, `v2.1`, `v2.2` | +| `team` | The team that owns the service. | Yes | | `v2`, `v2.1`, `v2.2` | +| `description` | A description of the service. | No | | `v2.1`, `v2.2` | +| `application` | The application that the service belongs to. | No | | `v2.1`, `v2.2` | +| `type` | The type of resource that this service constitutes. Values are constrained to one of "web", "db", "cache", "function", "browser", "mobile", or "custom". | No | | `v2.2` | +| `languages` | This is a list of the languages used in this service. This is an array, so you may supply multiple values. | No | `[]` | `v2.2` | +| `tier` | The importance tier of the service. This is an unconstrained text field where you can use your own tiering definitions. Examples would be `High`, `Critical`, or however you or your organization classify criticality tiers. | No | | `v2.1`, `v2.2` | +| `lifecycle` | This is the lifecycle of the service. This text field is unconstrained, and some examples are `production`, `development`, `staging`. | No | | `v2.1`, `v2.2` | +| `contacts` | The list of contacts for the service. Each of these contacts is an object. Keep in mind that `email` and `slack-support-channel` are already included as contacts. This list should be in addition to that. These values are supplied as objects, but due to the limitations of GitHub Actions, please supply these object properties as a multi-line string. | No | `[]` | `v2`, `v2.1`, `v2.2` | +| `contacts[].name` | The name of the contact. | Yes | | `v2`, `v2.1`, `v2.2` | +| `contacts[].type` | The type of the contact. Acceptable values are: `email`, `slack`, and `microsoft-teams` | Yes | | `v2`, `v2.1`, `v2.2` | +| `contacts[].contact` | The actual contact information for the contact. For example, if the type is `email`, this would be the email address. | Yes | | `v2`, `v2.1`, `v2.2` | | `repos` | The list of GitHub repositories that are part of the service. You must supply at least one repository. The repositories are supplied as objects, but due to the limitations of GitHub Actions, please supply these object properties as a multi-line string. In `v2.1`, this field is moved under `links`. | Yes | `[]` | `v2` | | `repos[].name` | The name of the repository. | Yes | | `v2` | | `repos[].url` | The URL of the repository. | Yes | | `v2` | | `repos[].provider` | The provider of the repository. Acceptable values are: `Github`. | No | | `v2` | | `tags` | The list of tags that are associated with the service. This should be a list of key-value pairs separated by colons. | No | | -| `links` | A list of links associated with the service. These links are objects with a variety of properties, but due to the limitations of GitHub Actions, please supply these object properties as a multi-line string. | No | `[]` | `v2`, `v2.1` | -| `links[].name` | The name of the link. | Yes | | `v2`, `v2.1` | -| `links[].url` | The URL of the link. | Yes | | `v2`, `v2.1` | -| `links[].type` | The type for the link. Acceptable values for the `v2` API are: `doc`, `wiki`, `runbook`, `url`, `repo`, `dashboard`, `oncall`, `code`, and `link`. Acceptable values for the `v2.1` API are: `doc`, `runbook`, `repo`, `dashboard`, and `other`. | Yes | | `v2`, `v2.1` | +| `links` | A list of links associated with the service. These links are objects with a variety of properties, but due to the limitations of GitHub Actions, please supply these object properties as a multi-line string. | No | `[]` | `v2`, `v2.1`, `v2.2` | +| `links[].name` | The name of the link. | Yes | | `v2`, `v2.1`, `v2.2` | +| `links[].url` | The URL of the link. | Yes | | `v2`, `v2.1`, `v2.2` | +| `links[].type` | The type for the link. Acceptable values for the `v2` API are: `doc`, `wiki`, `runbook`, `url`, `repo`, `dashboard`, `oncall`, `code`, and `link`. Acceptable values for the `v2.1` API are: `doc`, `runbook`, `repo`, `dashboard`, and `other`. | Yes | | `v2`, `v2.1`, `v2.2` | | `docs` | A list of documentation links associated with the service. These links are objects with a variety of properties, but due to the limitations of GitHub Actions, please supply these object properties as a multi-line string. In `v2.1`, this field moved under `links`. | No | `[]` | `v2` | | `docs[].name` | The name of the document. | Yes | | `v2` | | `docs[].url` | The URL of the document. | Yes | | `v2` | | `docs[].provider` | The provider for where the documentation lives. Acceptable values are: `Confluence`, `GoogleDocs`, `Github`, `Jira`, `OneNote`, `SharePoint`, and `Dropbox` | No | | `v2` | -| `integrations` | Integrations associated with the service. These integrations are objects with a variety of properties, but due to the limitations of GitHub Actions, please supply these object properties as a multi-line string. | No | `{}` | `v2`, `v2.1` | -| `integrations.opsgenie` | The OpsGenie details for the service. | No | | `v2`, `v2.1` | -| `integrations.opsgenie.service-url` | The service URL for the OpsGenie integration. A team URL will work, but if you want on-call metadata then make sure that this URL is to a service, not a team. | Yes | | `v2`, `v2.1` | -| `integrations.opsgenie.region` | The region for the OpsGenie integration. Acceptable values are `US` and `EU`. | No | | `v2`, `v2.1` | -| `integrations.pagerduty` | The PagerDuty URL for the service. **Important:** In `v2`, this field is just a URL. In `v2.1` this field is a dictionary with a `service-url` property. | No | | `v2`, `v2.1` | -| `integrations.pagerduty.service-url` | The PagerDuty URL for the service. | Yes | | `v2.1` | +| `integrations` | Integrations associated with the service. These integrations are objects with a variety of properties, but due to the limitations of GitHub Actions, please supply these object properties as a multi-line string. | No | `{}` | `v2`, `v2.1`, `v2.2` | +| `integrations.opsgenie` | The OpsGenie details for the service. | No | | `v2`, `v2.1`, `v2.2` | +| `integrations.opsgenie.service-url` | The service URL for the OpsGenie integration. A team URL will work, but if you want on-call metadata then make sure that this URL is to a service, not a team. | Yes | | `v2`, `v2.1`, `v2.2` | +| `integrations.opsgenie.region` | The region for the OpsGenie integration. Acceptable values are `US` and `EU`. | No | | `v2`, `v2.1`, `v2.2` | +| `integrations.pagerduty` | The PagerDuty URL for the service. **Important:** In `v2`, this field is just a URL. In `v2.1` this field is a dictionary with a `service-url` property. | No | | `v2`, `v2.1`, `v2.2` | +| `integrations.pagerduty.service-url` | The PagerDuty URL for the service. | Yes | | `v2.1`, `v2.2` | +| `ci-pipeline-fingerprints` | A set of CI pipeline fingerprints related to the service. | No | `[]` | `v2.2` | ### Convenience Fields diff --git a/__tests__/data/datadog-service-catalog-schema-v2.2.json b/__tests__/data/datadog-service-catalog-schema-v2.2.json new file mode 100644 index 0000000..8774e1e --- /dev/null +++ b/__tests__/data/datadog-service-catalog-schema-v2.2.json @@ -0,0 +1,218 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://github.com/DataDog/schema/tree/main/service-catalog/v2.2/schema.json", + "title": "Service Definition Schema v2.2", + "description": "A service definition for providing additional service metadata and integrations v2.2", + "type": "object", + "properties": { + "schema-version": { + "description": "Schema version being used", + "examples": ["v2.2"], + "type": "string", + "default": "v2.2", + "enum": ["v2.2"] + }, + "dd-service": { + "description": "Unique identifier of the service. Must be unique across all services, and is used to match with a service in Datadog", + "examples": ["my-service"], + "type": "string" + }, + "team": { + "description": "Team that owns the service. It is used to locate a team defined in Datadog Teams if it exists", + "examples": ["my-team"], + "type": "string" + }, + "application": { + "description": "Identifier for a group of related services serving a product feature, which the service is a part of", + "examples": ["my-app"], + "type": "string" + }, + "description": { + "description": "A short description of the service", + "examples": ["My app description"], + "type": "string" + }, + "tier": { + "description": "Importance of the service", + "examples": ["1", "High"], + "type": "string" + }, + "lifecycle": { + "description": "The current life cycle phase of the service.", + "examples": ["sandbox", "staging", "production", "deprecated"], + "type": "string" + }, + "type": { + "description": "The type of service", + "examples": [ + "web", + "db", + "cache", + "function", + "browser", + "mobile", + "custom" + ], + "type": "string", + "enum": ["web", "db", "cache", "function", "browser", "mobile", "custom"] + }, + "languages": { + "description": "The service's programming language. See examples for a list of recognizable languages", + "examples": [ + ["dotnet", "go", "java", "js", "php", "python", "ruby", "c++"] + ], + "type": "array", + "items": { + "type": "string" + } + }, + "contacts": { + "description": "A list of contacts related to the services. ", + "type": "array", + "items": { + "$ref": "#/$defs/contact" + } + }, + "links": { + "description": "A list of links related to the services. ", + "type": "array", + "items": { + "$ref": "#/$defs/link" + } + }, + "tags": { + "description": "A set of custom tags", + "examples": [["my:tag"]], + "type": "array", + "items": { + "type": "string" + } + }, + "integrations": { + "description": "Third party integrations that Datadog supports", + "type": "object", + "properties": { + "pagerduty": { + "description": "Pagerduty integration for the service", + "type": "object", + "properties": { + "service-url": { + "description": "Pagerduty Service URL", + "examples": [ + "https://my-org.pagerduty.com/service-directory/PMyService" + ], + "type": "string", + "pattern": "^(https?://)?[a-zA-Z\\d_\\-.]+\\.pagerduty\\.com/service-directory/(P[a-zA-Z\\d_\\-]+)/?$" + } + }, + "required": ["service-url"], + "additionalProperties": false + }, + "opsgenie": { + "description": "Opsgenie integration for the service", + "type": "object", + "properties": { + "service-url": { + "description": "Opsgenie Service URL", + "examples": [ + "https://www.opsgenie.com/service/123e4567-e89b-12d3-a456-426614174000" + ], + "type": "string", + "pattern": "^(https?://)?[a-zA-Z\\d_\\-.]+\\.opsgenie\\.com/service/([a-zA-Z\\d_\\-]+)/?$" + }, + "region": { + "description": "Opsgenie Instance Region", + "type": "string", + "examples": ["US", "EU"], + "enum": ["US", "EU"] + } + }, + "required": ["service-url"], + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "extensions": { + "description": "Custom extensions", + "type": "object", + "additionalProperties": true + }, + "ci-pipeline-fingerprints": { + "description": "A set of CI pipeline fingerprints related to the service", + "examples": [["j88xdEy0J5lc", "eZ7LMljCk8vo"]], + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false, + "required": ["schema-version", "dd-service"], + "$defs": { + "link": { + "additionalProperties": false, + "type": "object", + "properties": { + "name": { + "description": "Link name", + "examples": ["Runbook", "Dashboard"], + "type": "string" + }, + "type": { + "description": "Link type. See examples for a list of recognizable types", + "examples": ["runbook", "doc", "repo", "dashboard", "other"], + "type": "string", + "default": "other" + }, + "url": { + "description": "Link url", + "examples": ["https://my-runbook"], + "type": "string", + "format": "uri" + }, + "provider": { + "description": "Link provider. See examples for a list of recognizable providers", + "examples": ["Github", "Confluence"], + "type": "string" + } + }, + "required": ["name", "type", "url"] + }, + "contact": { + "additionalProperties": false, + "type": "object", + "properties": { + "name": { + "description": "Contact name", + "examples": ["Oncall Slack", "Team Email"], + "type": "string", + "minLength": 2 + }, + "type": { + "description": "Contact type. See examples for a list of recognizable types", + "examples": ["email", "slack", "microsoft-teams"], + "type": "string" + }, + "contact": { + "description": "Contact value", + "examples": [ + "contact@datadoghq.com", + "https://my-org.slack.com/archives/my-channel" + ], + "type": "string" + } + }, + "if": { + "properties": { "type": { "const": "email" } } + }, + "then": { + "properties": { "contact": { "format": "email" } } + }, + "else": { + "properties": { "contact": { "format": "uri" } } + }, + "required": ["type", "contact"] + } + } +} diff --git a/__tests__/lib/__snapshots__/fieldMappings-schema.test.cjs.snap b/__tests__/lib/__snapshots__/fieldMappings-schema.test.cjs.snap index d641ec0..096498c 100644 --- a/__tests__/lib/__snapshots__/fieldMappings-schema.test.cjs.snap +++ b/__tests__/lib/__snapshots__/fieldMappings-schema.test.cjs.snap @@ -16,54 +16,82 @@ exports[`constants mappings 1`] = ` "application": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], + }, + "ci-pipeline-fingerprints": { + "v2": [Function], + "v2.1": [Function], + "v2.2": [Function], }, "contacts": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], }, "description": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], }, "docs": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], }, "integrations": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], + }, + "languages": { + "v2": [Function], + "v2.1": [Function], + "v2.2": [Function], }, "lifecycle": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], }, "links": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], }, "repos": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], }, "schema-version": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], }, "service-name": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], }, "tags": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], }, "team": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], }, "tier": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], + }, + "type": { + "v2": [Function], + "v2.1": [Function], + "v2.2": [Function], }, } `; @@ -73,15 +101,18 @@ exports[`constants schemaFields 1`] = ` "schema-version", "service-name", "team", + "application", + "description", + "tier", + "lifecycle", + "type", + "languages", "contacts", - "tags", "links", + "tags", "integrations", "docs", "repos", - "application", - "description", - "tier", - "lifecycle", + "ci-pipeline-fingerprints", ] `; diff --git a/__tests__/lib/__snapshots__/fieldMappings.test.cjs.snap b/__tests__/lib/__snapshots__/fieldMappings.test.cjs.snap index d641ec0..096498c 100644 --- a/__tests__/lib/__snapshots__/fieldMappings.test.cjs.snap +++ b/__tests__/lib/__snapshots__/fieldMappings.test.cjs.snap @@ -16,54 +16,82 @@ exports[`constants mappings 1`] = ` "application": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], + }, + "ci-pipeline-fingerprints": { + "v2": [Function], + "v2.1": [Function], + "v2.2": [Function], }, "contacts": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], }, "description": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], }, "docs": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], }, "integrations": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], + }, + "languages": { + "v2": [Function], + "v2.1": [Function], + "v2.2": [Function], }, "lifecycle": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], }, "links": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], }, "repos": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], }, "schema-version": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], }, "service-name": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], }, "tags": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], }, "team": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], }, "tier": { "v2": [Function], "v2.1": [Function], + "v2.2": [Function], + }, + "type": { + "v2": [Function], + "v2.1": [Function], + "v2.2": [Function], }, } `; @@ -73,15 +101,18 @@ exports[`constants schemaFields 1`] = ` "schema-version", "service-name", "team", + "application", + "description", + "tier", + "lifecycle", + "type", + "languages", "contacts", - "tags", "links", + "tags", "integrations", "docs", "repos", - "application", - "description", - "tier", - "lifecycle", + "ci-pipeline-fingerprints", ] `; diff --git a/__tests__/lib/__snapshots__/input-validation.test.cjs.snap b/__tests__/lib/__snapshots__/input-validation.test.cjs.snap new file mode 100644 index 0000000..56a4907 --- /dev/null +++ b/__tests__/lib/__snapshots__/input-validation.test.cjs.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`validateDatadogHostname() invalid hostnames 1`] = `"Invalid DataDog host: somethingcompletelydifferent.com. See here for more details: https://docs.datadoghq.com/getting_started/site/"`; diff --git a/__tests__/lib/input-validation.test.cjs b/__tests__/lib/input-validation.test.cjs index 313581a..c7f1295 100644 --- a/__tests__/lib/input-validation.test.cjs +++ b/__tests__/lib/input-validation.test.cjs @@ -3,7 +3,13 @@ const { validateDatadogHostname } = require('../../lib/input-validation') describe('validateDatadogHostname()', () => { test('valid hostname', () => { expect(validateDatadogHostname('app.datadoghq.com')).toBe( - 'app.datadoghq.com', + 'app.datadoghq.com' ) }) + + test('invalid hostnames', () => { + expect(() => + validateDatadogHostname('somethingcompletelydifferent.com') + ).toThrowErrorMatchingSnapshot() + }) }) diff --git a/__tests__/lib/org-rules-extra.test.cjs b/__tests__/lib/org-rules-extra.test.cjs index fa5d96b..86a6f40 100644 --- a/__tests__/lib/org-rules-extra.test.cjs +++ b/__tests__/lib/org-rules-extra.test.cjs @@ -2,7 +2,7 @@ const path = require('path') process.env.GITHUB_EVENT_PATH = path.join( __dirname, - '../data/github-context-payload.json', + '../data/github-context-payload.json' ) process.env.GITHUB_REPOSITORY = 'arcxp/datadog-service-catalog-metadata-provider' @@ -278,6 +278,70 @@ email: 'team-name-here@fakeemaildomainthatdoesntexist.com' }, ], }, + { + name: 'v2.2-languages', + orgRules: ` +--- + +org: test-org +rules: + - name: "All services" + selection: + schema-version: v2.2 + requirements: + languages: + count: 2 +`, + tests: [ + { + type: 'compliance', + inputs: ` +--- + +schema-version: v2.2 +datadog-key: FAKE_KEY +datadog-app-key: FAKE_KEY +service-name: test1 +team: Team Name Here +email: 'team-name-here@fakeemaildomainthatdoesntexist.com' +`, + expected: false, + }, + { + type: 'compliance', + inputs: ` +--- + +schema-version: v2.2 +datadog-key: FAKE_KEY +datadog-app-key: FAKE_KEY +service-name: test1 +team: Team Name Here +email: 'team-name-here@fakeemaildomainthatdoesntexist.com' +languages: + - perl +`, + expected: false, + }, + { + type: 'compliance', + inputs: ` +--- + +schema-version: v2.2 +datadog-key: FAKE_KEY +datadog-app-key: FAKE_KEY +service-name: test1 +team: Team Name Here +email: 'team-name-here@fakeemaildomainthatdoesntexist.com' +languages: + - perl + - forth +`, + expected: true, + }, + ], + }, ])('determineApplicabilityOfRule() - $name', ({ name, orgRules, tests }) => { beforeEach(() => { console.warn = jest.fn() // Remove this for debugging details diff --git a/__tests__/lib/org-rules.test.cjs b/__tests__/lib/org-rules.test.cjs index a1ac05a..8e78ba9 100644 --- a/__tests__/lib/org-rules.test.cjs +++ b/__tests__/lib/org-rules.test.cjs @@ -4,7 +4,7 @@ const path = require('path') const YAML = require('yaml') // Pulling this in here activates the mocking of the github module -const github = require('@actions/github') +require('@actions/github') // Need to use inputs for some of our parameters const core = require('@actions/core') @@ -18,20 +18,20 @@ const testLocallyOnly = require('../test-locally-only') // This is our test subject const { - fetchAndApplyOrgRules, + // fetchAndApplyOrgRules, _test: { fetchRemoteRules, ghHandle, currentOrg, - determineApplicabilityOfRule, - determineRuleCompliance, + // determineApplicabilityOfRule, + // determineRuleCompliance, applyOrgRules, }, } = require('../../lib/org-rules') process.env.GITHUB_EVENT_PATH = path.join( __dirname, - '../data/github-context-payload.json', + '../data/github-context-payload.json' ) process.env.GITHUB_REPOSITORY = 'arcxp/datadog-service-catalog-metadata-provider' @@ -53,7 +53,7 @@ describe('org-rules.js Org Rules the basics', () => { const gh = await ghHandle() expect(core.warning).toHaveBeenCalledWith( - 'No GitHub token found, org rules cannot be applied.', + 'No GitHub token found, org rules cannot be applied.' ) expect(gh).toBeUndefined() process.env.GITHUB_TOKEN = GH_TOKEN @@ -70,7 +70,7 @@ describe('org-rules.js Org Rules the basics', () => { delete process.env.GITHUB_REPOSITORY const result = currentOrg() expect(core.setFailed).toHaveBeenCalledWith( - 'This GitHub Actions environment does not have a valid context.', + 'This GitHub Actions environment does not have a valid context.' ) expect(result).toBeUndefined() @@ -118,7 +118,7 @@ integrations: | opsgenie: service_url: https://example.com region: US - `), + `) ) const serviceDefinition = await inputsToRegistryDocument() @@ -146,7 +146,7 @@ service-name: test1 team: Team Name Here email: 'team-name-here@fakeemaildomainthatdoesntexist.com' repo: foo - `), + `) ) const serviceDefinition = await inputsToRegistryDocument() @@ -186,7 +186,7 @@ integrations: | opsgenie: service_url: https://example.com region: US - `), + `) ) const serviceDefinition = await inputsToRegistryDocument() @@ -222,7 +222,7 @@ email: 'team-name-here@fakeemaildomainthatdoesntexist.com' repo: foo tags: | - data-sensitivity:critical - `), + `) ) const serviceDefinition = await inputsToRegistryDocument() @@ -262,7 +262,7 @@ integrations: | opsgenie: service_url: https://example.com region: US - `), + `) ) const serviceDefinition = await inputsToRegistryDocument() @@ -300,7 +300,7 @@ integrations: | opsgenie: service_url: https://example.com region: US - `), + `) ) const serviceDefinition = await inputsToRegistryDocument() @@ -340,7 +340,7 @@ integrations: | opsgenie: service_url: https://example.com region: US - `), + `) ) const serviceDefinition = await inputsToRegistryDocument() @@ -348,3 +348,35 @@ integrations: | expect(result).toBeTruthy() }) }) + +describe('Edge cases', () => { + const OLD_ENV = process.env + + beforeEach(() => { + jest.resetModules() // Most important - it clears the cache + process.env = { ...OLD_ENV } // Make a copy + }) + + afterAll(() => { + process.env = OLD_ENV // Restore old environment + jest.clearAllMocks() + }) + + test('should return undefined without gh', () => { + process.env['GITHUB_TOKEN'] = undefined + + expect(fetchRemoteRules()).resolves.toBeUndefined() + }) + + test('should respect runner debug', async () => { + core.debug = jest.fn() + + expect(await fetchRemoteRules()).toBeTruthy() + expect(core.debug).toHaveBeenCalledTimes(1) + + process.env['RUNNER_DEBUG'] = 1 + + expect(await fetchRemoteRules()).toBeTruthy() + expect(core.debug).toHaveBeenCalledTimes(3) + }) +}) diff --git a/__tests__/self-workflow-validation.test.cjs b/__tests__/self-workflow-validation.test.cjs index a87c242..25a8135 100644 --- a/__tests__/self-workflow-validation.test.cjs +++ b/__tests__/self-workflow-validation.test.cjs @@ -2,7 +2,7 @@ const path = require('path') process.env.GITHUB_EVENT_PATH = path.join( __dirname, - './data/github-context-payload.json', + './data/github-context-payload.json' ) process.env.GITHUB_REPOSITORY = 'arcxp/datadog-service-catalog-metadata-provider' @@ -17,40 +17,47 @@ const core = require('@actions/core') const _ = require('lodash') -const {readFile} = require('fs/promises') +const { readFile } = require('fs/promises') // This lets us get the inputs the way that they will actually come in. const { inputsToRegistryDocument, } = require('../lib/input-to-registry-document') const { - applyOrgRules, + // applyOrgRules, _test: { - fetchRemoteRules, - ghHandle, - determineApplicabilityOfRule, - determineRuleCompliance, + // fetchRemoteRules, + // ghHandle, + // determineApplicabilityOfRule, + // determineRuleCompliance, }, } = require('../lib/org-rules') const Ajv = require('ajv') -const ddSchema_v2_1 = require('./data/datadog-service-catalog-schema-v2.1.json') -const validate_v2_1 = new Ajv({ +const ddSchema_v2_2 = require('./data/datadog-service-catalog-schema-v2.2.json') +const validate_v2_2 = new Ajv({ strict: false, validateFormats: false, -}).compile(ddSchema_v2_1) +}).compile(ddSchema_v2_2) describe('Read and validate the automated testing workflow', () => { test('read and validate workflow', async () => { - const workflowContent = await readFile('.github/workflows/automated-testing.yml',{ encoding: 'utf8' }) - const parsedWorkflow = _.last(YAML.parse(workflowContent)?.jobs?.['automated-testing']?.steps)?.with + const workflowContent = await readFile( + '.github/workflows/automated-testing.yml', + { encoding: 'utf8' } + ) + const parsedWorkflow = _.last( + YAML.parse(workflowContent)?.jobs?.['automated-testing']?.steps + )?.with core.__setInputsObject(parsedWorkflow) const serviceDefinition = await inputsToRegistryDocument() - const isValid = validate_v2_1(serviceDefinition) + console.log({ parsedWorkflow, serviceDefinition }) + const isValid = validate_v2_2(serviceDefinition) if (!isValid) { - console.log(validate_v2_1.errors) + console.log(validate_v2_2.errors) + console.log(validate_v2_2) } expect(isValid).toBeTruthy() }) diff --git a/action.yml b/action.yml index 191fb0c..66a9994 100644 --- a/action.yml +++ b/action.yml @@ -75,6 +75,17 @@ inputs: description: '(v2.1 only) The current life cycle phase of the service. For example: sandbox, staging, production, deprecated' required: false + # Fields which were added in v2.2 + type: + description: 'Type of the service. Examples: "web", "db", "cache", "function", "browser", "mobile", "custom"' + required: false + languages: + description: 'A list of programming languages used.' + required: false + ci-pipeline-fingerprints: + description: 'A set of CI pipeline fingerprints related to the service' + required: false + # These are convenience inputs which are unique to this action. email: description: 'The email address of the team responsible for the service' @@ -84,4 +95,4 @@ inputs: required: false repo: description: 'The repository URL for the service. This is a convenience input for when you only have one repository for the service.' - required: false \ No newline at end of file + required: false diff --git a/dist/index.cjs b/dist/index.cjs index 20be043..cfa156b 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -151,7 +151,7 @@ var require_command = __commonJS({ } }); -// node_modules/uuid/dist/esm-node/rng.js +// node_modules/@actions/core/node_modules/uuid/dist/esm-node/rng.js function rng() { if (poolPtr > rnds8Pool.length - 16) { import_crypto.default.randomFillSync(rnds8Pool); @@ -161,34 +161,34 @@ function rng() { } var import_crypto, rnds8Pool, poolPtr; var init_rng = __esm({ - "node_modules/uuid/dist/esm-node/rng.js"() { + "node_modules/@actions/core/node_modules/uuid/dist/esm-node/rng.js"() { import_crypto = __toESM(require("crypto")); rnds8Pool = new Uint8Array(256); poolPtr = rnds8Pool.length; } }); -// node_modules/uuid/dist/esm-node/regex.js +// node_modules/@actions/core/node_modules/uuid/dist/esm-node/regex.js var regex_default; var init_regex = __esm({ - "node_modules/uuid/dist/esm-node/regex.js"() { + "node_modules/@actions/core/node_modules/uuid/dist/esm-node/regex.js"() { regex_default = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; } }); -// node_modules/uuid/dist/esm-node/validate.js +// node_modules/@actions/core/node_modules/uuid/dist/esm-node/validate.js function validate(uuid) { return typeof uuid === "string" && regex_default.test(uuid); } var validate_default; var init_validate = __esm({ - "node_modules/uuid/dist/esm-node/validate.js"() { + "node_modules/@actions/core/node_modules/uuid/dist/esm-node/validate.js"() { init_regex(); validate_default = validate; } }); -// node_modules/uuid/dist/esm-node/stringify.js +// node_modules/@actions/core/node_modules/uuid/dist/esm-node/stringify.js function stringify(arr, offset = 0) { const uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); if (!validate_default(uuid)) { @@ -198,7 +198,7 @@ function stringify(arr, offset = 0) { } var byteToHex, stringify_default; var init_stringify = __esm({ - "node_modules/uuid/dist/esm-node/stringify.js"() { + "node_modules/@actions/core/node_modules/uuid/dist/esm-node/stringify.js"() { init_validate(); byteToHex = []; for (let i = 0; i < 256; ++i) { @@ -208,7 +208,7 @@ var init_stringify = __esm({ } }); -// node_modules/uuid/dist/esm-node/v1.js +// node_modules/@actions/core/node_modules/uuid/dist/esm-node/v1.js function v1(options, buf, offset) { let i = buf && offset || 0; const b = buf || new Array(16); @@ -259,7 +259,7 @@ function v1(options, buf, offset) { } var _nodeId, _clockseq, _lastMSecs, _lastNSecs, v1_default; var init_v1 = __esm({ - "node_modules/uuid/dist/esm-node/v1.js"() { + "node_modules/@actions/core/node_modules/uuid/dist/esm-node/v1.js"() { init_rng(); init_stringify(); _lastMSecs = 0; @@ -268,7 +268,7 @@ var init_v1 = __esm({ } }); -// node_modules/uuid/dist/esm-node/parse.js +// node_modules/@actions/core/node_modules/uuid/dist/esm-node/parse.js function parse(uuid) { if (!validate_default(uuid)) { throw TypeError("Invalid UUID"); @@ -295,13 +295,13 @@ function parse(uuid) { } var parse_default; var init_parse = __esm({ - "node_modules/uuid/dist/esm-node/parse.js"() { + "node_modules/@actions/core/node_modules/uuid/dist/esm-node/parse.js"() { init_validate(); parse_default = parse; } }); -// node_modules/uuid/dist/esm-node/v35.js +// node_modules/@actions/core/node_modules/uuid/dist/esm-node/v35.js function stringToBytes(str) { str = unescape(encodeURIComponent(str)); const bytes = []; @@ -346,7 +346,7 @@ function v35_default(name, version2, hashfunc) { } var DNS, URL2; var init_v35 = __esm({ - "node_modules/uuid/dist/esm-node/v35.js"() { + "node_modules/@actions/core/node_modules/uuid/dist/esm-node/v35.js"() { init_stringify(); init_parse(); DNS = "6ba7b810-9dad-11d1-80b4-00c04fd430c8"; @@ -354,7 +354,7 @@ var init_v35 = __esm({ } }); -// node_modules/uuid/dist/esm-node/md5.js +// node_modules/@actions/core/node_modules/uuid/dist/esm-node/md5.js function md5(bytes) { if (Array.isArray(bytes)) { bytes = Buffer.from(bytes); @@ -365,16 +365,16 @@ function md5(bytes) { } var import_crypto2, md5_default; var init_md5 = __esm({ - "node_modules/uuid/dist/esm-node/md5.js"() { + "node_modules/@actions/core/node_modules/uuid/dist/esm-node/md5.js"() { import_crypto2 = __toESM(require("crypto")); md5_default = md5; } }); -// node_modules/uuid/dist/esm-node/v3.js +// node_modules/@actions/core/node_modules/uuid/dist/esm-node/v3.js var v3, v3_default; var init_v3 = __esm({ - "node_modules/uuid/dist/esm-node/v3.js"() { + "node_modules/@actions/core/node_modules/uuid/dist/esm-node/v3.js"() { init_v35(); init_md5(); v3 = v35_default("v3", 48, md5_default); @@ -382,7 +382,7 @@ var init_v3 = __esm({ } }); -// node_modules/uuid/dist/esm-node/v4.js +// node_modules/@actions/core/node_modules/uuid/dist/esm-node/v4.js function v4(options, buf, offset) { options = options || {}; const rnds = options.random || (options.rng || rng)(); @@ -399,14 +399,14 @@ function v4(options, buf, offset) { } var v4_default; var init_v4 = __esm({ - "node_modules/uuid/dist/esm-node/v4.js"() { + "node_modules/@actions/core/node_modules/uuid/dist/esm-node/v4.js"() { init_rng(); init_stringify(); v4_default = v4; } }); -// node_modules/uuid/dist/esm-node/sha1.js +// node_modules/@actions/core/node_modules/uuid/dist/esm-node/sha1.js function sha1(bytes) { if (Array.isArray(bytes)) { bytes = Buffer.from(bytes); @@ -417,16 +417,16 @@ function sha1(bytes) { } var import_crypto3, sha1_default; var init_sha1 = __esm({ - "node_modules/uuid/dist/esm-node/sha1.js"() { + "node_modules/@actions/core/node_modules/uuid/dist/esm-node/sha1.js"() { import_crypto3 = __toESM(require("crypto")); sha1_default = sha1; } }); -// node_modules/uuid/dist/esm-node/v5.js +// node_modules/@actions/core/node_modules/uuid/dist/esm-node/v5.js var v5, v5_default; var init_v5 = __esm({ - "node_modules/uuid/dist/esm-node/v5.js"() { + "node_modules/@actions/core/node_modules/uuid/dist/esm-node/v5.js"() { init_v35(); init_sha1(); v5 = v35_default("v5", 80, sha1_default); @@ -434,15 +434,15 @@ var init_v5 = __esm({ } }); -// node_modules/uuid/dist/esm-node/nil.js +// node_modules/@actions/core/node_modules/uuid/dist/esm-node/nil.js var nil_default; var init_nil = __esm({ - "node_modules/uuid/dist/esm-node/nil.js"() { + "node_modules/@actions/core/node_modules/uuid/dist/esm-node/nil.js"() { nil_default = "00000000-0000-0000-0000-000000000000"; } }); -// node_modules/uuid/dist/esm-node/version.js +// node_modules/@actions/core/node_modules/uuid/dist/esm-node/version.js function version(uuid) { if (!validate_default(uuid)) { throw TypeError("Invalid UUID"); @@ -451,13 +451,13 @@ function version(uuid) { } var version_default; var init_version = __esm({ - "node_modules/uuid/dist/esm-node/version.js"() { + "node_modules/@actions/core/node_modules/uuid/dist/esm-node/version.js"() { init_validate(); version_default = version; } }); -// node_modules/uuid/dist/esm-node/index.js +// node_modules/@actions/core/node_modules/uuid/dist/esm-node/index.js var esm_node_exports = {}; __export(esm_node_exports, { NIL: () => nil_default, @@ -471,7 +471,7 @@ __export(esm_node_exports, { version: () => version_default }); var init_esm_node = __esm({ - "node_modules/uuid/dist/esm-node/index.js"() { + "node_modules/@actions/core/node_modules/uuid/dist/esm-node/index.js"() { init_v1(); init_v3(); init_v4(); @@ -18627,7 +18627,7 @@ var require_lodash = __commonJS({ } return new LodashWrapper(value); } - var baseCreate = function() { + var baseCreate = /* @__PURE__ */ function() { function object() { } return function(proto) { @@ -21934,7 +21934,7 @@ var require_lodash = __commonJS({ var gte = createRelationalOperation(function(value, other) { return value >= other; }); - var isArguments = baseIsArguments(function() { + var isArguments = baseIsArguments(/* @__PURE__ */ function() { return arguments; }()) ? baseIsArguments : function(value) { return isObjectLike(value) && hasOwnProperty.call(value, "callee") && !propertyIsEnumerable.call(value, "callee"); @@ -23703,7 +23703,7 @@ var require_directives = __commonJS({ onError("Verbatim tags must end with a >"); return verbatim; } - const [, handle, suffix] = source.match(/^(.*!)([^!]*)$/); + const [, handle, suffix] = source.match(/^(.*!)([^!]*)$/s); if (!suffix) onError(`The ${source} tag has no suffix`); const prefix = this.tags[handle]; @@ -30565,25 +30565,81 @@ var require_fieldMappings = __commonJS({ ); var mappings = { "schema-version": useSharedMappings( - ["v2", "v2.1"], + ["v2", "v2.1", "v2.2"], mapToUsing("schema-version", (input, value) => ({ + // We default to `v2` because later versions should specify the schema version. "schema-version": value ?? "v2" })) ), "service-name": useSharedMappings( - ["v2", "v2.1"], + ["v2", "v2.1", "v2.2"], mapToUsing("dd-service", passThru) ), - team: useSharedMappings(["v2", "v2.1"], mapToUsing("team", passThru)), + team: useSharedMappings(["v2", "v2.1", "v2.2"], mapToUsing("team", passThru)), + // New in v2.1 + application: Object.assign( + { + v2: versionCompatibilityError("application", "v2", ["v2.1"]) + }, + useSharedMappings(["v2.1", "v2.2"], mapToUsing("application", passThru)) + ), + // New in v2.1 + description: Object.assign( + { + v2: versionCompatibilityError("description", "v2", ["v2.1"]) + }, + useSharedMappings(["v2.1", "v2.2"], mapToUsing("description", passThru)) + ), + // New in v2.1 + tier: Object.assign( + { + v2: versionCompatibilityError("tier", "v2", ["v2.1"]) + }, + useSharedMappings(["v2.1", "v2.2"], mapToUsing("tier", passThru)) + ), + // New in v2.1 + lifecycle: Object.assign( + { + v2: versionCompatibilityError("lifecycle", "v2", ["v2.1"]) + }, + useSharedMappings(["v2.1", "v2.2"], mapToUsing("lifecycle", passThru)) + ), + // New in v2.2 + type: { + v2: versionCompatibilityError("type", "v2", ["v2.2"]), + "v2.1": versionCompatibilityError("type", "v2.1", ["v2.2"]), + "v2.2": mapToUsing("type", passThru) + }, + // New in v2.2 + languages: { + v2: versionCompatibilityError("languages", "v2", ["v2.2"]), + "v2.1": versionCompatibilityError("languages", "v2.1", ["v2.2"]), + "v2.2": mapToUsing("languages", arrayYamlParse) + }, contacts: useSharedMappings( - ["v2", "v2.1"], + ["v2", "v2.1", "v2.2"], mapToUsing("contacts", arrayYamlParse) ), + links: Object.assign( + { + v2: (input) => ({ + links: forceArray(expandObjectInputs(input)).map( + (x) => ( + // v2 doesn't have a provider field + _.omit(x, ["provider"]) + ) + ) + }) + }, + useSharedMappings(["v2.1", "v2.2"], (input) => ({ + links: forceArray(expandObjectInputs(input)) + })) + ), // This tags setup is a little hairy, but the biggest thing // to keep in mind is that we want a list of strings, made up // of colon-separated values. Mercifully, this is the same // for both v2 and v2.1. - tags: useSharedMappings(["v2", "v2.1"], (input) => ({ + tags: useSharedMappings(["v2", "v2.1", "v2.2"], (input) => ({ tags: forceArray(expandObjectInputs(input)).map( (entry) => _.isPlainObject(entry) ? _.join( _.head(_.toPairs(entry)).map( @@ -30597,44 +30653,34 @@ var require_fieldMappings = __commonJS({ ) : entry ) })), - links: { - v2: (input) => ({ - links: forceArray(expandObjectInputs(input)).map( - (x) => ( - // v2 doesn't have a provider field - _.omit(x, ["provider"]) - ) - ) - }), - "v2.1": (input) => ({ links: forceArray(expandObjectInputs(input)) }) - }, integrations: useSharedMappings( - ["v2", "v2.1"], + ["v2", "v2.1", "v2.2"], mapToUsing("integrations", objectYamlParse) ), - docs: { - v2: mapToUsing("docs", arrayYamlParse), - "v2.1": versionCompatibilityError("docs", "v2.1", ["v2"]) - }, - repos: { - v2: mapToUsing("repos", arrayYamlParse), - "v2.1": versionCompatibilityError("repos", "v2.1", ["v2"]) - }, - application: { - v2: versionCompatibilityError("application", "v2", ["v2.1"]), - "v2.1": mapToUsing("application", passThru) - }, - description: { - v2: versionCompatibilityError("description", "v2", ["v2.1"]), - "v2.1": mapToUsing("description", passThru) - }, - tier: { - v2: versionCompatibilityError("tier", "v2", ["v2.1"]), - "v2.1": mapToUsing("tier", passThru) - }, - lifecycle: { - v2: versionCompatibilityError("lifecycle", "v2", ["v2.1"]), - "v2.1": mapToUsing("lifecycle", passThru) + docs: Object.assign( + { + v2: mapToUsing("docs", arrayYamlParse) + }, + useSharedMappings( + ["v2.1", "v2.2"], + versionCompatibilityError("docs", "v2.1", ["v2"]) + ) + ), + repos: Object.assign( + { + v2: mapToUsing("repos", arrayYamlParse) + }, + useSharedMappings( + ["v2.1", "v2.2"], + versionCompatibilityError("repos", "v2.1", ["v2"]) + ) + ), + "ci-pipeline-fingerprints": { + v2: versionCompatibilityError("ci-pipeline-fingerprints", "v2", ["v2.2"]), + "v2.1": versionCompatibilityError("ci-pipeline-fingerprints", "v2.1", [ + "v2.2" + ]), + "v2.2": mapToUsing("ci-pipeline-fingerprints", arrayYamlParse) } }; Object.freeze(mappings); @@ -30653,7 +30699,7 @@ var require_fieldMappings = __commonJS({ var convenienceMappings = { // These fields map into `contacts` in the registry document. email: useSharedMappings( - ["v2", "v2.1"], + ["v2", "v2.1", "v2.2"], (input, doc) => incorporateConvenienceMapping( { contact: input, type: "email" }, doc, @@ -30661,7 +30707,7 @@ var require_fieldMappings = __commonJS({ ) ), slack: useSharedMappings( - ["v2", "v2.1"], + ["v2", "v2.1", "v2.2"], (input, doc) => incorporateConvenienceMapping( { contact: input, type: "slack" }, doc, @@ -30669,38 +30715,53 @@ var require_fieldMappings = __commonJS({ ) ), // These fields map into `repos` list in the registry document for v2, and into the `links` list in the registry document for v2.1. - repo: { - v2: (input, doc) => incorporateConvenienceMapping({ name: "Repo", url: input }, doc, "repos"), - "v2.1": (input, doc) => incorporateConvenienceMapping( - { name: "Repo", type: "repo", url: input }, - doc, - "links" + repo: Object.assign( + { + v2: (input, doc) => incorporateConvenienceMapping( + { name: "Repo", url: input }, + doc, + "repos" + ) + }, + useSharedMappings( + ["v2.1", "v2.2"], + (input, doc) => incorporateConvenienceMapping( + { name: "Repo", type: "repo", url: input }, + doc, + "links" + ) ) - }, + ), // These fields map into `integrations` in the registry document. opsgenie: useSharedMappings( - ["v2", "v2.1"], + ["v2", "v2.1", "v2.2"], (input, doc) => incorporateConvenienceMappingToObject( { opsgenie: { "service-url": input } }, doc, "integrations" ) ), - pagerduty: { - v2: (input, doc) => incorporateConvenienceMappingToObject( - { pagerduty: input }, - doc, - "integrations" - ), - "v2.1": (input, doc) => incorporateConvenienceMappingToObject( - { pagerduty: { "service-url": input } }, - doc, - "integrations" + pagerduty: Object.assign( + { + v2: (input, doc) => incorporateConvenienceMappingToObject( + { pagerduty: input }, + doc, + "integrations" + ) + }, + useSharedMappings( + ["v2.1", "v2.2"], + (input, doc) => incorporateConvenienceMappingToObject( + { pagerduty: { "service-url": input } }, + doc, + "integrations" + ) ) - } + ) }; convenienceMappings["slack-support-channel"] = convenienceMappings.slack; Object.freeze(convenienceMappings); + core2.debug({ mappings, convenienceMappings }); var convenienceFields = _.keys(convenienceMappings); Object.freeze(convenienceFields); var mapField = (field, version2) => (input, doc = void 0) => (mappings?.[field]?.[version2] ?? convenienceMappings?.[field]?.[version2] ?? ((_2) => core2.setFailed(`Unknown field: ${field}`)))(input, doc); @@ -34721,104 +34782,12 @@ var require_github = __commonJS({ } }); -// node_modules/@octokit/plugin-request-log/dist-node/index.js -var require_dist_node11 = __commonJS({ - "node_modules/@octokit/plugin-request-log/dist-node/index.js"(exports2, module2) { - "use strict"; - var __defProp2 = Object.defineProperty; - var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor; - var __getOwnPropNames2 = Object.getOwnPropertyNames; - var __hasOwnProp2 = Object.prototype.hasOwnProperty; - var __export2 = (target, all) => { - for (var name in all) - __defProp2(target, name, { get: all[name], enumerable: true }); - }; - var __copyProps2 = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames2(from)) - if (!__hasOwnProp2.call(to, key) && key !== except) - __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable }); - } - return to; - }; - var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod); - var dist_src_exports = {}; - __export2(dist_src_exports, { - requestLog: () => requestLog - }); - module2.exports = __toCommonJS2(dist_src_exports); - var VERSION = "4.0.0"; - function requestLog(octokit) { - octokit.hook.wrap("request", (request, options) => { - octokit.log.debug("request", options); - const start = Date.now(); - const requestOptions = octokit.request.endpoint.parse(options); - const path = requestOptions.url.replace(options.baseUrl, ""); - return request(options).then((response) => { - octokit.log.info( - `${requestOptions.method} ${path} - ${response.status} in ${Date.now() - start}ms` - ); - return response; - }).catch((error) => { - octokit.log.info( - `${requestOptions.method} ${path} - ${error.status} in ${Date.now() - start}ms` - ); - throw error; - }); - }); - } - requestLog.VERSION = VERSION; - } -}); - -// node_modules/@octokit/rest/dist-node/index.js -var require_dist_node12 = __commonJS({ - "node_modules/@octokit/rest/dist-node/index.js"(exports2, module2) { - "use strict"; - var __defProp2 = Object.defineProperty; - var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor; - var __getOwnPropNames2 = Object.getOwnPropertyNames; - var __hasOwnProp2 = Object.prototype.hasOwnProperty; - var __export2 = (target, all) => { - for (var name in all) - __defProp2(target, name, { get: all[name], enumerable: true }); - }; - var __copyProps2 = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames2(from)) - if (!__hasOwnProp2.call(to, key) && key !== except) - __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable }); - } - return to; - }; - var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod); - var dist_src_exports = {}; - __export2(dist_src_exports, { - Octokit: () => Octokit - }); - module2.exports = __toCommonJS2(dist_src_exports); - var import_core = require_dist_node8(); - var import_plugin_request_log = require_dist_node11(); - var import_plugin_paginate_rest = require_dist_node10(); - var import_plugin_rest_endpoint_methods = require_dist_node9(); - var VERSION = "20.0.2"; - var Octokit = import_core.Octokit.plugin( - import_plugin_request_log.requestLog, - import_plugin_rest_endpoint_methods.legacyRestEndpointMethods, - import_plugin_paginate_rest.paginateRest - ).defaults({ - userAgent: `octokit-rest.js/${VERSION}` - }); - } -}); - // lib/org-rules.cjs var require_org_rules = __commonJS({ "lib/org-rules.cjs"(exports2, module2) { var YAML = require_dist(); var core2 = require_core(); var github = require_github(); - var ghRestPlugin = require_dist_node12(); var _ = require_lodash(); var DEFAULT_RULES_NAME = "service-catalog-rules.yml"; var ghHandle = async (token = void 0) => Promise.resolve().then( @@ -34894,8 +34863,6 @@ var require_org_rules = __commonJS({ } catch (err) { return core2.setFailed("Error fetching remote rules: " + err.toString()); } - core2.warning("Somehow we got here, but we shouldn't have."); - return { org: "UNKNOWN", rules: [] }; }; var selectionForTags = (tags, serviceDefinition) => { if (!_.isPlainObject(tags) || _.isEmpty(tags)) { @@ -35053,6 +35020,7 @@ var require_org_rules = __commonJS({ return true; }; var determineRuleCompliance = (rule, serviceDescription) => { + core2.debug({ rule, serviceDescription }); if (!rule || !serviceDescription) { throw new Error("Both rule and service description are required."); } @@ -35067,6 +35035,8 @@ var require_org_rules = __commonJS({ description: makeSimpleStringFieldComplianceChecker("description"), lifecycle: makeSimpleStringFieldComplianceChecker("lifecycle"), tier: makeSimpleStringFieldComplianceChecker("tier"), + type: makeSimpleStringFieldComplianceChecker("type"), + languages: makeComplianceCheck_countOnly("count", "languages.length"), // Everything else can use these higher-order functions. links: makeComplianceCheck_valueMatchAndCount( "type", @@ -35147,7 +35117,9 @@ var require_org_rules = __commonJS({ } return remoteOrgRules; }).then( - (remoteOrgRules) => Promise.resolve(!!remoteOrgRules ? applyOrgRules(serviceDescription, remoteOrgRules) : true) + (remoteOrgRules) => Promise.resolve( + !!remoteOrgRules ? applyOrgRules(serviceDescription, remoteOrgRules) : true + ) ).catch((err) => { core2.warning("Failing with error: " + err); return Promise.reject(err); diff --git a/lib/fieldMappings.cjs b/lib/fieldMappings.cjs index 8053563..73eae9a 100644 --- a/lib/fieldMappings.cjs +++ b/lib/fieldMappings.cjs @@ -76,8 +76,8 @@ const versionCompatibilityError = (field, chosenVersion, validVersions) => (_input) => core.setFailed( `Sorry, but the «${field}» field is not avaiable in version ${chosenVersion} of the Datadog Service Catalog schema; this field is only available in version(s): ${validVersions.join( - ',', - )}`, + ',' + )}` ) /** @@ -89,86 +89,135 @@ const versionCompatibilityError = **/ const mappings = { 'schema-version': useSharedMappings( - ['v2', 'v2.1'], + ['v2', 'v2.1', 'v2.2'], mapToUsing('schema-version', (input, value) => ({ + // We default to `v2` because later versions should specify the schema version. 'schema-version': value ?? 'v2', - })), + })) ), 'service-name': useSharedMappings( - ['v2', 'v2.1'], - mapToUsing('dd-service', passThru), + ['v2', 'v2.1', 'v2.2'], + mapToUsing('dd-service', passThru) ), - team: useSharedMappings(['v2', 'v2.1'], mapToUsing('team', passThru)), + team: useSharedMappings(['v2', 'v2.1', 'v2.2'], mapToUsing('team', passThru)), + + // New in v2.1 + application: Object.assign( + { + v2: versionCompatibilityError('application', 'v2', ['v2.1']), + }, + useSharedMappings(['v2.1', 'v2.2'], mapToUsing('application', passThru)) + ), + + // New in v2.1 + description: Object.assign( + { + v2: versionCompatibilityError('description', 'v2', ['v2.1']), + }, + useSharedMappings(['v2.1', 'v2.2'], mapToUsing('description', passThru)) + ), + + // New in v2.1 + tier: Object.assign( + { + v2: versionCompatibilityError('tier', 'v2', ['v2.1']), + }, + useSharedMappings(['v2.1', 'v2.2'], mapToUsing('tier', passThru)) + ), + + // New in v2.1 + lifecycle: Object.assign( + { + v2: versionCompatibilityError('lifecycle', 'v2', ['v2.1']), + }, + useSharedMappings(['v2.1', 'v2.2'], mapToUsing('lifecycle', passThru)) + ), + + // New in v2.2 + type: { + v2: versionCompatibilityError('type', 'v2', ['v2.2']), + 'v2.1': versionCompatibilityError('type', 'v2.1', ['v2.2']), + 'v2.2': mapToUsing('type', passThru), + }, + + // New in v2.2 + languages: { + v2: versionCompatibilityError('languages', 'v2', ['v2.2']), + 'v2.1': versionCompatibilityError('languages', 'v2.1', ['v2.2']), + 'v2.2': mapToUsing('languages', arrayYamlParse), + }, contacts: useSharedMappings( - ['v2', 'v2.1'], - mapToUsing('contacts', arrayYamlParse), + ['v2', 'v2.1', 'v2.2'], + mapToUsing('contacts', arrayYamlParse) + ), + + links: Object.assign( + { + v2: (input) => ({ + links: forceArray(expandObjectInputs(input)).map((x) => + // v2 doesn't have a provider field + _.omit(x, ['provider']) + ), + }), + }, + useSharedMappings(['v2.1', 'v2.2'], (input) => ({ + links: forceArray(expandObjectInputs(input)), + })) ), // This tags setup is a little hairy, but the biggest thing // to keep in mind is that we want a list of strings, made up // of colon-separated values. Mercifully, this is the same // for both v2 and v2.1. - tags: useSharedMappings(['v2', 'v2.1'], (input) => ({ + tags: useSharedMappings(['v2', 'v2.1', 'v2.2'], (input) => ({ tags: forceArray(expandObjectInputs(input)).map((entry) => _.isPlainObject(entry) ? _.join( _.head(_.toPairs(entry)).map((x) => // This check is so that we trim strings, but don't break // numbers or boolean values. - typeof x === 'string' ? x.trim() : x, + typeof x === 'string' ? x.trim() : x ), - ':', + ':' ) - : entry, + : entry ), })), - links: { - v2: (input) => ({ - links: forceArray(expandObjectInputs(input)).map((x) => - // v2 doesn't have a provider field - _.omit(x, ['provider']), - ), - }), - 'v2.1': (input) => ({ links: forceArray(expandObjectInputs(input)) }), - }, - integrations: useSharedMappings( - ['v2', 'v2.1'], - mapToUsing('integrations', objectYamlParse), + ['v2', 'v2.1', 'v2.2'], + mapToUsing('integrations', objectYamlParse) ), - docs: { - v2: mapToUsing('docs', arrayYamlParse), - 'v2.1': versionCompatibilityError('docs', 'v2.1', ['v2']), - }, - - repos: { - v2: mapToUsing('repos', arrayYamlParse), - 'v2.1': versionCompatibilityError('repos', 'v2.1', ['v2']), - }, - - application: { - v2: versionCompatibilityError('application', 'v2', ['v2.1']), - 'v2.1': mapToUsing('application', passThru), - }, - - description: { - v2: versionCompatibilityError('description', 'v2', ['v2.1']), - 'v2.1': mapToUsing('description', passThru), - }, + docs: Object.assign( + { + v2: mapToUsing('docs', arrayYamlParse), + }, + useSharedMappings( + ['v2.1', 'v2.2'], + versionCompatibilityError('docs', 'v2.1', ['v2']) + ) + ), - tier: { - v2: versionCompatibilityError('tier', 'v2', ['v2.1']), - 'v2.1': mapToUsing('tier', passThru), - }, + repos: Object.assign( + { + v2: mapToUsing('repos', arrayYamlParse), + }, + useSharedMappings( + ['v2.1', 'v2.2'], + versionCompatibilityError('repos', 'v2.1', ['v2']) + ) + ), - lifecycle: { - v2: versionCompatibilityError('lifecycle', 'v2', ['v2.1']), - 'v2.1': mapToUsing('lifecycle', passThru), + 'ci-pipeline-fingerprints': { + v2: versionCompatibilityError('ci-pipeline-fingerprints', 'v2', ['v2.2']), + 'v2.1': versionCompatibilityError('ci-pipeline-fingerprints', 'v2.1', [ + 'v2.2', + ]), + 'v2.2': mapToUsing('ci-pipeline-fingerprints', arrayYamlParse), }, } Object.freeze(mappings) @@ -203,60 +252,72 @@ const incorporateConvenienceMappingToObject = (inputObj, doc, targetObject) => { **/ const convenienceMappings = { // These fields map into `contacts` in the registry document. - email: useSharedMappings(['v2', 'v2.1'], (input, doc) => + email: useSharedMappings(['v2', 'v2.1', 'v2.2'], (input, doc) => incorporateConvenienceMapping( { contact: input, type: 'email' }, doc, - 'contacts', - ), + 'contacts' + ) ), - slack: useSharedMappings(['v2', 'v2.1'], (input, doc) => + slack: useSharedMappings(['v2', 'v2.1', 'v2.2'], (input, doc) => incorporateConvenienceMapping( { contact: input, type: 'slack' }, doc, - 'contacts', - ), + 'contacts' + ) ), // These fields map into `repos` list in the registry document for v2, and into the `links` list in the registry document for v2.1. - repo: { - v2: (input, doc) => - incorporateConvenienceMapping({ name: 'Repo', url: input }, doc, 'repos'), - 'v2.1': (input, doc) => + repo: Object.assign( + { + v2: (input, doc) => + incorporateConvenienceMapping( + { name: 'Repo', url: input }, + doc, + 'repos' + ), + }, + useSharedMappings(['v2.1', 'v2.2'], (input, doc) => incorporateConvenienceMapping( { name: 'Repo', type: 'repo', url: input }, doc, - 'links', - ), - }, + 'links' + ) + ) + ), // These fields map into `integrations` in the registry document. - opsgenie: useSharedMappings(['v2', 'v2.1'], (input, doc) => + opsgenie: useSharedMappings(['v2', 'v2.1', 'v2.2'], (input, doc) => incorporateConvenienceMappingToObject( { opsgenie: { 'service-url': input } }, doc, - 'integrations', - ), + 'integrations' + ) ), - pagerduty: { - v2: (input, doc) => - incorporateConvenienceMappingToObject( - { pagerduty: input }, - doc, - 'integrations', - ), - 'v2.1': (input, doc) => + pagerduty: Object.assign( + { + v2: (input, doc) => + incorporateConvenienceMappingToObject( + { pagerduty: input }, + doc, + 'integrations' + ), + }, + useSharedMappings(['v2.1', 'v2.2'], (input, doc) => incorporateConvenienceMappingToObject( { pagerduty: { 'service-url': input } }, doc, - 'integrations', - ), - }, + 'integrations' + ) + ) + ), } convenienceMappings['slack-support-channel'] = convenienceMappings.slack Object.freeze(convenienceMappings) +core.debug({ mappings, convenienceMappings }) + /** * This is the list of fields which are convenience fields, which are mapped to other fields in the registry document. * @type {string[]} diff --git a/lib/org-rules.cjs b/lib/org-rules.cjs index 4cb7bce..95852b3 100644 --- a/lib/org-rules.cjs +++ b/lib/org-rules.cjs @@ -7,7 +7,7 @@ const YAML = require('yaml') const core = require('@actions/core') const github = require('@actions/github') -const ghRestPlugin = require('@octokit/rest') +// const ghRestPlugin = require('@octokit/rest') const _ = require('lodash') /** @@ -31,12 +31,12 @@ const ghHandle = async (token = undefined) => Promise.resolve() .then( () => - token || core.getInput('github-token') || process.env['GITHUB_TOKEN'], + token || core.getInput('github-token') || process.env['GITHUB_TOKEN'] ) .then((token) => !!token && token.length > 0 ? github.getOctokit(token, {}) - : core.warning('No GitHub token found, org rules cannot be applied.'), + : core.warning('No GitHub token found, org rules cannot be applied.') ) /** @@ -53,7 +53,7 @@ const currentOrg = (gh = undefined) => { } catch (err) { core.error(`Unable to determine current organization or owner: ${err}`) core.setFailed( - 'This GitHub Actions environment does not have a valid context.', + 'This GitHub Actions environment does not have a valid context.' ) } @@ -71,7 +71,7 @@ const currentOrg = (gh = undefined) => { */ const fetchRemoteRules = async ( gh = undefined, - rulesFileName = DEFAULT_RULES_NAME, + rulesFileName = DEFAULT_RULES_NAME ) => { try { const octokit = gh ?? (await ghHandle()) @@ -104,7 +104,7 @@ const fetchRemoteRules = async ( }) if (!data) { core.debug( - `The Org Rules File "${rulesFileName}" in the «${orgName}/.github» repository appears to contain no content.`, + `The Org Rules File "${rulesFileName}" in the «${orgName}/.github» repository appears to contain no content.` ) return defaultPayload } @@ -115,21 +115,21 @@ const fetchRemoteRules = async ( `Org Rules File "${rulesFileName}" contents: ${JSON.stringify( data, undefined, - 2, - )}`, + 2 + )}` ) } // Start parsing the rules file. const orgRulesFileContents = YAML.parse( decodeURIComponent( - Buffer.from(data.content, data.encoding ?? 'base64').toString(), - ), + Buffer.from(data.content, data.encoding ?? 'base64').toString() + ) ) if (!orgRulesFileContents || typeof orgRulesFileContents !== 'object') { return core.setFailed( - `Org Rules File "${rulesFileName}" failed to parse.`, + `Org Rules File "${rulesFileName}" failed to parse.` ) } @@ -138,7 +138,7 @@ const fetchRemoteRules = async ( orgName?.toLocaleLowerCase() ) { return core.warning( - `Org ${orgName} does not match the org in the Org Rules File. This isn't fatal, but it might be an indication that you're using the wrong Org Rules File.`, + `Org ${orgName} does not match the org in the Org Rules File. This isn't fatal, but it might be an indication that you're using the wrong Org Rules File.` ) } @@ -146,9 +146,6 @@ const fetchRemoteRules = async ( } catch (err) { return core.setFailed('Error fetching remote rules: ' + err.toString()) } - - core.warning("Somehow we got here, but we shouldn't have.") - return { org: 'UNKNOWN', rules: [] } } /** @@ -168,7 +165,7 @@ const selectionForTags = (tags, serviceDefinition) => { for (const [tagKey, tagValue] of Object.entries(tags)) { const foundTag = serviceDefinition?.tags?.find((tag) => - _.startsWith(tag.toLocaleLowerCase(), tagKey.toLocaleLowerCase()), + _.startsWith(tag.toLocaleLowerCase(), tagKey.toLocaleLowerCase()) ) || undefined if (!foundTag) { @@ -195,7 +192,7 @@ const caseSensitiveFieldListMatch = } if (!Array.isArray(value)) { core.warning( - `Invalid value for ${fieldName}: ${value}; this should be either 'all' or an array of acceptable values.`, + `Invalid value for ${fieldName}: ${value}; this should be either 'all' or an array of acceptable values.` ) } @@ -250,8 +247,8 @@ const determineApplicabilityOfRule = (rule, serviceDescription) => { if (!selectionCheckers[key]) { throw new Error( `Field "${key}" is not a valid for selection criteria, only ${selectableFields.join( - ', ', - )} are supported.`, + ', ' + )} are supported.` ) } @@ -272,7 +269,7 @@ const determineApplicabilityOfRule = (rule, serviceDescription) => { */ const makeComplianceCheck_countOnly = ( locationOfCountInRequirement, - locationOfCountInServiceDefinition, + locationOfCountInServiceDefinition ) => { const countField_req = (requirement) => _.get(requirement, locationOfCountInRequirement, undefined) @@ -307,7 +304,7 @@ const makeComplianceCheck_valueMatchAndCount = ( locationOfCountInRequirement, locationOfFieldListInServiceDefinition, locationOfMatchInField, - locationOfCountInServiceDefinition, + locationOfCountInServiceDefinition ) => { const matchField_req = (requirement) => _.get(requirement, locationOfMatchInRequirement, undefined) @@ -317,7 +314,7 @@ const makeComplianceCheck_valueMatchAndCount = ( _.get(field, locationOfMatchInField, undefined) const countEnforcer = makeComplianceCheck_countOnly( locationOfCountInRequirement, - locationOfCountInServiceDefinition, + locationOfCountInServiceDefinition ) return (requirement, serviceDefinition) => { @@ -333,7 +330,7 @@ const makeComplianceCheck_valueMatchAndCount = ( if ( permittedValues.length && !sd_list.find((value) => - _.includes(permittedValues, matchField_sd(value).toLocaleLowerCase()), + _.includes(permittedValues, matchField_sd(value).toLocaleLowerCase()) ) ) { return false @@ -396,14 +393,14 @@ const checkTagsCompliance = (requirement, serviceDescription) => { ...(serviceDescription?.tags || []).map((tag) => { const [tagKey, tagValue] = tag.toLocaleLowerCase().split(/\s*?:\s*?/) return { [tagKey]: tagValue } - }), + }) ) const nonCompliantTags = _.filter(requiredTags, (tagObj) => { const [tagName, tagValue] = _.head(Object.entries(tagObj)) validTagValues = (Array.isArray(tagValue) ? tagValue : [tagValue]).map( - (x) => (typeof x === 'string' ? x.toLocaleLowerCase() : x), + (x) => (typeof x === 'string' ? x.toLocaleLowerCase() : x) ) return tagValue === 'ANY' @@ -461,6 +458,7 @@ const checkIntegrationsCompliance = (requirement, serviceDescription) => { * @throws {Error} - If the rule or service description are invalid. */ const determineRuleCompliance = (rule, serviceDescription) => { + core.debug({ rule, serviceDescription }) if (!rule || !serviceDescription) { throw new Error('Both rule and service description are required.') } @@ -482,6 +480,8 @@ const determineRuleCompliance = (rule, serviceDescription) => { description: makeSimpleStringFieldComplianceChecker('description'), lifecycle: makeSimpleStringFieldComplianceChecker('lifecycle'), tier: makeSimpleStringFieldComplianceChecker('tier'), + type: makeSimpleStringFieldComplianceChecker('type'), + languages: makeComplianceCheck_countOnly('count', 'languages.length'), // Everything else can use these higher-order functions. links: makeComplianceCheck_valueMatchAndCount( @@ -489,21 +489,21 @@ const determineRuleCompliance = (rule, serviceDescription) => { 'count', 'links', 'type', - 'links.length', + 'links.length' ), docs: makeComplianceCheck_valueMatchAndCount( 'provider', 'count', 'docs', 'provider', - 'docs.length', + 'docs.length' ), contacts: makeComplianceCheck_valueMatchAndCount( 'type', 'count', 'contacts', 'type', - 'contacts.length', + 'contacts.length' ), repos: makeComplianceCheck_countOnly('count', 'repos.length'), } @@ -512,7 +512,7 @@ const determineRuleCompliance = (rule, serviceDescription) => { _.each(rule?.requirements, (reqValue, reqName) => { if (!complianceCheckers[reqName]) { throw new Error( - `Field "${reqName}" is not available for requirements. Please see the documentation for available fields.`, + `Field "${reqName}" is not available for requirements. Please see the documentation for available fields.` ) } @@ -526,8 +526,8 @@ const determineRuleCompliance = (rule, serviceDescription) => { `Fields out of compliance: ${JSON.stringify( fieldsOutOfCompliance, undefined, - 2, - )}`, + 2 + )}` ) return fieldsOutOfCompliance.length === 0 @@ -547,7 +547,7 @@ const determineRuleCompliance = (rule, serviceDescription) => { const applyOrgRules = (serviceDescription, orgRules) => { const rules = orgRules?.rules || [] const brokenRules = rules.filter( - (rule) => !determineRuleCompliance(rule, serviceDescription), + (rule) => !determineRuleCompliance(rule, serviceDescription) ) if (brokenRules.length > 0) { @@ -555,8 +555,8 @@ const applyOrgRules = (serviceDescription, orgRules) => { `The service description violates the following rules: ${JSON.stringify( brokenRules, undefined, - 2, - )}`, + 2 + )}` ) return false } @@ -579,8 +579,8 @@ const fetchAndApplyOrgRules = (serviceDescription) => .then((gh) => fetchRemoteRules( gh, - core.getInput('org-rules-file') || DEFAULT_RULES_NAME, - ), + core.getInput('org-rules-file') || DEFAULT_RULES_NAME + ) ) .then((remoteOrgRules) => { if (!remoteOrgRules) { @@ -590,16 +590,18 @@ const fetchAndApplyOrgRules = (serviceDescription) => `Rules found for the organization "${currentOrg()}": ${JSON.stringify( remoteOrgRules, undefined, - 2, - )}`, + 2 + )}` ) } return remoteOrgRules }) .then((remoteOrgRules) => - Promise.resolve(!!remoteOrgRules - ? applyOrgRules(serviceDescription, remoteOrgRules) - : true) + Promise.resolve( + !!remoteOrgRules + ? applyOrgRules(serviceDescription, remoteOrgRules) + : true + ) ) .catch((err) => { core.warning('Failing with error: ' + err) diff --git a/package-lock.json b/package-lock.json index 7e0ea58..bd42168 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@arcxp/datadog-service-catalog-metadata-provider", - "version": "2.1.0", + "version": "2.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@arcxp/datadog-service-catalog-metadata-provider", - "version": "2.1.0", + "version": "2.2.0", "license": "MIT", "dependencies": { "@actions/core": "^1.10.1", @@ -14,14 +14,15 @@ "@actions/http-client": "^2.2.0", "@octokit/rest": "^20.0.2", "lodash": "^4.17.21", - "yaml": "^2.3.3" + "uuid": "^9.0.1", + "yaml": "^2.3.4" }, "devDependencies": { - "@types/jest": "^29.5.6", + "@types/jest": "^29.5.11", "ajv": "^8.12.0", - "esbuild": "0.19.5", + "esbuild": "0.19.10", "jest": "^29.7.0", - "prettier": "^3.0.3" + "prettier": "^3.1.1" } }, "node_modules/@actions/core": { @@ -33,6 +34,14 @@ "uuid": "^8.3.2" } }, + "node_modules/@actions/core/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/@actions/github": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@actions/github/-/github-6.0.0.tgz", @@ -688,10 +697,26 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.10.tgz", + "integrity": "sha512-Q+mk96KJ+FZ30h9fsJl+67IjNJm3x2eX+GBWGmocAKgzp27cowCOOqSdscX80s0SpdFXZnIv/+1xD1EctFx96Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/android-arm": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.5.tgz", - "integrity": "sha512-bhvbzWFF3CwMs5tbjf3ObfGqbl/17ict2/uwOSfr3wmxDE6VdS2GqY/FuzIPe0q0bdhj65zQsvqfArI9MY6+AA==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.10.tgz", + "integrity": "sha512-7W0bK7qfkw1fc2viBfrtAEkDKHatYfHzr/jKAHNr9BvkYDXPcC6bodtm8AyLJNNuqClLNaeTLuwURt4PRT9d7w==", "cpu": [ "arm" ], @@ -705,9 +730,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.5.tgz", - "integrity": "sha512-5d1OkoJxnYQfmC+Zd8NBFjkhyCNYwM4n9ODrycTFY6Jk1IGiZ+tjVJDDSwDt77nK+tfpGP4T50iMtVi4dEGzhQ==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.10.tgz", + "integrity": "sha512-1X4CClKhDgC3by7k8aOWZeBXQX8dHT5QAMCAQDArCLaYfkppoARvh0fit3X2Qs+MXDngKcHv6XXyQCpY0hkK1Q==", "cpu": [ "arm64" ], @@ -721,9 +746,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.5.tgz", - "integrity": "sha512-9t+28jHGL7uBdkBjL90QFxe7DVA+KGqWlHCF8ChTKyaKO//VLuoBricQCgwhOjA1/qOczsw843Fy4cbs4H3DVA==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.10.tgz", + "integrity": "sha512-O/nO/g+/7NlitUxETkUv/IvADKuZXyH4BHf/g/7laqKC4i/7whLpB0gvpPc2zpF0q9Q6FXS3TS75QHac9MvVWw==", "cpu": [ "x64" ], @@ -737,9 +762,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.5.tgz", - "integrity": "sha512-mvXGcKqqIqyKoxq26qEDPHJuBYUA5KizJncKOAf9eJQez+L9O+KfvNFu6nl7SCZ/gFb2QPaRqqmG0doSWlgkqw==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.10.tgz", + "integrity": "sha512-YSRRs2zOpwypck+6GL3wGXx2gNP7DXzetmo5pHXLrY/VIMsS59yKfjPizQ4lLt5vEI80M41gjm2BxrGZ5U+VMA==", "cpu": [ "arm64" ], @@ -753,9 +778,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.5.tgz", - "integrity": "sha512-Ly8cn6fGLNet19s0X4unjcniX24I0RqjPv+kurpXabZYSXGM4Pwpmf85WHJN3lAgB8GSth7s5A0r856S+4DyiA==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.10.tgz", + "integrity": "sha512-alfGtT+IEICKtNE54hbvPg13xGBe4GkVxyGWtzr+yHO7HIiRJppPDhOKq3zstTcVf8msXb/t4eavW3jCDpMSmA==", "cpu": [ "x64" ], @@ -769,9 +794,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.5.tgz", - "integrity": "sha512-GGDNnPWTmWE+DMchq1W8Sd0mUkL+APvJg3b11klSGUDvRXh70JqLAO56tubmq1s2cgpVCSKYywEiKBfju8JztQ==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.10.tgz", + "integrity": "sha512-dMtk1wc7FSH8CCkE854GyGuNKCewlh+7heYP/sclpOG6Cectzk14qdUIY5CrKDbkA/OczXq9WesqnPl09mj5dg==", "cpu": [ "arm64" ], @@ -785,9 +810,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.5.tgz", - "integrity": "sha512-1CCwDHnSSoA0HNwdfoNY0jLfJpd7ygaLAp5EHFos3VWJCRX9DMwWODf96s9TSse39Br7oOTLryRVmBoFwXbuuQ==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.10.tgz", + "integrity": "sha512-G5UPPspryHu1T3uX8WiOEUa6q6OlQh6gNl4CO4Iw5PS+Kg5bVggVFehzXBJY6X6RSOMS8iXDv2330VzaObm4Ag==", "cpu": [ "x64" ], @@ -801,9 +826,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.5.tgz", - "integrity": "sha512-lrWXLY/vJBzCPC51QN0HM71uWgIEpGSjSZZADQhq7DKhPcI6NH1IdzjfHkDQws2oNpJKpR13kv7/pFHBbDQDwQ==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.10.tgz", + "integrity": "sha512-j6gUW5aAaPgD416Hk9FHxn27On28H4eVI9rJ4az7oCGTFW48+LcgNDBN+9f8rKZz7EEowo889CPKyeaD0iw9Kg==", "cpu": [ "arm" ], @@ -817,9 +842,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.5.tgz", - "integrity": "sha512-o3vYippBmSrjjQUCEEiTZ2l+4yC0pVJD/Dl57WfPwwlvFkrxoSO7rmBZFii6kQB3Wrn/6GwJUPLU5t52eq2meA==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.10.tgz", + "integrity": "sha512-QxaouHWZ+2KWEj7cGJmvTIHVALfhpGxo3WLmlYfJ+dA5fJB6lDEIg+oe/0//FuyVHuS3l79/wyBxbHr0NgtxJQ==", "cpu": [ "arm64" ], @@ -833,9 +858,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.5.tgz", - "integrity": "sha512-MkjHXS03AXAkNp1KKkhSKPOCYztRtK+KXDNkBa6P78F8Bw0ynknCSClO/ztGszILZtyO/lVKpa7MolbBZ6oJtQ==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.10.tgz", + "integrity": "sha512-4ub1YwXxYjj9h1UIZs2hYbnTZBtenPw5NfXCRgEkGb0b6OJ2gpkMvDqRDYIDRjRdWSe/TBiZltm3Y3Q8SN1xNg==", "cpu": [ "ia32" ], @@ -849,9 +874,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.5.tgz", - "integrity": "sha512-42GwZMm5oYOD/JHqHska3Jg0r+XFb/fdZRX+WjADm3nLWLcIsN27YKtqxzQmGNJgu0AyXg4HtcSK9HuOk3v1Dw==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.10.tgz", + "integrity": "sha512-lo3I9k+mbEKoxtoIbM0yC/MZ1i2wM0cIeOejlVdZ3D86LAcFXFRdeuZmh91QJvUTW51bOK5W2BznGNIl4+mDaA==", "cpu": [ "loong64" ], @@ -865,9 +890,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.5.tgz", - "integrity": "sha512-kcjndCSMitUuPJobWCnwQ9lLjiLZUR3QLQmlgaBfMX23UEa7ZOrtufnRds+6WZtIS9HdTXqND4yH8NLoVVIkcg==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.10.tgz", + "integrity": "sha512-J4gH3zhHNbdZN0Bcr1QUGVNkHTdpijgx5VMxeetSk6ntdt+vR1DqGmHxQYHRmNb77tP6GVvD+K0NyO4xjd7y4A==", "cpu": [ "mips64el" ], @@ -881,9 +906,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.5.tgz", - "integrity": "sha512-yJAxJfHVm0ZbsiljbtFFP1BQKLc8kUF6+17tjQ78QjqjAQDnhULWiTA6u0FCDmYT1oOKS9PzZ2z0aBI+Mcyj7Q==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.10.tgz", + "integrity": "sha512-tgT/7u+QhV6ge8wFMzaklOY7KqiyitgT1AUHMApau32ZlvTB/+efeCtMk4eXS+uEymYK249JsoiklZN64xt6oQ==", "cpu": [ "ppc64" ], @@ -897,9 +922,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.5.tgz", - "integrity": "sha512-5u8cIR/t3gaD6ad3wNt1MNRstAZO+aNyBxu2We8X31bA8XUNyamTVQwLDA1SLoPCUehNCymhBhK3Qim1433Zag==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.10.tgz", + "integrity": "sha512-0f/spw0PfBMZBNqtKe5FLzBDGo0SKZKvMl5PHYQr3+eiSscfJ96XEknCe+JoOayybWUFQbcJTrk946i3j9uYZA==", "cpu": [ "riscv64" ], @@ -913,9 +938,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.5.tgz", - "integrity": "sha512-Z6JrMyEw/EmZBD/OFEFpb+gao9xJ59ATsoTNlj39jVBbXqoZm4Xntu6wVmGPB/OATi1uk/DB+yeDPv2E8PqZGw==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.10.tgz", + "integrity": "sha512-pZFe0OeskMHzHa9U38g+z8Yx5FNCLFtUnJtQMpwhS+r4S566aK2ci3t4NCP4tjt6d5j5uo4h7tExZMjeKoehAA==", "cpu": [ "s390x" ], @@ -929,9 +954,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.5.tgz", - "integrity": "sha512-psagl+2RlK1z8zWZOmVdImisMtrUxvwereIdyJTmtmHahJTKb64pAcqoPlx6CewPdvGvUKe2Jw+0Z/0qhSbG1A==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.10.tgz", + "integrity": "sha512-SpYNEqg/6pZYoc+1zLCjVOYvxfZVZj6w0KROZ3Fje/QrM3nfvT2llI+wmKSrWuX6wmZeTapbarvuNNK/qepSgA==", "cpu": [ "x64" ], @@ -945,9 +970,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.5.tgz", - "integrity": "sha512-kL2l+xScnAy/E/3119OggX8SrWyBEcqAh8aOY1gr4gPvw76la2GlD4Ymf832UCVbmuWeTf2adkZDK+h0Z/fB4g==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.10.tgz", + "integrity": "sha512-ACbZ0vXy9zksNArWlk2c38NdKg25+L9pr/mVaj9SUq6lHZu/35nx2xnQVRGLrC1KKQqJKRIB0q8GspiHI3J80Q==", "cpu": [ "x64" ], @@ -961,9 +986,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.5.tgz", - "integrity": "sha512-sPOfhtzFufQfTBgRnE1DIJjzsXukKSvZxloZbkJDG383q0awVAq600pc1nfqBcl0ice/WN9p4qLc39WhBShRTA==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.10.tgz", + "integrity": "sha512-PxcgvjdSjtgPMiPQrM3pwSaG4kGphP+bLSb+cihuP0LYdZv1epbAIecHVl5sD3npkfYBZ0ZnOjR878I7MdJDFg==", "cpu": [ "x64" ], @@ -977,9 +1002,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.5.tgz", - "integrity": "sha512-dGZkBXaafuKLpDSjKcB0ax0FL36YXCvJNnztjKV+6CO82tTYVDSH2lifitJ29jxRMoUhgkg9a+VA/B03WK5lcg==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.10.tgz", + "integrity": "sha512-ZkIOtrRL8SEJjr+VHjmW0znkPs+oJXhlJbNwfI37rvgeMtk3sxOQevXPXjmAPZPigVTncvFqLMd+uV0IBSEzqA==", "cpu": [ "x64" ], @@ -993,9 +1018,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.5.tgz", - "integrity": "sha512-dWVjD9y03ilhdRQ6Xig1NWNgfLtf2o/STKTS+eZuF90fI2BhbwD6WlaiCGKptlqXlURVB5AUOxUj09LuwKGDTg==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.10.tgz", + "integrity": "sha512-+Sa4oTDbpBfGpl3Hn3XiUe4f8TU2JF7aX8cOfqFYMMjXp6ma6NJDztl5FDG8Ezx0OjwGikIHw+iA54YLDNNVfw==", "cpu": [ "arm64" ], @@ -1009,9 +1034,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.5.tgz", - "integrity": "sha512-4liggWIA4oDgUxqpZwrDhmEfAH4d0iljanDOK7AnVU89T6CzHon/ony8C5LeOdfgx60x5cnQJFZwEydVlYx4iw==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.10.tgz", + "integrity": "sha512-EOGVLK1oWMBXgfttJdPHDTiivYSjX6jDNaATeNOaCOFEVcfMjtbx7WVQwPSE1eIfCp/CaSF2nSrDtzc4I9f8TQ==", "cpu": [ "ia32" ], @@ -1025,9 +1050,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.5.tgz", - "integrity": "sha512-czTrygUsB/jlM8qEW5MD8bgYU2Xg14lo6kBDXW6HdxKjh8M5PzETGiSHaz9MtbXBYDloHNUAUW2tMiKW4KM9Mw==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.10.tgz", + "integrity": "sha512-whqLG6Sc70AbU73fFYvuYzaE4MNMBIlR1Y/IrUeOXFrWHxBEjjbZaQ3IXIQS8wJdAzue2GwYZCjOrgrU1oUHoA==", "cpu": [ "x64" ], @@ -1643,9 +1668,9 @@ } }, "node_modules/@types/jest": { - "version": "29.5.6", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.6.tgz", - "integrity": "sha512-/t9NnzkOpXb4Nfvg17ieHE6EeSjDS2SGSpNYfoLbUAeL/EOueU/RSdOWFpfQTXBEM7BguYW1XQ0EbM+6RlIh6w==", + "version": "29.5.11", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.11.tgz", + "integrity": "sha512-S2mHmYIVe13vrm6q4kN6fLYYAka15ALQki/vgDC3mIukEOx8WJlv0kQPM+d4w8Gp6u0uSdKND04IlTXBv0rwnQ==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -2222,9 +2247,9 @@ } }, "node_modules/esbuild": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.5.tgz", - "integrity": "sha512-bUxalY7b1g8vNhQKdB24QDmHeY4V4tw/s6Ak5z+jJX9laP5MoQseTOMemAr0gxssjNcH0MCViG8ONI2kksvfFQ==", + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.10.tgz", + "integrity": "sha512-S1Y27QGt/snkNYrRcswgRFqZjaTG5a5xM3EQo97uNBnH505pdzSNe/HLBq1v0RO7iK/ngdbhJB6mDAp0OK+iUA==", "dev": true, "hasInstallScript": true, "bin": { @@ -2234,28 +2259,29 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.19.5", - "@esbuild/android-arm64": "0.19.5", - "@esbuild/android-x64": "0.19.5", - "@esbuild/darwin-arm64": "0.19.5", - "@esbuild/darwin-x64": "0.19.5", - "@esbuild/freebsd-arm64": "0.19.5", - "@esbuild/freebsd-x64": "0.19.5", - "@esbuild/linux-arm": "0.19.5", - "@esbuild/linux-arm64": "0.19.5", - "@esbuild/linux-ia32": "0.19.5", - "@esbuild/linux-loong64": "0.19.5", - "@esbuild/linux-mips64el": "0.19.5", - "@esbuild/linux-ppc64": "0.19.5", - "@esbuild/linux-riscv64": "0.19.5", - "@esbuild/linux-s390x": "0.19.5", - "@esbuild/linux-x64": "0.19.5", - "@esbuild/netbsd-x64": "0.19.5", - "@esbuild/openbsd-x64": "0.19.5", - "@esbuild/sunos-x64": "0.19.5", - "@esbuild/win32-arm64": "0.19.5", - "@esbuild/win32-ia32": "0.19.5", - "@esbuild/win32-x64": "0.19.5" + "@esbuild/aix-ppc64": "0.19.10", + "@esbuild/android-arm": "0.19.10", + "@esbuild/android-arm64": "0.19.10", + "@esbuild/android-x64": "0.19.10", + "@esbuild/darwin-arm64": "0.19.10", + "@esbuild/darwin-x64": "0.19.10", + "@esbuild/freebsd-arm64": "0.19.10", + "@esbuild/freebsd-x64": "0.19.10", + "@esbuild/linux-arm": "0.19.10", + "@esbuild/linux-arm64": "0.19.10", + "@esbuild/linux-ia32": "0.19.10", + "@esbuild/linux-loong64": "0.19.10", + "@esbuild/linux-mips64el": "0.19.10", + "@esbuild/linux-ppc64": "0.19.10", + "@esbuild/linux-riscv64": "0.19.10", + "@esbuild/linux-s390x": "0.19.10", + "@esbuild/linux-x64": "0.19.10", + "@esbuild/netbsd-x64": "0.19.10", + "@esbuild/openbsd-x64": "0.19.10", + "@esbuild/sunos-x64": "0.19.10", + "@esbuild/win32-arm64": "0.19.10", + "@esbuild/win32-ia32": "0.19.10", + "@esbuild/win32-x64": "0.19.10" } }, "node_modules/escalade": { @@ -3724,9 +3750,9 @@ } }, "node_modules/prettier": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", - "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz", + "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -4186,9 +4212,13 @@ } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "bin": { "uuid": "dist/bin/uuid" } @@ -4282,9 +4312,9 @@ "dev": true }, "node_modules/yaml": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.3.tgz", - "integrity": "sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", "engines": { "node": ">= 14" } diff --git a/package.json b/package.json index 5f457ba..c209cd7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@arcxp/datadog-service-catalog-metadata-provider", - "version": "2.1.0", + "version": "2.2.0", "type": "commonjs", "description": "This is a package which provides GitHub Actions with a workflow for providing the DataDog Service Catalog Provider with information that will register your service in the Service Catalog.", "main": "index.cjs", @@ -31,13 +31,14 @@ "@actions/http-client": "^2.2.0", "@octokit/rest": "^20.0.2", "lodash": "^4.17.21", - "yaml": "^2.3.3" + "uuid": "^9.0.1", + "yaml": "^2.3.4" }, "devDependencies": { - "@types/jest": "^29.5.6", + "@types/jest": "^29.5.11", "ajv": "^8.12.0", - "esbuild": "0.19.5", + "esbuild": "0.19.10", "jest": "^29.7.0", - "prettier": "^3.0.3" + "prettier": "^3.1.1" } }