@backstage/plugin-techdocs-node 1.4.4-next.1 → 1.4.4-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/index.cjs.js +131 -0
- package/dist/index.cjs.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @backstage/plugin-techdocs-node
|
|
2
2
|
|
|
3
|
+
## 1.4.4-next.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
- @backstage/backend-common@0.18.0-next.1
|
|
9
|
+
- @backstage/catalog-model@1.1.5-next.1
|
|
10
|
+
- @backstage/config@1.0.6-next.0
|
|
11
|
+
- @backstage/errors@1.1.4
|
|
12
|
+
- @backstage/integration@1.4.2-next.0
|
|
13
|
+
- @backstage/integration-aws-node@0.1.1-next.0
|
|
14
|
+
- @backstage/plugin-search-common@1.2.1-next.0
|
|
15
|
+
|
|
3
16
|
## 1.4.4-next.1
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
package/dist/index.cjs.js
CHANGED
|
@@ -106,6 +106,7 @@ const getCloudPathForLocalPath = (entity, localPath = "", useLegacyPathCasing =
|
|
|
106
106
|
const relativeFilePathTriplet = `${entityRootDir}/${relativeFilePathPosix}`;
|
|
107
107
|
const destination = useLegacyPathCasing ? relativeFilePathTriplet : lowerCaseEntityTriplet(relativeFilePathTriplet);
|
|
108
108
|
const destinationWithRoot = [
|
|
109
|
+
// The extra filter prevents unintended double slashes and prefixes.
|
|
109
110
|
...externalStorageRootPath.split(path__default["default"].posix.sep).filter((s) => s !== ""),
|
|
110
111
|
destination
|
|
111
112
|
].join("/");
|
|
@@ -383,6 +384,11 @@ const pathMkdocsYmlWithTechdocsPlugin = async (mkdocsYmlPath, logger) => {
|
|
|
383
384
|
};
|
|
384
385
|
|
|
385
386
|
const _TechdocsGenerator = class {
|
|
387
|
+
/**
|
|
388
|
+
* Returns a instance of TechDocs generator
|
|
389
|
+
* @param config - A Backstage configuration
|
|
390
|
+
* @param options - Options to configure the generator
|
|
391
|
+
*/
|
|
386
392
|
static fromConfig(config, options) {
|
|
387
393
|
const { containerRunner, logger } = options;
|
|
388
394
|
const scmIntegrations = integration.ScmIntegrations.fromConfig(config);
|
|
@@ -399,6 +405,7 @@ const _TechdocsGenerator = class {
|
|
|
399
405
|
this.containerRunner = options.containerRunner;
|
|
400
406
|
this.scmIntegrations = options.scmIntegrations;
|
|
401
407
|
}
|
|
408
|
+
/** {@inheritDoc GeneratorBase.run} */
|
|
402
409
|
async run(options) {
|
|
403
410
|
var _a;
|
|
404
411
|
const {
|
|
@@ -456,6 +463,8 @@ const _TechdocsGenerator = class {
|
|
|
456
463
|
logStream,
|
|
457
464
|
mountDirs,
|
|
458
465
|
workingDir: "/input",
|
|
466
|
+
// Set the home directory inside the container as something that applications can
|
|
467
|
+
// write to, otherwise they will just fail trying to write to /
|
|
459
468
|
envVars: { HOME: "/tmp" },
|
|
460
469
|
pullImage: this.options.pullImage
|
|
461
470
|
});
|
|
@@ -490,6 +499,10 @@ const _TechdocsGenerator = class {
|
|
|
490
499
|
}
|
|
491
500
|
};
|
|
492
501
|
let TechdocsGenerator = _TechdocsGenerator;
|
|
502
|
+
/**
|
|
503
|
+
* The default docker image (and version) used to generate content. Public
|
|
504
|
+
* and static so that techdocs-node consumers can use the same version.
|
|
505
|
+
*/
|
|
493
506
|
TechdocsGenerator.defaultDockerImage = "spotify/techdocs:v1.1.0";
|
|
494
507
|
function readGeneratorConfig(config, logger) {
|
|
495
508
|
var _a;
|
|
@@ -518,15 +531,29 @@ class Generators {
|
|
|
518
531
|
constructor() {
|
|
519
532
|
this.generatorMap = /* @__PURE__ */ new Map();
|
|
520
533
|
}
|
|
534
|
+
/**
|
|
535
|
+
* Returns a generators instance containing a generator for TechDocs
|
|
536
|
+
* @param config - A Backstage configuration
|
|
537
|
+
* @param options - Options to configure the TechDocs generator
|
|
538
|
+
*/
|
|
521
539
|
static async fromConfig(config, options) {
|
|
522
540
|
const generators = new Generators();
|
|
523
541
|
const techdocsGenerator = TechdocsGenerator.fromConfig(config, options);
|
|
524
542
|
generators.register("techdocs", techdocsGenerator);
|
|
525
543
|
return generators;
|
|
526
544
|
}
|
|
545
|
+
/**
|
|
546
|
+
* Register a generator in the generators collection
|
|
547
|
+
* @param generatorKey - Unique identifier for the generator
|
|
548
|
+
* @param generator - The generator instance to register
|
|
549
|
+
*/
|
|
527
550
|
register(generatorKey, generator) {
|
|
528
551
|
this.generatorMap.set(generatorKey, generator);
|
|
529
552
|
}
|
|
553
|
+
/**
|
|
554
|
+
* Returns the generator for a given TechDocs entity
|
|
555
|
+
* @param entity - A TechDocs entity instance
|
|
556
|
+
*/
|
|
530
557
|
get(entity) {
|
|
531
558
|
const generatorKey = getGeneratorKey(entity);
|
|
532
559
|
const generator = this.generatorMap.get(generatorKey);
|
|
@@ -609,6 +636,11 @@ const getDocFilesFromRepository = async (reader, entity, opts) => {
|
|
|
609
636
|
};
|
|
610
637
|
|
|
611
638
|
class DirectoryPreparer {
|
|
639
|
+
/**
|
|
640
|
+
* Returns a directory preparer instance
|
|
641
|
+
* @param config - A backstage config
|
|
642
|
+
* @param options - A directory preparer options containing a logger and reader
|
|
643
|
+
*/
|
|
612
644
|
static fromConfig(config, { logger, reader }) {
|
|
613
645
|
return new DirectoryPreparer(config, logger, reader);
|
|
614
646
|
}
|
|
@@ -616,6 +648,7 @@ class DirectoryPreparer {
|
|
|
616
648
|
this.reader = reader;
|
|
617
649
|
this.scmIntegrations = integration.ScmIntegrations.fromConfig(config);
|
|
618
650
|
}
|
|
651
|
+
/** {@inheritDoc PreparerBase.prepare} */
|
|
619
652
|
async prepare(entity, options) {
|
|
620
653
|
var _a, _b;
|
|
621
654
|
const annotation = parseReferenceAnnotation(
|
|
@@ -642,7 +675,9 @@ class DirectoryPreparer {
|
|
|
642
675
|
}
|
|
643
676
|
case "dir": {
|
|
644
677
|
return {
|
|
678
|
+
// the transformation already validated that the target is in a safe location
|
|
645
679
|
preparedDir: target,
|
|
680
|
+
// Instead of supporting caching on local sources, use techdocs-cli for local development and debugging.
|
|
646
681
|
etag: ""
|
|
647
682
|
};
|
|
648
683
|
}
|
|
@@ -653,6 +688,10 @@ class DirectoryPreparer {
|
|
|
653
688
|
}
|
|
654
689
|
|
|
655
690
|
class UrlPreparer {
|
|
691
|
+
/**
|
|
692
|
+
* Returns a directory preparer instance
|
|
693
|
+
* @param config - A URL preparer config containing the a logger and reader
|
|
694
|
+
*/
|
|
656
695
|
static fromConfig({ reader, logger }) {
|
|
657
696
|
return new UrlPreparer(reader, logger);
|
|
658
697
|
}
|
|
@@ -660,6 +699,7 @@ class UrlPreparer {
|
|
|
660
699
|
this.logger = logger;
|
|
661
700
|
this.reader = reader;
|
|
662
701
|
}
|
|
702
|
+
/** {@inheritDoc PreparerBase.prepare} */
|
|
663
703
|
async prepare(entity, options) {
|
|
664
704
|
try {
|
|
665
705
|
return await getDocFilesFromRepository(this.reader, entity, {
|
|
@@ -684,6 +724,12 @@ class Preparers {
|
|
|
684
724
|
constructor() {
|
|
685
725
|
this.preparerMap = /* @__PURE__ */ new Map();
|
|
686
726
|
}
|
|
727
|
+
/**
|
|
728
|
+
* Returns a generators instance containing a generator for TechDocs
|
|
729
|
+
* @public
|
|
730
|
+
* @param backstageConfig - A Backstage configuration
|
|
731
|
+
* @param preparerConfig - Options to configure preparers
|
|
732
|
+
*/
|
|
687
733
|
static async fromConfig(backstageConfig, { logger, reader }) {
|
|
688
734
|
const preparers = new Preparers();
|
|
689
735
|
const urlPreparer = UrlPreparer.fromConfig({ reader, logger });
|
|
@@ -695,9 +741,19 @@ class Preparers {
|
|
|
695
741
|
preparers.register("dir", directoryPreparer);
|
|
696
742
|
return preparers;
|
|
697
743
|
}
|
|
744
|
+
/**
|
|
745
|
+
* Register a preparer in the preparers collection
|
|
746
|
+
* @param protocol - url or dir to associate with preparer
|
|
747
|
+
* @param preparer - The preparer instance to set
|
|
748
|
+
*/
|
|
698
749
|
register(protocol, preparer) {
|
|
699
750
|
this.preparerMap.set(protocol, preparer);
|
|
700
751
|
}
|
|
752
|
+
/**
|
|
753
|
+
* Returns the preparer for a given TechDocs entity
|
|
754
|
+
* @param entity - A TechDocs entity instance
|
|
755
|
+
* @returns
|
|
756
|
+
*/
|
|
701
757
|
get(entity) {
|
|
702
758
|
const { type } = parseReferenceAnnotation(
|
|
703
759
|
"backstage.io/techdocs-ref",
|
|
@@ -818,6 +874,10 @@ class AwsS3Publish {
|
|
|
818
874
|
}
|
|
819
875
|
return explicitCredentials;
|
|
820
876
|
}
|
|
877
|
+
/**
|
|
878
|
+
* Check if the defined bucket exists. Being able to connect means the configuration is good
|
|
879
|
+
* and the storage client will work.
|
|
880
|
+
*/
|
|
821
881
|
async getReadiness() {
|
|
822
882
|
try {
|
|
823
883
|
await this.storageClient.send(
|
|
@@ -837,6 +897,10 @@ class AwsS3Publish {
|
|
|
837
897
|
};
|
|
838
898
|
}
|
|
839
899
|
}
|
|
900
|
+
/**
|
|
901
|
+
* Upload all the files from the generated `directory` to the S3 bucket.
|
|
902
|
+
* Directory structure used in the bucket is - entityNamespace/entityKind/entityName/index.html
|
|
903
|
+
*/
|
|
840
904
|
async publish({
|
|
841
905
|
entity,
|
|
842
906
|
directory
|
|
@@ -964,6 +1028,9 @@ class AwsS3Publish {
|
|
|
964
1028
|
throw new errors.ForwardedError("TechDocs metadata fetch failed", e);
|
|
965
1029
|
}
|
|
966
1030
|
}
|
|
1031
|
+
/**
|
|
1032
|
+
* Express route middleware to serve static files on a route in techdocs-backend.
|
|
1033
|
+
*/
|
|
967
1034
|
docsRouter() {
|
|
968
1035
|
return async (req, res) => {
|
|
969
1036
|
const decodedUri = decodeURI(req.path.replace(/^\//, ""));
|
|
@@ -990,6 +1057,10 @@ class AwsS3Publish {
|
|
|
990
1057
|
}
|
|
991
1058
|
};
|
|
992
1059
|
}
|
|
1060
|
+
/**
|
|
1061
|
+
* A helper function which checks if index.html of an Entity's docs site is available. This
|
|
1062
|
+
* can be used to verify if there are any pre-generated docs available to serve.
|
|
1063
|
+
*/
|
|
993
1064
|
async hasDocsBeenGenerated(entity) {
|
|
994
1065
|
try {
|
|
995
1066
|
const entityTriplet = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`;
|
|
@@ -1051,6 +1122,9 @@ class AwsS3Publish {
|
|
|
1051
1122
|
)
|
|
1052
1123
|
);
|
|
1053
1124
|
}
|
|
1125
|
+
/**
|
|
1126
|
+
* Returns a list of all object keys from the configured bucket.
|
|
1127
|
+
*/
|
|
1054
1128
|
async getAllObjectsFromBucket({ prefix } = { prefix: "" }) {
|
|
1055
1129
|
const objects = [];
|
|
1056
1130
|
let nextContinuation;
|
|
@@ -1146,6 +1220,10 @@ class AzureBlobStoragePublish {
|
|
|
1146
1220
|
);
|
|
1147
1221
|
return { isAvailable: false };
|
|
1148
1222
|
}
|
|
1223
|
+
/**
|
|
1224
|
+
* Upload all the files from the generated `directory` to the Azure Blob Storage container.
|
|
1225
|
+
* Directory structure used in the container is - entityNamespace/entityKind/entityName/index.html
|
|
1226
|
+
*/
|
|
1149
1227
|
async publish({
|
|
1150
1228
|
entity,
|
|
1151
1229
|
directory
|
|
@@ -1275,6 +1353,9 @@ class AzureBlobStoragePublish {
|
|
|
1275
1353
|
throw new errors.ForwardedError("TechDocs metadata fetch failed", e);
|
|
1276
1354
|
}
|
|
1277
1355
|
}
|
|
1356
|
+
/**
|
|
1357
|
+
* Express route middleware to serve static files on a route in techdocs-backend.
|
|
1358
|
+
*/
|
|
1278
1359
|
docsRouter() {
|
|
1279
1360
|
return (req, res) => {
|
|
1280
1361
|
const decodedUri = decodeURI(req.path.replace(/^\//, ""));
|
|
@@ -1296,6 +1377,10 @@ class AzureBlobStoragePublish {
|
|
|
1296
1377
|
});
|
|
1297
1378
|
};
|
|
1298
1379
|
}
|
|
1380
|
+
/**
|
|
1381
|
+
* A helper function which checks if index.html of an Entity's docs site is available. This
|
|
1382
|
+
* can be used to verify if there are any pre-generated docs available to serve.
|
|
1383
|
+
*/
|
|
1299
1384
|
hasDocsBeenGenerated(entity) {
|
|
1300
1385
|
const entityTriplet = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`;
|
|
1301
1386
|
const entityRootDir = this.legacyPathCasing ? entityTriplet : lowerCaseEntityTriplet(entityTriplet);
|
|
@@ -1467,6 +1552,10 @@ class GoogleGCSPublish {
|
|
|
1467
1552
|
bucketRootPath
|
|
1468
1553
|
});
|
|
1469
1554
|
}
|
|
1555
|
+
/**
|
|
1556
|
+
* Check if the defined bucket exists. Being able to connect means the configuration is good
|
|
1557
|
+
* and the storage client will work.
|
|
1558
|
+
*/
|
|
1470
1559
|
async getReadiness() {
|
|
1471
1560
|
try {
|
|
1472
1561
|
await this.storageClient.bucket(this.bucketName).getMetadata();
|
|
@@ -1485,6 +1574,10 @@ class GoogleGCSPublish {
|
|
|
1485
1574
|
return { isAvailable: false };
|
|
1486
1575
|
}
|
|
1487
1576
|
}
|
|
1577
|
+
/**
|
|
1578
|
+
* Upload all the files from the generated `directory` to the GCS bucket.
|
|
1579
|
+
* Directory structure used in the bucket is - entityNamespace/entityKind/entityName/index.html
|
|
1580
|
+
*/
|
|
1488
1581
|
async publish({
|
|
1489
1582
|
entity,
|
|
1490
1583
|
directory
|
|
@@ -1577,6 +1670,9 @@ class GoogleGCSPublish {
|
|
|
1577
1670
|
});
|
|
1578
1671
|
});
|
|
1579
1672
|
}
|
|
1673
|
+
/**
|
|
1674
|
+
* Express route middleware to serve static files on a route in techdocs-backend.
|
|
1675
|
+
*/
|
|
1580
1676
|
docsRouter() {
|
|
1581
1677
|
return (req, res) => {
|
|
1582
1678
|
const decodedUri = decodeURI(req.path.replace(/^\//, ""));
|
|
@@ -1598,6 +1694,10 @@ class GoogleGCSPublish {
|
|
|
1598
1694
|
}).pipe(res);
|
|
1599
1695
|
};
|
|
1600
1696
|
}
|
|
1697
|
+
/**
|
|
1698
|
+
* A helper function which checks if index.html of an Entity's docs site is available. This
|
|
1699
|
+
* can be used to verify if there are any pre-generated docs available to serve.
|
|
1700
|
+
*/
|
|
1601
1701
|
async hasDocsBeenGenerated(entity) {
|
|
1602
1702
|
return new Promise((resolve) => {
|
|
1603
1703
|
const entityTriplet = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`;
|
|
@@ -1775,6 +1875,7 @@ class LocalPublish {
|
|
|
1775
1875
|
});
|
|
1776
1876
|
router.use(
|
|
1777
1877
|
express__default["default"].static(this.staticDocsDir, {
|
|
1878
|
+
// Handle content-type header the same as all other publishers.
|
|
1778
1879
|
setHeaders: (res, filePath) => {
|
|
1779
1880
|
const fileExtension = path__default["default"].extname(filePath);
|
|
1780
1881
|
const headers = getHeadersForFileExtension(fileExtension);
|
|
@@ -1809,6 +1910,10 @@ class LocalPublish {
|
|
|
1809
1910
|
return false;
|
|
1810
1911
|
}
|
|
1811
1912
|
}
|
|
1913
|
+
/**
|
|
1914
|
+
* This code will never run in practice. It is merely here to illustrate how
|
|
1915
|
+
* to implement this method for other storage providers.
|
|
1916
|
+
*/
|
|
1812
1917
|
async migrateDocsCase({
|
|
1813
1918
|
removeOriginal = false,
|
|
1814
1919
|
concurrency = 25
|
|
@@ -1842,6 +1947,9 @@ class LocalPublish {
|
|
|
1842
1947
|
)
|
|
1843
1948
|
);
|
|
1844
1949
|
}
|
|
1950
|
+
/**
|
|
1951
|
+
* Utility wrapper around path.join(), used to control legacy case logic.
|
|
1952
|
+
*/
|
|
1845
1953
|
staticEntityPathJoin(...allParts) {
|
|
1846
1954
|
let staticEntityPath = this.staticDocsDir;
|
|
1847
1955
|
allParts.map((part) => part.split(path__default["default"].sep)).flat().forEach((part, index) => {
|
|
@@ -1904,6 +2012,10 @@ class OpenStackSwiftPublish {
|
|
|
1904
2012
|
});
|
|
1905
2013
|
return new OpenStackSwiftPublish({ storageClient, containerName, logger });
|
|
1906
2014
|
}
|
|
2015
|
+
/*
|
|
2016
|
+
* Check if the defined container exists. Being able to connect means the configuration is good
|
|
2017
|
+
* and the storage client will work.
|
|
2018
|
+
*/
|
|
1907
2019
|
async getReadiness() {
|
|
1908
2020
|
try {
|
|
1909
2021
|
const container = await this.storageClient.getContainerMetadata(
|
|
@@ -1931,6 +2043,10 @@ class OpenStackSwiftPublish {
|
|
|
1931
2043
|
};
|
|
1932
2044
|
}
|
|
1933
2045
|
}
|
|
2046
|
+
/**
|
|
2047
|
+
* Upload all the files from the generated `directory` to the OpenStack Swift container.
|
|
2048
|
+
* Directory structure used in the bucket is - entityNamespace/entityKind/entityName/index.html
|
|
2049
|
+
*/
|
|
1934
2050
|
async publish({
|
|
1935
2051
|
entity,
|
|
1936
2052
|
directory
|
|
@@ -2000,6 +2116,9 @@ class OpenStackSwiftPublish {
|
|
|
2000
2116
|
}
|
|
2001
2117
|
});
|
|
2002
2118
|
}
|
|
2119
|
+
/**
|
|
2120
|
+
* Express route middleware to serve static files on a route in techdocs-backend.
|
|
2121
|
+
*/
|
|
2003
2122
|
docsRouter() {
|
|
2004
2123
|
return async (req, res) => {
|
|
2005
2124
|
const filePath = decodeURI(req.path.replace(/^\//, ""));
|
|
@@ -2033,6 +2152,10 @@ class OpenStackSwiftPublish {
|
|
|
2033
2152
|
}
|
|
2034
2153
|
};
|
|
2035
2154
|
}
|
|
2155
|
+
/**
|
|
2156
|
+
* A helper function which checks if index.html of an Entity's docs site is available. This
|
|
2157
|
+
* can be used to verify if there are any pre-generated docs available to serve.
|
|
2158
|
+
*/
|
|
2036
2159
|
async hasDocsBeenGenerated(entity) {
|
|
2037
2160
|
const entityRootDir = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`;
|
|
2038
2161
|
try {
|
|
@@ -2089,6 +2212,9 @@ class OpenStackSwiftPublish {
|
|
|
2089
2212
|
)
|
|
2090
2213
|
);
|
|
2091
2214
|
}
|
|
2215
|
+
/**
|
|
2216
|
+
* Returns a list of all object keys from the configured container.
|
|
2217
|
+
*/
|
|
2092
2218
|
async getAllObjectsFromContainer({ prefix } = { prefix: "" }) {
|
|
2093
2219
|
let objects = [];
|
|
2094
2220
|
const OSS_MAX_LIMIT = Math.pow(2, 31) - 1;
|
|
@@ -2103,6 +2229,11 @@ class OpenStackSwiftPublish {
|
|
|
2103
2229
|
}
|
|
2104
2230
|
|
|
2105
2231
|
class Publisher {
|
|
2232
|
+
/**
|
|
2233
|
+
* Returns a instance of TechDocs publisher
|
|
2234
|
+
* @param config - A Backstage configuration
|
|
2235
|
+
* @param options - Options for configuring the publisher factory
|
|
2236
|
+
*/
|
|
2106
2237
|
static async fromConfig(config, { logger, discovery }) {
|
|
2107
2238
|
var _a;
|
|
2108
2239
|
const publisherType = (_a = config.getOptionalString(
|