@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
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