@backstage/plugin-scaffolder-backend 1.5.0-next.0 → 1.5.0

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 CHANGED
@@ -1,5 +1,55 @@
1
1
  # @backstage/plugin-scaffolder-backend
2
2
 
3
+ ## 1.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - c4b452e16a: Starting the implementation of the Wizard page for the `next` scaffolder plugin
8
+ - 593dea6710: Add support for Basic Auth for Bitbucket Server.
9
+ - 3b7930b3e5: Add support for Bearer Authorization header / token-based auth at Git commands.
10
+ - 3f1316f1c5: User Bearer Authorization header at Git commands with token-based auth at Bitbucket Server.
11
+ - eeff5046ae: Updated `publish:gitlab:merge-request` action to allow commit updates and deletes
12
+ - 692d5d3405: Added `reviewers` and `teamReviewers` parameters to `publish:github:pull-request` action to add reviewers on the pull request created by the action
13
+
14
+ ### Patch Changes
15
+
16
+ - fc8a5f797b: Add a `publish:gerrit:review` scaffolder action
17
+ - c971afbf21: The `publish:file` action has been deprecated in favor of testing templates using the template editor instead. Note that this action is not and was never been installed by default.
18
+ - b10b6c4aa4: Fix issue on Windows where templated files where not properly skipped as intended.
19
+ - 56e1b4b89c: Fixed typos in alpha types.
20
+ - dad0f65494: Fail gracefully if an invalid `Authorization` header is passed to `POST /v2/tasks`
21
+ - 014b3b7776: Add missing `res.end()` in scaffolder backend `EventStream` usage
22
+ - Updated dependencies
23
+ - @backstage/backend-common@0.15.0
24
+ - @backstage/backend-plugin-api@0.1.1
25
+ - @backstage/plugin-catalog-node@1.0.1
26
+ - @backstage/integration@1.3.0
27
+ - @backstage/plugin-catalog-backend@1.3.1
28
+
29
+ ## 1.5.0-next.2
30
+
31
+ ### Minor Changes
32
+
33
+ - 692d5d3405: Added `reviewers` and `teamReviewers` parameters to `publish:github:pull-request` action to add reviewers on the pull request created by the action
34
+
35
+ ### Patch Changes
36
+
37
+ - Updated dependencies
38
+ - @backstage/plugin-catalog-backend@1.3.1-next.2
39
+
40
+ ## 1.5.0-next.1
41
+
42
+ ### Minor Changes
43
+
44
+ - c4b452e16a: Starting the implementation of the Wizard page for the `next` scaffolder plugin
45
+
46
+ ### Patch Changes
47
+
48
+ - Updated dependencies
49
+ - @backstage/backend-common@0.15.0-next.1
50
+ - @backstage/integration@1.3.0-next.1
51
+ - @backstage/plugin-catalog-backend@1.3.1-next.1
52
+
3
53
  ## 1.5.0-next.0
4
54
 
5
55
  ### Minor Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-scaffolder-backend",
3
- "version": "1.5.0-next.0",
3
+ "version": "1.5.0",
4
4
  "main": "../dist/index.cjs.js",
5
5
  "types": "../dist/index.alpha.d.ts"
6
6
  }
@@ -6,7 +6,7 @@
6
6
 
7
7
  /// <reference types="node" />
8
8
 
9
- import { BackendRegistrable } from '@backstage/backend-plugin-api';
9
+ import { BackendFeature } from '@backstage/backend-plugin-api';
10
10
  import { CatalogApi } from '@backstage/catalog-client';
11
11
  import { CatalogProcessor } from '@backstage/plugin-catalog-backend';
12
12
  import { CatalogProcessorEmit } from '@backstage/plugin-catalog-backend';
@@ -21,6 +21,7 @@ import { Knex } from 'knex';
21
21
  import { LocationSpec } from '@backstage/plugin-catalog-backend';
22
22
  import { Logger } from 'winston';
23
23
  import { Observable } from '@backstage/types';
24
+ import { Octokit } from 'octokit';
24
25
  import { PluginDatabaseManager } from '@backstage/backend-common';
25
26
  import { Schema } from 'jsonschema';
26
27
  import { ScmIntegrationRegistry } from '@backstage/integration';
@@ -418,6 +419,7 @@ token?: string | undefined;
418
419
  * production, as it writes the files to the local filesystem of the scaffolder.
419
420
  *
420
421
  * @public
422
+ * @deprecated This action will be removed, prefer testing templates using the template editor instead.
421
423
  */
422
424
  export declare function createPublishFileAction(): TemplateAction< {
423
425
  path: string;
@@ -513,6 +515,8 @@ draft?: boolean | undefined;
513
515
  targetPath?: string | undefined;
514
516
  sourcePath?: string | undefined;
515
517
  token?: string | undefined;
518
+ reviewers?: string[] | undefined;
519
+ teamReviewers?: string[] | undefined;
516
520
  }>;
517
521
 
518
522
  /**
@@ -676,14 +680,14 @@ export declare function fetchContents({ reader, integrations, baseUrl, fetchUrl,
676
680
  }): Promise<void>;
677
681
 
678
682
  /** @public */
679
- export declare interface OctokitWithPullRequestPluginClient {
683
+ export declare type OctokitWithPullRequestPluginClient = Octokit & {
680
684
  createPullRequest(options: createPullRequest.Options): Promise<{
681
685
  data: {
682
686
  html_url: string;
683
687
  number: number;
684
688
  };
685
689
  } | null>;
686
- }
690
+ };
687
691
 
688
692
  /**
689
693
  * RouterOptions
@@ -718,7 +722,7 @@ export declare type RunCommandOptions = {
718
722
  * @alpha
719
723
  * Registers the ScaffolderEntitiesProcessor with the catalog processing extension point.
720
724
  */
721
- export declare const scaffolderCatalogModule: (option: unknown) => BackendRegistrable;
725
+ export declare const scaffolderCatalogModule: (options?: unknown) => BackendFeature;
722
726
 
723
727
  /** @public */
724
728
  export declare class ScaffolderEntitiesProcessor implements CatalogProcessor {
@@ -6,7 +6,7 @@
6
6
 
7
7
  /// <reference types="node" />
8
8
 
9
- import { BackendRegistrable } from '@backstage/backend-plugin-api';
9
+ import { BackendFeature } from '@backstage/backend-plugin-api';
10
10
  import { CatalogApi } from '@backstage/catalog-client';
11
11
  import { CatalogProcessor } from '@backstage/plugin-catalog-backend';
12
12
  import { CatalogProcessorEmit } from '@backstage/plugin-catalog-backend';
@@ -21,6 +21,7 @@ import { Knex } from 'knex';
21
21
  import { LocationSpec } from '@backstage/plugin-catalog-backend';
22
22
  import { Logger } from 'winston';
23
23
  import { Observable } from '@backstage/types';
24
+ import { Octokit } from 'octokit';
24
25
  import { PluginDatabaseManager } from '@backstage/backend-common';
25
26
  import { Schema } from 'jsonschema';
26
27
  import { ScmIntegrationRegistry } from '@backstage/integration';
@@ -418,6 +419,7 @@ token?: string | undefined;
418
419
  * production, as it writes the files to the local filesystem of the scaffolder.
419
420
  *
420
421
  * @public
422
+ * @deprecated This action will be removed, prefer testing templates using the template editor instead.
421
423
  */
422
424
  export declare function createPublishFileAction(): TemplateAction< {
423
425
  path: string;
@@ -513,6 +515,8 @@ draft?: boolean | undefined;
513
515
  targetPath?: string | undefined;
514
516
  sourcePath?: string | undefined;
515
517
  token?: string | undefined;
518
+ reviewers?: string[] | undefined;
519
+ teamReviewers?: string[] | undefined;
516
520
  }>;
517
521
 
518
522
  /**
@@ -676,14 +680,14 @@ export declare function fetchContents({ reader, integrations, baseUrl, fetchUrl,
676
680
  }): Promise<void>;
677
681
 
678
682
  /** @public */
679
- export declare interface OctokitWithPullRequestPluginClient {
683
+ export declare type OctokitWithPullRequestPluginClient = Octokit & {
680
684
  createPullRequest(options: createPullRequest.Options): Promise<{
681
685
  data: {
682
686
  html_url: string;
683
687
  number: number;
684
688
  };
685
689
  } | null>;
686
- }
690
+ };
687
691
 
688
692
  /**
689
693
  * RouterOptions
package/dist/index.cjs.js CHANGED
@@ -673,7 +673,7 @@ function createFetchTemplateAction(options) {
673
673
  });
674
674
  }
675
675
  function containsSkippedContent(localOutputPath) {
676
- return localOutputPath === "" || path__default["default"].isAbsolute(localOutputPath) || localOutputPath.includes(`${path__default["default"].sep}${path__default["default"].sep}`);
676
+ return localOutputPath === "" || localOutputPath.startsWith("/") || localOutputPath.includes("//");
677
677
  }
678
678
 
679
679
  const createFilesystemDeleteAction = () => {
@@ -2561,6 +2561,9 @@ function createPublishFileAction() {
2561
2561
  }
2562
2562
  },
2563
2563
  async handler(ctx) {
2564
+ ctx.logger.warn(
2565
+ "[DEPRECATED] This action will be removed, prefer testing templates using the template editor instead."
2566
+ );
2564
2567
  const { path: path$1 } = ctx.input;
2565
2568
  const exists = await fs__default["default"].pathExists(path$1);
2566
2569
  if (exists) {
@@ -3055,6 +3058,22 @@ const createPublishGithubPullRequestAction = ({
3055
3058
  title: "Authentication Token",
3056
3059
  type: "string",
3057
3060
  description: "The token to use for authorization to GitHub"
3061
+ },
3062
+ reviewers: {
3063
+ title: "Pull Request Reviewers",
3064
+ type: "array",
3065
+ items: {
3066
+ type: "string"
3067
+ },
3068
+ description: "The users that will be added as reviewers to the pull request"
3069
+ },
3070
+ teamReviewers: {
3071
+ title: "Pull Request Team Reviewers",
3072
+ type: "array",
3073
+ items: {
3074
+ type: "string"
3075
+ },
3076
+ description: "The teams that will be added as reviewers to the pull request"
3058
3077
  }
3059
3078
  }
3060
3079
  },
@@ -3084,7 +3103,9 @@ const createPublishGithubPullRequestAction = ({
3084
3103
  draft,
3085
3104
  targetPath,
3086
3105
  sourcePath,
3087
- token: providedToken
3106
+ token: providedToken,
3107
+ reviewers,
3108
+ teamReviewers
3088
3109
  } = ctx.input;
3089
3110
  const { owner, repo, host } = parseRepoUrl(repoUrl, integrations);
3090
3111
  if (!owner) {
@@ -3132,13 +3153,46 @@ const createPublishGithubPullRequestAction = ({
3132
3153
  if (!response) {
3133
3154
  throw new GithubResponseError("null response from Github");
3134
3155
  }
3156
+ const pullRequestNumber = response.data.number;
3157
+ if (reviewers || teamReviewers) {
3158
+ const pullRequest = { owner, repo, number: pullRequestNumber };
3159
+ await requestReviewersOnPullRequest(
3160
+ pullRequest,
3161
+ reviewers,
3162
+ teamReviewers,
3163
+ client,
3164
+ ctx.logger
3165
+ );
3166
+ }
3135
3167
  ctx.output("remoteUrl", response.data.html_url);
3136
- ctx.output("pullRequestNumber", response.data.number);
3168
+ ctx.output("pullRequestNumber", pullRequestNumber);
3137
3169
  } catch (e) {
3138
3170
  throw new GithubResponseError("Pull request creation failed", e);
3139
3171
  }
3140
3172
  }
3141
3173
  });
3174
+ async function requestReviewersOnPullRequest(pr, reviewers, teamReviewers, client, logger) {
3175
+ var _a, _b, _c, _d;
3176
+ try {
3177
+ const result = await client.rest.pulls.requestReviewers({
3178
+ owner: pr.owner,
3179
+ repo: pr.repo,
3180
+ pull_number: pr.number,
3181
+ reviewers,
3182
+ team_reviewers: teamReviewers
3183
+ });
3184
+ const addedUsers = (_b = (_a = result.data.requested_reviewers) == null ? void 0 : _a.join(", ")) != null ? _b : "";
3185
+ const addedTeams = (_d = (_c = result.data.requested_teams) == null ? void 0 : _c.join(", ")) != null ? _d : "";
3186
+ logger.info(
3187
+ `Added users [${addedUsers}] and teams [${addedTeams}] as reviewers to Pull request ${pr.number}`
3188
+ );
3189
+ } catch (e) {
3190
+ logger.error(
3191
+ `Failure when adding reviewers to Pull request ${pr.number}`,
3192
+ e
3193
+ );
3194
+ }
3195
+ }
3142
3196
  };
3143
3197
 
3144
3198
  function createPublishGitlabAction(options) {
@@ -4455,7 +4509,10 @@ async function createRouter(options) {
4455
4509
  async (req, res) => {
4456
4510
  var _a, _b;
4457
4511
  const { namespace, kind, name } = req.params;
4458
- const { token } = parseBearerToken(req.headers.authorization);
4512
+ const { token } = parseBearerToken({
4513
+ header: req.headers.authorization,
4514
+ logger
4515
+ });
4459
4516
  const template = await findTemplate({
4460
4517
  catalogApi: catalogClient,
4461
4518
  entityRef: { kind, namespace, name },
@@ -4465,10 +4522,12 @@ async function createRouter(options) {
4465
4522
  const parameters = [(_a = template.spec.parameters) != null ? _a : []].flat();
4466
4523
  res.json({
4467
4524
  title: (_b = template.metadata.title) != null ? _b : template.metadata.name,
4525
+ description: template.metadata.description,
4468
4526
  steps: parameters.map((schema) => {
4469
4527
  var _a2;
4470
4528
  return {
4471
- title: (_a2 = schema.title) != null ? _a2 : "Fill in template parameters",
4529
+ title: (_a2 = schema.title) != null ? _a2 : "Please enter the following information",
4530
+ description: schema.description,
4472
4531
  schema
4473
4532
  };
4474
4533
  })
@@ -4494,9 +4553,10 @@ async function createRouter(options) {
4494
4553
  const { kind, namespace, name } = catalogModel.parseEntityRef(templateRef, {
4495
4554
  defaultKind: "template"
4496
4555
  });
4497
- const { token, entityRef: userEntityRef } = parseBearerToken(
4498
- req.headers.authorization
4499
- );
4556
+ const { token, entityRef: userEntityRef } = parseBearerToken({
4557
+ header: req.headers.authorization,
4558
+ logger
4559
+ });
4500
4560
  const userEntity = userEntityRef ? await catalogClient.getEntityByRef(userEntityRef, { token }) : void 0;
4501
4561
  let auditLog = `Scaffolding task for ${templateRef}`;
4502
4562
  if (userEntityRef) {
@@ -4658,7 +4718,10 @@ data: ${JSON.stringify(event)}
4658
4718
  if (!await pluginScaffolderCommon.templateEntityV1beta3Validator.check(template)) {
4659
4719
  throw new errors.InputError("Input template is not a template");
4660
4720
  }
4661
- const { token } = parseBearerToken(req.headers.authorization);
4721
+ const { token } = parseBearerToken({
4722
+ header: req.headers.authorization,
4723
+ logger
4724
+ });
4662
4725
  for (const parameters of [(_a = template.spec.parameters) != null ? _a : []].flat()) {
4663
4726
  const result2 = jsonschema.validate(body.values, parameters);
4664
4727
  if (!result2.valid) {
@@ -4705,7 +4768,10 @@ data: ${JSON.stringify(event)}
4705
4768
  app.use("/", router);
4706
4769
  return app;
4707
4770
  }
4708
- function parseBearerToken(header) {
4771
+ function parseBearerToken({
4772
+ header,
4773
+ logger
4774
+ }) {
4709
4775
  var _a;
4710
4776
  if (!header) {
4711
4777
  return {};
@@ -4726,9 +4792,11 @@ function parseBearerToken(header) {
4726
4792
  if (typeof sub !== "string") {
4727
4793
  throw new TypeError("Expected string sub claim");
4728
4794
  }
4795
+ catalogModel.parseEntityRef(sub);
4729
4796
  return { entityRef: sub, token };
4730
4797
  } catch (e) {
4731
- throw new errors.InputError(`Invalid authorization header: ${errors.stringifyError(e)}`);
4798
+ logger.error(`Invalid authorization header: ${errors.stringifyError(e)}`);
4799
+ return {};
4732
4800
  }
4733
4801
  }
4734
4802
 
@@ -4791,12 +4859,10 @@ const scaffolderCatalogModule = backendPluginApi.createBackendModule({
4791
4859
  register(env) {
4792
4860
  env.registerInit({
4793
4861
  deps: {
4794
- catalogProcessingExtensionPoint: pluginCatalogNode.catalogProcessingExtentionPoint
4862
+ catalog: pluginCatalogNode.catalogProcessingExtensionPoint
4795
4863
  },
4796
- async init({ catalogProcessingExtensionPoint }) {
4797
- catalogProcessingExtensionPoint.addProcessor(
4798
- new ScaffolderEntitiesProcessor()
4799
- );
4864
+ async init({ catalog }) {
4865
+ catalog.addProcessor(new ScaffolderEntitiesProcessor());
4800
4866
  }
4801
4867
  });
4802
4868
  }