@backstage/plugin-scaffolder-backend 1.3.0-next.1 → 1.3.0-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 CHANGED
@@ -1,5 +1,40 @@
1
1
  # @backstage/plugin-scaffolder-backend
2
2
 
3
+ ## 1.3.0-next.2
4
+
5
+ ### Minor Changes
6
+
7
+ - ce0d8d7eb1: Fixed a bug in `publish:github` action that didn't permit to add users as collaborators.
8
+ This fix required changing the way parameters are passed to the action.
9
+ In order to add a team as collaborator, now you must use the `team` field instead of `username`.
10
+ In order to add a user as collaborator, you must use the `user` field.
11
+
12
+ It's still possible to use the field `username` but is deprecated in favor of `team`.
13
+
14
+ ```yaml
15
+ - id: publish
16
+ name: Publish
17
+ action: publish:github
18
+ input:
19
+ repoUrl: ...
20
+ collaborators:
21
+ - access: ...
22
+ team: my_team
23
+ - access: ...
24
+ user: my_username
25
+ ```
26
+
27
+ - 582003a059: - Added an optional `list` method on the `TaskBroker` and `TaskStore` interface to list tasks by an optional `userEntityRef`
28
+ - Implemented a `list` method on the `DatabaseTaskStore` class to list tasks by an optional `userEntityRef`
29
+ - Added a route under `/v2/tasks` to list tasks by a `userEntityRef` using the `createdBy` query parameter
30
+
31
+ ### Patch Changes
32
+
33
+ - Updated dependencies
34
+ - @backstage/backend-common@0.14.0-next.2
35
+ - @backstage/integration@1.2.1-next.2
36
+ - @backstage/plugin-catalog-backend@1.2.0-next.2
37
+
3
38
  ## 1.3.0-next.1
4
39
 
5
40
  ### Minor Changes
package/dist/index.cjs.js CHANGED
@@ -1862,22 +1862,36 @@ function createPublishGithubAction(options) {
1862
1862
  },
1863
1863
  collaborators: {
1864
1864
  title: "Collaborators",
1865
- description: "Provide additional users with permissions",
1865
+ description: "Provide additional users or teams with permissions",
1866
1866
  type: "array",
1867
1867
  items: {
1868
1868
  type: "object",
1869
- required: ["username", "access"],
1869
+ additionalProperties: false,
1870
+ required: ["access"],
1870
1871
  properties: {
1871
1872
  access: {
1872
1873
  type: "string",
1873
1874
  description: "The type of access for the user",
1874
1875
  enum: ["push", "pull", "admin", "maintain", "triage"]
1875
1876
  },
1877
+ user: {
1878
+ type: "string",
1879
+ description: "The name of the user that will be added as a collaborator"
1880
+ },
1876
1881
  username: {
1877
1882
  type: "string",
1878
- description: "The username or group"
1883
+ description: "Deprecated. Use the `team` or `user` field instead."
1884
+ },
1885
+ team: {
1886
+ type: "string",
1887
+ description: "The name of the team that will be added as a collaborator"
1879
1888
  }
1880
- }
1889
+ },
1890
+ oneOf: [
1891
+ { required: ["user"] },
1892
+ { required: ["username"] },
1893
+ { required: ["team"] }
1894
+ ]
1881
1895
  }
1882
1896
  },
1883
1897
  token: {
@@ -1990,21 +2004,37 @@ function createPublishGithubAction(options) {
1990
2004
  });
1991
2005
  }
1992
2006
  if (collaborators) {
1993
- for (const {
1994
- access: permission,
1995
- username: team_slug
1996
- } of collaborators) {
2007
+ for (const collaborator of collaborators) {
1997
2008
  try {
1998
- await client.rest.teams.addOrUpdateRepoPermissionsInOrg({
1999
- org: owner,
2000
- team_slug,
2001
- owner,
2002
- repo,
2003
- permission
2004
- });
2009
+ if ("user" in collaborator) {
2010
+ await client.rest.repos.addCollaborator({
2011
+ owner,
2012
+ repo,
2013
+ username: collaborator.user,
2014
+ permission: collaborator.access
2015
+ });
2016
+ } else if ("username" in collaborator) {
2017
+ ctx.logger.warn("The field `username` is deprecated in favor of `team` and will be removed in the future.");
2018
+ await client.rest.teams.addOrUpdateRepoPermissionsInOrg({
2019
+ org: owner,
2020
+ team_slug: collaborator.username,
2021
+ owner,
2022
+ repo,
2023
+ permission: collaborator.access
2024
+ });
2025
+ } else if ("team" in collaborator) {
2026
+ await client.rest.teams.addOrUpdateRepoPermissionsInOrg({
2027
+ org: owner,
2028
+ team_slug: collaborator.team,
2029
+ owner,
2030
+ repo,
2031
+ permission: collaborator.access
2032
+ });
2033
+ }
2005
2034
  } catch (e) {
2006
2035
  errors.assertError(e);
2007
- ctx.logger.warn(`Skipping ${permission} access for ${team_slug}, ${e.message}`);
2036
+ const name = extractCollaboratorName(collaborator);
2037
+ ctx.logger.warn(`Skipping ${collaborator.access} access for ${name}, ${e.message}`);
2008
2038
  }
2009
2039
  }
2010
2040
  }
@@ -2059,6 +2089,13 @@ function createPublishGithubAction(options) {
2059
2089
  }
2060
2090
  });
2061
2091
  }
2092
+ function extractCollaboratorName(collaborator) {
2093
+ if ("username" in collaborator)
2094
+ return collaborator.username;
2095
+ if ("user" in collaborator)
2096
+ return collaborator.user;
2097
+ return collaborator.team;
2098
+ }
2062
2099
 
2063
2100
  const DEFAULT_GLOB_PATTERNS = ["./**", "!.git"];
2064
2101
  const isExecutable = (fileMode) => {
@@ -2834,6 +2871,12 @@ class TemplateActionRegistry {
2834
2871
  }
2835
2872
 
2836
2873
  const migrationsDir = backendCommon.resolvePackagePath("@backstage/plugin-scaffolder-backend", "migrations");
2874
+ const parseSqlDateToIsoString = (input) => {
2875
+ if (typeof input === "string") {
2876
+ return luxon.DateTime.fromSQL(input, { zone: "UTC" }).toISO();
2877
+ }
2878
+ return input;
2879
+ };
2837
2880
  class DatabaseTaskStore {
2838
2881
  static async create(options) {
2839
2882
  await options.database.migrate.latest({
@@ -2844,6 +2887,27 @@ class DatabaseTaskStore {
2844
2887
  constructor(options) {
2845
2888
  this.db = options.database;
2846
2889
  }
2890
+ async list(options) {
2891
+ const queryBuilder = this.db("tasks");
2892
+ if (options.createdBy) {
2893
+ queryBuilder.where({
2894
+ created_by: options.createdBy
2895
+ });
2896
+ }
2897
+ const results = await queryBuilder.orderBy("created_at", "desc").select();
2898
+ const tasks = results.map((result) => {
2899
+ var _a;
2900
+ return {
2901
+ id: result.id,
2902
+ spec: JSON.parse(result.spec),
2903
+ status: result.status,
2904
+ createdBy: (_a = result.created_by) != null ? _a : void 0,
2905
+ lastHeartbeatAt: parseSqlDateToIsoString(result.last_heartbeat_at),
2906
+ createdAt: parseSqlDateToIsoString(result.created_at)
2907
+ };
2908
+ });
2909
+ return { tasks };
2910
+ }
2847
2911
  async getTask(taskId) {
2848
2912
  var _a;
2849
2913
  const [result] = await this.db("tasks").where({ id: taskId }).select();
@@ -2857,8 +2921,8 @@ class DatabaseTaskStore {
2857
2921
  id: result.id,
2858
2922
  spec,
2859
2923
  status: result.status,
2860
- lastHeartbeatAt: result.last_heartbeat_at,
2861
- createdAt: result.created_at,
2924
+ lastHeartbeatAt: parseSqlDateToIsoString(result.last_heartbeat_at),
2925
+ createdAt: parseSqlDateToIsoString(result.created_at),
2862
2926
  createdBy: (_a = result.created_by) != null ? _a : void 0,
2863
2927
  secrets
2864
2928
  };
@@ -2995,7 +3059,7 @@ class DatabaseTaskStore {
2995
3059
  taskId,
2996
3060
  body,
2997
3061
  type: event.event_type,
2998
- createdAt: typeof event.created_at === "string" ? luxon.DateTime.fromSQL(event.created_at, { zone: "UTC" }).toISO() : event.created_at
3062
+ createdAt: parseSqlDateToIsoString(event.created_at)
2999
3063
  };
3000
3064
  } catch (error) {
3001
3065
  throw new Error(`Failed to parse event body from event taskId=${taskId} id=${event.id}, ${error}`);
@@ -3078,6 +3142,12 @@ class StorageTaskBroker {
3078
3142
  this.logger = logger;
3079
3143
  this.deferredDispatch = defer();
3080
3144
  }
3145
+ async list(options) {
3146
+ if (!this.storage.list) {
3147
+ throw new Error("TaskStore does not implement the list method. Please implement the list method to be able to list tasks");
3148
+ }
3149
+ return await this.storage.list({ createdBy: options == null ? void 0 : options.createdBy });
3150
+ }
3081
3151
  async claim() {
3082
3152
  for (; ; ) {
3083
3153
  const pendingTask = await this.storage.claimTask();
@@ -3682,6 +3752,18 @@ async function createRouter(options) {
3682
3752
  }
3683
3753
  });
3684
3754
  res.status(201).json({ id: result.taskId });
3755
+ }).get("/v2/tasks", async (req, res) => {
3756
+ const [userEntityRef] = [req.query.createdBy].flat();
3757
+ if (typeof userEntityRef !== "string" && typeof userEntityRef !== "undefined") {
3758
+ throw new errors.InputError("createdBy query parameter must be a string");
3759
+ }
3760
+ if (!taskBroker.list) {
3761
+ throw new Error("TaskBroker does not support listing tasks, please implement the list method on the TaskBroker.");
3762
+ }
3763
+ const tasks = await taskBroker.list({
3764
+ createdBy: userEntityRef
3765
+ });
3766
+ res.status(200).json(tasks);
3685
3767
  }).get("/v2/tasks/:taskId", async (req, res) => {
3686
3768
  const { taskId } = req.params;
3687
3769
  const task = await taskBroker.get(taskId);