@pnp/cli-microsoft365 5.1.0-beta.7b2911b → 5.1.0-beta.c518929

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/.eslintrc.js CHANGED
@@ -59,6 +59,7 @@ const dictionary = [
59
59
  'site',
60
60
  'status',
61
61
  'storage',
62
+ 'teams',
62
63
  'token',
63
64
  'type',
64
65
  'user',
package/Dockerfile CHANGED
@@ -21,7 +21,9 @@ RUN apk add --no-cache \
21
21
  shadow \
22
22
  bash-completion \
23
23
  nodejs \
24
- npm
24
+ npm \
25
+ python3 \
26
+ py3-pip
25
27
 
26
28
  RUN adduser --system cli-microsoft365
27
29
  USER cli-microsoft365
@@ -31,11 +33,10 @@ WORKDIR /home/cli-microsoft365
31
33
  ENV 0="/bin/bash" \
32
34
  SHELL="bash" \
33
35
  NPM_CONFIG_PREFIX=/home/cli-microsoft365/.npm-global \
34
- PATH=$PATH:/home/cli-microsoft365/.npm-global/bin \
36
+ PATH=$PATH:/home/cli-microsoft365/.npm-global/bin:/home/cli-microsoft365/.local/bin \
35
37
  CLIMICROSOFT365_ENV="docker"
36
38
 
37
- RUN bash -c 'echo "export PATH=$PATH:/home/cli-microsoft365/.npm-global/bin" >> ~/.bash_profile' \
38
- && bash -c 'echo "export NPM_CONFIG_PREFIX=/home/cli-microsoft365/.npm-global" >> ~/.bash_profile' \
39
+ RUN bash -c 'echo "export PATH=$PATH:/home/cli-microsoft365/.npm-global/bin:/home/.local/bin" >> ~/.bash_profile' \
39
40
  && bash -c 'echo "export CLIMICROSOFT365_ENV=\"docker\"" >> ~/.bash_profile' \
40
41
  && bash -c 'npm i -g @pnp/cli-microsoft365@${CLI_VERSION} --production --quiet --no-progress' \
41
42
  && bash -c 'echo "source /etc/profile.d/bash_completion.sh" >> ~/.bash_profile' \
@@ -43,4 +44,6 @@ RUN bash -c 'echo "export PATH=$PATH:/home/cli-microsoft365/.npm-global/bin" >>
43
44
  && bash -c 'm365 cli completion sh setup' \
44
45
  && pwsh -c 'm365 cli completion pwsh setup --profile $profile'
45
46
 
47
+ RUN pip install jmespath-terminal
48
+
46
49
  CMD [ "bash", "-l" ]
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const request_1 = require("../../../../request");
6
+ const urlUtil_1 = require("../../../../utils/urlUtil");
7
+ const spo_1 = require("../../../../utils/spo");
8
+ const validation_1 = require("../../../../utils/validation");
9
+ const commands_1 = require("../../commands");
10
+ const SpoAppBaseCommand_1 = require("./SpoAppBaseCommand");
11
+ class SpoAppTeamsPackageDownloadCommand extends SpoAppBaseCommand_1.SpoAppBaseCommand {
12
+ get name() {
13
+ return commands_1.default.APP_TEAMSPACKAGE_DOWNLOAD;
14
+ }
15
+ get description() {
16
+ return 'Downloads Teams app package for an SPFx solution deployed to tenant app catalog';
17
+ }
18
+ getTelemetryProperties(args) {
19
+ const telemetryProps = super.getTelemetryProperties(args);
20
+ telemetryProps.appCatalogUrl = typeof args.options.appCatalogUrl !== 'undefined';
21
+ telemetryProps.appItemUniqueId = typeof args.options.appItemUniqueId !== 'undefined';
22
+ telemetryProps.appItemId = typeof args.options.appItemId !== 'undefined';
23
+ telemetryProps.appName = typeof args.options.appName !== 'undefined';
24
+ telemetryProps.fileName = typeof args.options.fileName !== 'undefined';
25
+ return telemetryProps;
26
+ }
27
+ commandAction(logger, args, cb) {
28
+ var _a, _b;
29
+ this.appCatalogUrl = args.options.appCatalogUrl;
30
+ const appInfo = {
31
+ id: (_a = args.options.appItemId) !== null && _a !== void 0 ? _a : undefined,
32
+ packageFileName: (_b = args.options.fileName) !== null && _b !== void 0 ? _b : undefined
33
+ };
34
+ if (this.debug) {
35
+ logger.logToStderr(`appInfo: ${JSON.stringify(appInfo)}`);
36
+ }
37
+ this
38
+ .ensureAppInfo(logger, args, appInfo)
39
+ .then(_ => {
40
+ if (this.debug) {
41
+ logger.logToStderr(`ensureAppInfo: ${JSON.stringify(appInfo)}`);
42
+ }
43
+ return this.loadAppCatalogUrl(logger, args);
44
+ })
45
+ .then(_ => {
46
+ const requestOptions = {
47
+ url: `${this.appCatalogUrl}/_api/web/tenantappcatalog/downloadteamssolution(${appInfo.id})/$value`,
48
+ headers: {
49
+ accept: 'application/json;odata=nometadata'
50
+ },
51
+ responseType: 'stream'
52
+ };
53
+ return request_1.default.get(requestOptions);
54
+ })
55
+ .then((file) => {
56
+ return new Promise((resolve, reject) => {
57
+ const writer = fs.createWriteStream(appInfo.packageFileName);
58
+ file.data.pipe(writer);
59
+ writer.on('error', err => {
60
+ reject(err);
61
+ });
62
+ writer.on('close', () => {
63
+ resolve(appInfo.packageFileName);
64
+ });
65
+ });
66
+ })
67
+ .then((file) => {
68
+ if (this.verbose) {
69
+ logger.logToStderr(`Package saved to ${file}`);
70
+ }
71
+ cb();
72
+ }, (err) => this.handleRejectedODataJsonPromise(err, logger, cb));
73
+ }
74
+ ensureAppInfo(logger, args, appInfo) {
75
+ if (appInfo.id && appInfo.packageFileName) {
76
+ return Promise.resolve();
77
+ }
78
+ if (args.options.appName && !appInfo.packageFileName) {
79
+ appInfo.packageFileName = this.getPackageNameFromFileName(args.options.appName);
80
+ }
81
+ return this
82
+ .loadAppCatalogUrl(logger, args)
83
+ .then(_ => {
84
+ const appCatalogListName = 'AppCatalog';
85
+ const serverRelativeAppCatalogListUrl = `${urlUtil_1.urlUtil.getServerRelativeSiteUrl(this.appCatalogUrl)}/${appCatalogListName}`;
86
+ let url = `${this.appCatalogUrl}/_api/web/`;
87
+ if (args.options.appItemUniqueId) {
88
+ url += `GetList('${serverRelativeAppCatalogListUrl}')/GetItemByUniqueId('${args.options.appItemUniqueId}')?$expand=File&$select=Id,File/Name`;
89
+ }
90
+ else if (args.options.appItemId) {
91
+ url += `GetList('${serverRelativeAppCatalogListUrl}')/GetItemById(${args.options.appItemId})?$expand=File&$select=File/Name`;
92
+ }
93
+ else if (args.options.appName) {
94
+ url += `getfolderbyserverrelativeurl('${appCatalogListName}')/files('${encodeURIComponent(args.options.appName)}')/ListItemAllFields?$select=Id`;
95
+ }
96
+ const requestOptions = {
97
+ url,
98
+ headers: {
99
+ accept: 'application/json;odata=nometadata'
100
+ },
101
+ responseType: 'json'
102
+ };
103
+ return request_1.default.get(requestOptions);
104
+ })
105
+ .then(res => {
106
+ if (args.options.appItemUniqueId) {
107
+ appInfo.id = parseInt(res.Id);
108
+ if (!appInfo.packageFileName) {
109
+ appInfo.packageFileName = this.getPackageNameFromFileName(res.File.Name);
110
+ }
111
+ return Promise.resolve();
112
+ }
113
+ if (args.options.appItemId) {
114
+ if (!appInfo.packageFileName) {
115
+ appInfo.packageFileName = this.getPackageNameFromFileName(res.File.Name);
116
+ }
117
+ return Promise.resolve();
118
+ }
119
+ // if (args.options.appName)
120
+ // skipped 'if' clause to provide a default code branch
121
+ appInfo.id = parseInt(res.Id);
122
+ return Promise.resolve();
123
+ });
124
+ }
125
+ getPackageNameFromFileName(fileName) {
126
+ return `${path.basename(fileName, path.extname(fileName))}.zip`;
127
+ }
128
+ loadAppCatalogUrl(logger, args) {
129
+ if (this.appCatalogUrl) {
130
+ return Promise.resolve();
131
+ }
132
+ return spo_1.spo
133
+ .getSpoUrl(logger, this.debug)
134
+ .then(spoUrl => this.getAppCatalogSiteUrl(logger, spoUrl, args))
135
+ .then(appCatalogUrl => {
136
+ this.appCatalogUrl = appCatalogUrl;
137
+ });
138
+ }
139
+ options() {
140
+ const options = [
141
+ { option: '--appItemId [appItemId]' },
142
+ { option: '--appItemUniqueId [appItemUniqueId]' },
143
+ { option: '--appName [appName]' },
144
+ { option: '--fileName [fileName]' },
145
+ { option: '-u, --appCatalogUrl [appCatalogUrl]' }
146
+ ];
147
+ const parentOptions = super.options();
148
+ return options.concat(parentOptions);
149
+ }
150
+ validate(args) {
151
+ if (!args.options.appItemUniqueId &&
152
+ !args.options.appItemId &&
153
+ !args.options.appName) {
154
+ return `Specify appItemUniqueId, appItemId or appName`;
155
+ }
156
+ if ((args.options.appItemUniqueId && args.options.appItemId) ||
157
+ (args.options.appItemUniqueId && args.options.appName) ||
158
+ (args.options.appItemId && args.options.appName)) {
159
+ return `Specify appItemUniqueId, appItemId or appName but not multiple`;
160
+ }
161
+ if (args.options.appItemUniqueId &&
162
+ !validation_1.validation.isValidGuid(args.options.appItemUniqueId)) {
163
+ return `${args.options.appItemUniqueId} is not a valid GUID`;
164
+ }
165
+ if (args.options.appItemId &&
166
+ isNaN(args.options.appItemId)) {
167
+ return `${args.options.appItemId} is not a number`;
168
+ }
169
+ if (args.options.fileName &&
170
+ fs.existsSync(args.options.fileName)) {
171
+ return `File ${args.options.fileName} already exists`;
172
+ }
173
+ if (args.options.appCatalogUrl) {
174
+ return validation_1.validation.isValidSharePointUrl(args.options.appCatalogUrl);
175
+ }
176
+ return true;
177
+ }
178
+ }
179
+ module.exports = new SpoAppTeamsPackageDownloadCommand();
180
+ //# sourceMappingURL=app-teamspackage-download.js.map
@@ -10,6 +10,7 @@ exports.default = {
10
10
  APP_LIST: `${prefix} app list`,
11
11
  APP_REMOVE: `${prefix} app remove`,
12
12
  APP_RETRACT: `${prefix} app retract`,
13
+ APP_TEAMSPACKAGE_DOWNLOAD: `${prefix} app teamspackage download`,
13
14
  APP_UNINSTALL: `${prefix} app uninstall`,
14
15
  APP_UPGRADE: `${prefix} app upgrade`,
15
16
  APPPAGE_ADD: `${prefix} apppage add`,
@@ -0,0 +1,56 @@
1
+ # spo app teamspackage download
2
+
3
+ Downloads Teams app package for an SPFx solution deployed to tenant app catalog
4
+
5
+ ## Usage
6
+
7
+ ```sh
8
+ m365 spo app teamspackage download [options]
9
+ ```
10
+
11
+ ## Options
12
+
13
+ `--appItemUniqueId [appItemUniqueId]`
14
+ : The unique ID of the SPFx app to download the Teams package for. Specify `appItemUniqueId`, `appItemId` or `appName`
15
+
16
+ `--appItemId [appItemId]`
17
+ : The ID of the list item behind the SPFx app to download the Teams package for. Specify `appItemUniqueId`, `appItemId` or `appName`
18
+
19
+ `--appName [appName]`
20
+ : The name of the sppkg file to download the Teams package for. Specify `appItemUniqueId`, `appItemId` or `appName`
21
+
22
+ `--fileName [fileName]`
23
+ : Name of the file to save the package to. If not specified will use the name of the sppkg file with a `.zip` extension
24
+
25
+ `-u, --appCatalogUrl [appCatalogUrl]`
26
+ : URL of the tenant app catalog. If not specified, the command will try to autodiscover it
27
+
28
+ --8<-- "docs/cmd/_global.md"
29
+
30
+ ## Remarks
31
+
32
+ Download the Teams app package for an SPFx solution works only for solutions deployed to the tenant app catalog.
33
+
34
+ If you try to download Teams app package for an SPFx solution that doesn't support deployment to Teams, you'll get the _Request failed with status code 404_ error.
35
+
36
+ For maximum performance, specify the URL of the tenant app catalog, the item ID (`appItemId`) of the SPFx package for which you want to download the Teams app package and the name of the file where you want to save the downloaded package to (`fileName`).
37
+
38
+ ## Examples
39
+
40
+ Downloads the Teams app package for the SPFx solution deployed to the tenant app catalog with the ID `1` to a file with .zip extension named after the .sppkg file:
41
+
42
+ ```sh
43
+ m365 spo app teamspackage download --appItemId 1
44
+ ```
45
+
46
+ Downloads the Teams app package for the SPFx solution deployed to the tenant app catalog with the unique item ID `335a5612-3e85-462d-9d5b-c014b5abeac5` to the specified file:
47
+
48
+ ```sh
49
+ m365 spo app teamspackage download --appItemUniqueId 335a5612-3e85-462d-9d5b-c014b5abeac5 --fileName my-app.zip
50
+ ```
51
+
52
+ Downloads the Teams app package for the SPFx solution deployed to the specified tenant app catalog:
53
+
54
+ ```sh
55
+ m365 spo app teamspackage download --appName my-app.sppkg --appCatalogUrl https://contoso.sharepoint.com/sites/appcatalog
56
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnp/cli-microsoft365",
3
- "version": "5.1.0-beta.7b2911b",
3
+ "version": "5.1.0-beta.c518929",
4
4
  "description": "Manage Microsoft 365 and SharePoint Framework projects on any platform",
5
5
  "license": "MIT",
6
6
  "main": "./dist/api.js",