Skip to content

Commit 7d6a8d3

Browse files
Fixing partial exclusion behavior to be more robust (#1188)
Fixes an edge case with content exclusion that was exposed in this [slack thread](https://ibm-hashicorp.slack.com/archives/C09LU1THDDE/p1761569101837889?thread_ts=1761316683.936989&cid=C09LU1THDDE). Reworks directive block logic to reference its node rather than its line number since the line number references become ambiguous in use cases like this. Added in extra tests for this and also verified that none of the other files that are currently created in the build process has broken/changed.
2 parents 378f62d + 924372f commit 7d6a8d3

File tree

8 files changed

+420
-107
lines changed

8 files changed

+420
-107
lines changed

scripts/prebuild/mdx-transforms/build-mdx-transforms.test.mjs

Lines changed: 319 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ describe('applyMdxTransforms - Integration Tests', () => {
2424
],
2525
'terraform-enterprise': [
2626
{ version: 'v202409-2', releaseStage: 'stable', isLatest: true },
27+
{ version: 'v1.1.x', releaseStage: 'stable', isLatest: true },
2728
],
2829
}
2930

@@ -1244,6 +1245,324 @@ The API includes endpoints for system-level operations, such as health checks an
12441245
// Should not contain the @include directive
12451246
expect(output).not.toContain('@include')
12461247
})
1248+
1249+
test('should handle partial wrapped in json responses in TFC and TFEnterprise exclusions', async () => {
1250+
vi.spyOn(repoConfig, 'PRODUCT_CONFIG', 'get').mockReturnValue({
1251+
'terraform-enterprise': {
1252+
contentDir: 'docs',
1253+
versionedDocs: true,
1254+
supportsExclusionDirectives: true,
1255+
},
1256+
})
1257+
1258+
// This is the actual workspace-with-vcs.mdx partial content structure
1259+
const partialContent = `<!-- BEGIN: TFC:only -->
1260+
1261+
\`\`\`json
1262+
{
1263+
"data": {
1264+
"id": "ws-KTuq99JSzgmDSvYj",
1265+
"type": "workspaces",
1266+
"attributes": {
1267+
"global-remote-state": false,
1268+
"name": "workspace-2",
1269+
"vcs-repo": {
1270+
"branch": "",
1271+
"identifier": "example/terraform-test-proj"
1272+
}
1273+
}
1274+
}
1275+
}
1276+
\`\`\`
1277+
1278+
<!-- END: TFC:only -->
1279+
1280+
<!-- BEGIN: TFEnterprise:only name:project-remote-state -->
1281+
1282+
\`\`\`json
1283+
{
1284+
"data": {
1285+
"id": "ws-KTuq99JSzgmDSvYj",
1286+
"type": "workspaces",
1287+
"attributes": {
1288+
"global-remote-state": false,
1289+
"project-remote-state": false,
1290+
"name": "workspace-2",
1291+
"vcs-repo": {
1292+
"branch": "",
1293+
"identifier": "example/terraform-test-proj"
1294+
}
1295+
}
1296+
}
1297+
}
1298+
\`\`\`
1299+
1300+
<!-- END: TFEnterprise:only name:project-remote-state -->
1301+
`
1302+
1303+
const mainContent = `---
1304+
page_title: Workspaces - API Docs
1305+
---
1306+
1307+
# Workspaces API
1308+
1309+
## Sample Response
1310+
1311+
@include 'api-code-blocks/workspace-with-vcs.mdx'
1312+
1313+
Additional documentation content.
1314+
`
1315+
1316+
vol.fromJSON({
1317+
'/content/terraform-enterprise/v1.1.x/docs/api-docs/workspaces.mdx':
1318+
mainContent,
1319+
'/content/terraform-enterprise/v1.1.x/docs/partials/api-code-blocks/workspace-with-vcs.mdx':
1320+
partialContent,
1321+
})
1322+
1323+
await buildMdxTransforms('/content', '/output', mockVersionMetadata)
1324+
1325+
const output = fs.readFileSync(
1326+
'/output/terraform-enterprise/v1.1.x/docs/api-docs/workspaces.mdx',
1327+
'utf8',
1328+
)
1329+
1330+
// TFC:only content should be removed in terraform-enterprise
1331+
expect(output).not.toContain('<!-- BEGIN: TFC:only -->')
1332+
expect(output).not.toContain('<!-- END: TFC:only -->')
1333+
1334+
// TFEnterprise:only content should be kept in terraform-enterprise
1335+
expect(output).toContain('"project-remote-state": false')
1336+
expect(output).toContain(
1337+
'<!-- BEGIN: TFEnterprise:only name:project-remote-state -->',
1338+
)
1339+
expect(output).toContain(
1340+
'<!-- END: TFEnterprise:only name:project-remote-state -->',
1341+
)
1342+
1343+
// Main content should be preserved
1344+
expect(output).toContain('# Workspaces API')
1345+
expect(output).toContain('## Sample Response')
1346+
expect(output).toContain('Additional documentation content')
1347+
})
1348+
1349+
test('should handle workspace-with-vcs partial in terraform-docs-common (keeps TFC:only)', async () => {
1350+
vi.spyOn(repoConfig, 'PRODUCT_CONFIG', 'get').mockReturnValue({
1351+
'terraform-docs-common': {
1352+
versionedDocs: true,
1353+
basePaths: ['docs'],
1354+
supportsExclusionDirectives: true,
1355+
},
1356+
})
1357+
1358+
const partialContent = `<!-- BEGIN: TFC:only -->
1359+
1360+
\`\`\`json
1361+
{
1362+
"data": {
1363+
"attributes": {
1364+
"global-remote-state": false,
1365+
"name": "workspace-2"
1366+
}
1367+
}
1368+
}
1369+
\`\`\`
1370+
1371+
<!-- END: TFC:only -->
1372+
1373+
<!-- BEGIN: TFEnterprise:only name:project-remote-state -->
1374+
1375+
\`\`\`json
1376+
{
1377+
"data": {
1378+
"attributes": {
1379+
"project-remote-state": false,
1380+
"name": "workspace-2"
1381+
}
1382+
}
1383+
}
1384+
\`\`\`
1385+
1386+
<!-- END: TFEnterprise:only name:project-remote-state -->
1387+
`
1388+
1389+
const mainContent = `---
1390+
page_title: Workspaces - API Docs
1391+
---
1392+
1393+
# Workspaces API
1394+
1395+
@include 'workspace-with-vcs.mdx'
1396+
1397+
More content.
1398+
`
1399+
1400+
vol.fromJSON({
1401+
'/content/terraform-docs-common/v1.20.x/docs/workspaces.mdx':
1402+
mainContent,
1403+
'/content/terraform-docs-common/v1.20.x/docs/partials/workspace-with-vcs.mdx':
1404+
partialContent,
1405+
})
1406+
1407+
await buildMdxTransforms('/content', '/output', mockVersionMetadata)
1408+
1409+
const output = fs.readFileSync(
1410+
'/output/terraform-docs-common/v1.20.x/docs/workspaces.mdx',
1411+
'utf8',
1412+
)
1413+
1414+
// TFC:only content should be kept in terraform-docs-common
1415+
expect(output).toContain('"global-remote-state": false')
1416+
expect(output).toContain('<!-- BEGIN: TFC:only -->')
1417+
expect(output).toContain('<!-- END: TFC:only -->')
1418+
1419+
// TFEnterprise:only content should be removed in terraform-docs-common
1420+
expect(output).not.toContain('"project-remote-state": false')
1421+
expect(output).not.toContain(
1422+
'<!-- BEGIN: TFEnterprise:only name:project-remote-state -->',
1423+
)
1424+
1425+
// Main content should be preserved
1426+
expect(output).toContain('# Workspaces API')
1427+
expect(output).toContain('More content')
1428+
})
1429+
1430+
test('should handle multiple partials with same directive name in sequence', async () => {
1431+
vi.spyOn(repoConfig, 'PRODUCT_CONFIG', 'get').mockReturnValue({
1432+
'terraform-enterprise': {
1433+
contentDir: 'docs',
1434+
versionedDocs: true,
1435+
supportsExclusionDirectives: true,
1436+
},
1437+
})
1438+
1439+
// First partial with TFEnterprise:only directive
1440+
const workspacePartial = `<!-- BEGIN: TFC:only -->
1441+
1442+
\`\`\`json
1443+
{
1444+
"data": {
1445+
"attributes": {
1446+
"name": "workspace-1-tfc"
1447+
}
1448+
}
1449+
}
1450+
\`\`\`
1451+
1452+
<!-- END: TFC:only -->
1453+
1454+
<!-- BEGIN: TFEnterprise:only name:project-remote-state -->
1455+
1456+
\`\`\`json
1457+
{
1458+
"data": {
1459+
"attributes": {
1460+
"name": "workspace-1-tfe",
1461+
"project-remote-state": false
1462+
}
1463+
}
1464+
}
1465+
\`\`\`
1466+
1467+
<!-- END: TFEnterprise:only name:project-remote-state -->
1468+
`
1469+
1470+
// Second partial with the SAME TFEnterprise:only directive name
1471+
const workspaceWithVcsPartial = `<!-- BEGIN: TFC:only -->
1472+
1473+
\`\`\`json
1474+
{
1475+
"data": {
1476+
"attributes": {
1477+
"name": "workspace-2-tfc",
1478+
"vcs-repo": {
1479+
"identifier": "org/repo"
1480+
}
1481+
}
1482+
}
1483+
}
1484+
\`\`\`
1485+
1486+
<!-- END: TFC:only -->
1487+
1488+
<!-- BEGIN: TFEnterprise:only name:project-remote-state -->
1489+
1490+
\`\`\`json
1491+
{
1492+
"data": {
1493+
"attributes": {
1494+
"name": "workspace-2-tfe",
1495+
"project-remote-state": false,
1496+
"vcs-repo": {
1497+
"identifier": "org/repo"
1498+
}
1499+
}
1500+
}
1501+
}
1502+
\`\`\`
1503+
1504+
<!-- END: TFEnterprise:only name:project-remote-state -->
1505+
`
1506+
1507+
const mainContent = `---
1508+
page_title: Workspaces - API Docs
1509+
---
1510+
1511+
# Workspaces API
1512+
1513+
## Sample Response
1514+
1515+
_Without a VCS repository_
1516+
1517+
@include 'api-code-blocks/workspace.mdx'
1518+
1519+
_With a VCS repository_
1520+
1521+
@include 'api-code-blocks/workspace-with-vcs.mdx'
1522+
1523+
Additional documentation content.
1524+
`
1525+
1526+
vol.fromJSON({
1527+
'/content/terraform-enterprise/v1.1.x/docs/api-docs/workspaces.mdx':
1528+
mainContent,
1529+
'/content/terraform-enterprise/v1.1.x/docs/partials/api-code-blocks/workspace.mdx':
1530+
workspacePartial,
1531+
'/content/terraform-enterprise/v1.1.x/docs/partials/api-code-blocks/workspace-with-vcs.mdx':
1532+
workspaceWithVcsPartial,
1533+
})
1534+
1535+
await buildMdxTransforms('/content', '/output', mockVersionMetadata)
1536+
1537+
const output = fs.readFileSync(
1538+
'/output/terraform-enterprise/v1.1.x/docs/api-docs/workspaces.mdx',
1539+
'utf8',
1540+
)
1541+
1542+
// TFC:only content should be removed in terraform-enterprise
1543+
expect(output).not.toContain('workspace-1-tfc')
1544+
expect(output).not.toContain('workspace-2-tfc')
1545+
1546+
// BOTH TFEnterprise:only blocks should be kept in terraform-enterprise
1547+
expect(output).toContain('workspace-1-tfe')
1548+
expect(output).toContain('workspace-2-tfe')
1549+
expect(output).toContain('"project-remote-state": false')
1550+
1551+
// Both TFEnterprise:only directive comments should be present
1552+
const beginDirective =
1553+
'<!-- BEGIN: TFEnterprise:only name:project-remote-state -->'
1554+
const endDirective =
1555+
'<!-- END: TFEnterprise:only name:project-remote-state -->'
1556+
const beginCount = output.split(beginDirective).length - 1
1557+
const endCount = output.split(endDirective).length - 1
1558+
expect(beginCount).toBe(2)
1559+
expect(endCount).toBe(2)
1560+
1561+
// Section headers should be preserved
1562+
expect(output).toContain('_Without a VCS repository_')
1563+
expect(output).toContain('_With a VCS repository_')
1564+
expect(output).toContain('Additional documentation content')
1565+
})
12471566
})
12481567
})
12491568

0 commit comments

Comments
 (0)