UNPKG

serverless-tag-resources

Version:

Datamart: Tag all AWS resources with dual legacy + datamart:* tag support

91 lines (75 loc) 2.77 kB
"use strict"; const { buildListTags, buildDictTags } = require("./tags"); const { classifyResource } = require("./resource-classifier"); /** * Template Tagger — Hook: before:package:finalize * * Mutates the compiled CloudFormation template to inject tags * into resource Properties before deployment. */ /** * Tag all resources in a CloudFormation resources object. * * @param {object} resources - { LogicalId: { Type, Properties, ... } } * @param {object} stackTags - from provider.stackTags * @param {string} stage - deployment stage * @param {Function} log - logging function */ function tagResources(resources, stackTags, stage, log) { if (!resources) return; for (const [logicalId, resource] of Object.entries(resources)) { const resourceType = resource.Type; if (!resourceType) continue; const classification = classifyResource(resourceType); if (classification === "skip") continue; if (!resource.Properties) { log(`TAGGING: skipping ${resourceType} (${logicalId}) — no Properties`); continue; } switch (classification) { case "list": tagListBased(resource, stackTags, stage, logicalId); break; case "dict": tagDictBased(resource, stackTags, stage, logicalId); break; case "unclassified": log(`TAGGING: WARNING — unclassified resource type ${resourceType} (${logicalId}). Attempting list-based tagging. If deploy fails, add to skipTypes.`); tagListBased(resource, stackTags, stage, logicalId); break; case "api-only": case "related": // These are tagged post-deploy via API, not in the template break; } } } /** * Apply list-based tags [{Key, Value}] to a resource. * Merges with existing tags without overwriting. */ function tagListBased(resource, stackTags, stage, logicalId) { const newTags = buildListTags(stackTags, stage, logicalId); const existing = resource.Properties.Tags || []; // Build set of existing keys (case-insensitive) const existingKeys = new Set( existing.map((t) => (t.Key || "").toLowerCase()) ); // Only add tags that don't already exist const merged = [ ...existing, ...newTags.filter((t) => !existingKeys.has(t.Key.toLowerCase())), ]; resource.Properties.Tags = merged; } /** * Apply dict-based tags {key: value} to a resource. * Merges with existing tags without overwriting. */ function tagDictBased(resource, stackTags, stage, logicalId) { const newTags = buildDictTags(stackTags, stage, logicalId); const existing = resource.Properties.Tags || {}; // Merge: existing keys take priority resource.Properties.Tags = { ...newTags, ...existing }; } module.exports = { tagResources, tagListBased, tagDictBased };