-
Notifications
You must be signed in to change notification settings - Fork 329
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds m365 spo tenant homesite add
. Closes #6488
#6533
base: main
Are you sure you want to change the base?
Changes from all commits
633959a
7d2a270
f79efd4
a5d46e7
8f7a2d4
4a6dd5b
19ea2ae
0fe6459
de55555
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
import Global from '/docs/cmd/_global.mdx'; | ||
import Tabs from '@theme/Tabs'; | ||
import TabItem from '@theme/TabItem'; | ||
|
||
# spo tenant homesite add | ||
|
||
Adds a Home Site. | ||
|
||
## Usage | ||
|
||
```sh | ||
m365 spo tenant homesite add [options] | ||
``` | ||
|
||
## Options | ||
|
||
```md definition-list | ||
`-u, --url <url>` | ||
: URL of the site to use as a home site. | ||
|
||
`--isInDraftMode [isInDraftMode]` | ||
: Specifies whether the home site is in draft mode. Accepts `true` or `false`. | ||
|
||
`--vivaConnectionsDefaultStart [vivaConnectionsDefaultStart]` | ||
: Specifies whether the home site is the default start for Viva Connections. Accepts `true` or `false`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's mention the default value here as well. |
||
|
||
`--audiences [audiences]` | ||
: Comma-separated list of audience GUIDs. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These are GUIDs of Microsoft Entra groups, right? Let's clarify that a bit more. |
||
|
||
`--order [order]` | ||
: Order of the home site. Must be an integer. | ||
``` | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's not forget to include the global options that are available in every command. |
||
## Examples | ||
|
||
Add a Home Site | ||
|
||
```sh | ||
m365 spo tenant homesite add --url "https://contoso.sharepoint.com/sites/testcomms" | ||
``` | ||
|
||
Add a Home Site with optional parameters | ||
|
||
```sh | ||
m365 spo tenant homesite add --url "https://contoso.sharepoint.com/sites/testcomms" --isInDraftMode true --vivaConnectionsDefaultStart false --audiences "af8c0bc8-7b1b-44b4-b087-ffcc8df70d16,754ff15c-76b1-44cb-88c7-0065a4d3cfb7" --order 2 | ||
``` | ||
## Response | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's add a blank line between content and title |
||
|
||
<Tabs> | ||
<TabItem value="JSON"> | ||
|
||
```json | ||
{ | ||
"Audiences": [], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we add 1 audience value to the response? This way it's clear for the user to know what value they can expect. |
||
"IsInDraftMode": true, | ||
"IsVivaBackendSite": false, | ||
"SiteId": "ca49054c-85f3-41eb-a290-46ffda8f219c", | ||
"TargetedLicenseType": 0, | ||
"Title": "testcommsite", | ||
"Url": "https://contoso.sharepoint.com/sites/testcomms", | ||
"VivaConnectionsDefaultStart": false, | ||
"WebId": "256c4f0f-e372-47b4-a891-b4888e829e20" | ||
} | ||
``` | ||
|
||
</TabItem> | ||
<TabItem value="Text"> | ||
|
||
```text | ||
Audiences : [] | ||
IsInDraftMode : true | ||
IsVivaBackendSite : false | ||
SiteId : ca49054c-85f3-41eb-a290-46ffda8f219c | ||
TargetedLicenseType : 0 | ||
Title : testcommsite | ||
Url : https://contoso.sharepoint.com/sites/testcomms | ||
VivaConnectionsDefaultStart: false | ||
WebId : 256c4f0f-e372-47b4-a891-b4888e829e20 | ||
``` | ||
|
||
</TabItem> | ||
<TabItem value="CSV"> | ||
|
||
```csv | ||
IsInDraftMode,IsVivaBackendSite,SiteId,TargetedLicenseType,Title,Url,VivaConnectionsDefaultStart,WebId | ||
1,0,ca49054c-85f3-41eb-a290-46ffda8f219c,0,testcommsite,https://contoso.sharepoint.com/sites/testcomms,0,256c4f0f-e372-47b4-a891-b4888e829e20 | ||
``` | ||
|
||
</TabItem> | ||
<TabItem value="Markdown"> | ||
|
||
```md | ||
# spo tenant homesite add --url "https://contoso.sharepoint.com/sites/testcomms" | ||
|
||
Date: 12/23/2024 | ||
|
||
## testcommsite (https://contoso.sharepoint.com/sites/testcomms) | ||
|
||
Property | Value | ||
---------|------- | ||
IsInDraftMode | true | ||
IsVivaBackendSite | false | ||
SiteId | ca49054c-85f3-41eb-a290-46ffda8f219c | ||
TargetedLicenseType | 0 | ||
Title | testcommsite | ||
Url | https://contoso.sharepoint.com/sites/testcomms | ||
VivaConnectionsDefaultStart | false | ||
WebId | 256c4f0f-e372-47b4-a891-b4888e829e20 | ||
``` | ||
</TabItem> | ||
</Tabs> | ||
|
||
## More information | ||
|
||
- SharePoint home sites [Viva Connections set up](https://learn.microsoft.com/en-us/viva/connections/set-up-admin-center) | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,175 @@ | ||||||||||||||||
import assert from 'assert'; | ||||||||||||||||
import sinon from 'sinon'; | ||||||||||||||||
import auth from '../../../../Auth.js'; | ||||||||||||||||
import { cli } from '../../../../cli/cli.js'; | ||||||||||||||||
import { Logger } from '../../../../cli/Logger.js'; | ||||||||||||||||
import { CommandError } from '../../../../Command.js'; | ||||||||||||||||
import { CommandInfo } from '../../../../cli/CommandInfo.js'; | ||||||||||||||||
import request from '../../../../request.js'; | ||||||||||||||||
import { telemetry } from '../../../../telemetry.js'; | ||||||||||||||||
import { pid } from '../../../../utils/pid.js'; | ||||||||||||||||
import { session } from '../../../../utils/session.js'; | ||||||||||||||||
import { sinonUtil } from '../../../../utils/sinonUtil.js'; | ||||||||||||||||
import commands from '../../commands.js'; | ||||||||||||||||
import command from './tenant-homesite-add.js'; | ||||||||||||||||
|
||||||||||||||||
describe(commands.TENANT_HOMESITE_ADD, () => { | ||||||||||||||||
let log: string[]; | ||||||||||||||||
let logger: Logger; | ||||||||||||||||
let loggerLogSpy: sinon.SinonSpy; | ||||||||||||||||
let commandInfo: CommandInfo; | ||||||||||||||||
const homeSite = "https://contoso.sharepoint.com/sites/testcomms"; | ||||||||||||||||
const homeSites = { | ||||||||||||||||
"Audiences": [], | ||||||||||||||||
"IsInDraftMode": true, | ||||||||||||||||
"IsVivaBackendSite": false, | ||||||||||||||||
"SiteId": "ca49054c-85f3-41eb-a290-46ffda8f219c", | ||||||||||||||||
"TargetedLicenseType": 0, | ||||||||||||||||
"Title": "testcommsite", | ||||||||||||||||
"Url": homeSite, | ||||||||||||||||
"VivaConnectionsDefaultStart": false, | ||||||||||||||||
"WebId": "256c4f0f-e372-47b4-a891-b4888e829e20" | ||||||||||||||||
}; | ||||||||||||||||
|
||||||||||||||||
const homeSiteConfig = { | ||||||||||||||||
"Audiences": [ | ||||||||||||||||
{ | ||||||||||||||||
"Email": "[email protected]", | ||||||||||||||||
"Id": "af8c0bc8-7b1b-44b4-b087-ffcc8df70d16", | ||||||||||||||||
"Title": "SharingTest Members" | ||||||||||||||||
} | ||||||||||||||||
], | ||||||||||||||||
"IsInDraftMode": true, | ||||||||||||||||
"IsVivaBackendSite": false, | ||||||||||||||||
"SiteId": "ca49054c-85f3-41eb-a290-46ffda8f219c", | ||||||||||||||||
"TargetedLicenseType": 0, | ||||||||||||||||
"Title": "testcommsite", | ||||||||||||||||
"Url": "https://contoso.sharepoint.com/sites/testcomms", | ||||||||||||||||
"VivaConnectionsDefaultStart": false, | ||||||||||||||||
"WebId": "256c4f0f-e372-47b4-a891-b4888e829e20" | ||||||||||||||||
}; | ||||||||||||||||
|
||||||||||||||||
before(() => { | ||||||||||||||||
sinon.stub(auth, 'restoreAuth').resolves(); | ||||||||||||||||
sinon.stub(telemetry, 'trackEvent').returns(); | ||||||||||||||||
sinon.stub(pid, 'getProcessName').returns(''); | ||||||||||||||||
sinon.stub(session, 'getId').returns(''); | ||||||||||||||||
auth.connection.active = true; | ||||||||||||||||
auth.connection.spoUrl = 'https://contoso.sharepoint.com'; | ||||||||||||||||
}); | ||||||||||||||||
|
||||||||||||||||
beforeEach(() => { | ||||||||||||||||
log = []; | ||||||||||||||||
logger = { | ||||||||||||||||
log: async (msg: string) => { | ||||||||||||||||
log.push(msg); | ||||||||||||||||
}, | ||||||||||||||||
logRaw: async (msg: string) => { | ||||||||||||||||
log.push(msg); | ||||||||||||||||
}, | ||||||||||||||||
logToStderr: async (msg: string) => { | ||||||||||||||||
log.push(msg); | ||||||||||||||||
} | ||||||||||||||||
}; | ||||||||||||||||
loggerLogSpy = sinon.spy(logger, 'log'); | ||||||||||||||||
commandInfo = cli.getCommandInfo(command); | ||||||||||||||||
}); | ||||||||||||||||
|
||||||||||||||||
afterEach(() => { | ||||||||||||||||
sinonUtil.restore([ | ||||||||||||||||
request.post | ||||||||||||||||
]); | ||||||||||||||||
}); | ||||||||||||||||
|
||||||||||||||||
after(() => { | ||||||||||||||||
sinon.restore(); | ||||||||||||||||
auth.connection.active = false; | ||||||||||||||||
auth.connection.spoUrl = undefined; | ||||||||||||||||
}); | ||||||||||||||||
|
||||||||||||||||
it('has correct name', () => { | ||||||||||||||||
assert.strictEqual(command.name, commands.TENANT_HOMESITE_ADD); | ||||||||||||||||
}); | ||||||||||||||||
|
||||||||||||||||
it('has a description', () => { | ||||||||||||||||
assert.notStrictEqual(command.description, null); | ||||||||||||||||
}); | ||||||||||||||||
|
||||||||||||||||
it('correctly logs command response', async () => { | ||||||||||||||||
sinon.stub(request, 'post').callsFake(async (opts) => { | ||||||||||||||||
if (opts.url === `https://contoso-admin.sharepoint.com/_api/SPHSite/AddHomeSite`) { | ||||||||||||||||
return homeSites; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
throw opts.url; | ||||||||||||||||
}); | ||||||||||||||||
|
||||||||||||||||
await command.action(logger, { options: { url: homeSite, verbose: true } }); | ||||||||||||||||
assert(loggerLogSpy.calledWith(homeSites)); | ||||||||||||||||
}); | ||||||||||||||||
|
||||||||||||||||
it('adds a home site with the specified URL, isInDraftMode, vivaConnectionsDefaultStart, and audiences', async () => { | ||||||||||||||||
sinon.stub(request, 'post').callsFake(async (opts) => { | ||||||||||||||||
if (opts.url === `https://contoso-admin.sharepoint.com/_api/SPHSite/AddHomeSite`) { | ||||||||||||||||
return homeSiteConfig; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
throw 'Invalid request'; | ||||||||||||||||
}); | ||||||||||||||||
|
||||||||||||||||
await command.action(logger, { | ||||||||||||||||
options: { | ||||||||||||||||
url: homeSite, | ||||||||||||||||
isInDraftMode: 'true', | ||||||||||||||||
vivaConnectionsDefaultStart: 'false', | ||||||||||||||||
audiences: 'af8c0bc8-7b1b-44b4-b087-ffcc8df70d16,754ff15c-76b1-44cb-88c7-0065a4d3cfb7', | ||||||||||||||||
order: 2 | ||||||||||||||||
} | ||||||||||||||||
}); | ||||||||||||||||
assert(loggerLogSpy.calledWith(homeSiteConfig)); | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of checking just this, let's check if we actually provided the right arguments in our request to SharePoint. An example can be found here: cli-microsoft365/src/m365/spo/commands/site/site-admin-add.spec.ts Lines 314 to 320 in db90bed
|
||||||||||||||||
}); | ||||||||||||||||
|
||||||||||||||||
it('correctly handles invalid GUID in audiences', async () => { | ||||||||||||||||
const result = await command.validate({ | ||||||||||||||||
options: { | ||||||||||||||||
url: homeSite, | ||||||||||||||||
audiences: "invalidGuid,af8c0bc8-7b1b-44b4-b087-ffcc8df70d16" | ||||||||||||||||
} | ||||||||||||||||
}, commandInfo); | ||||||||||||||||
assert.strictEqual(result, `invalidGuid is not a valid GUID`); | ||||||||||||||||
}); | ||||||||||||||||
|
||||||||||||||||
it('correctly handles non-integer order', async () => { | ||||||||||||||||
const result = await command.validate({ | ||||||||||||||||
options: { | ||||||||||||||||
url: homeSite, | ||||||||||||||||
order: 'invalid-order' | ||||||||||||||||
} | ||||||||||||||||
}, commandInfo); | ||||||||||||||||
assert.strictEqual(result, 'Order must be an integer'); | ||||||||||||||||
}); | ||||||||||||||||
|
||||||||||||||||
it('fails validation if the url is not a valid SharePoint url', async () => { | ||||||||||||||||
const actual = await command.validate({ | ||||||||||||||||
options: { | ||||||||||||||||
url: "test" | ||||||||||||||||
} | ||||||||||||||||
}, commandInfo); | ||||||||||||||||
assert.notStrictEqual(actual, true); | ||||||||||||||||
}); | ||||||||||||||||
|
||||||||||||||||
it('passes validation with URL', async () => { | ||||||||||||||||
const actual = await command.validate({ | ||||||||||||||||
options: { | ||||||||||||||||
url: homeSite | ||||||||||||||||
} | ||||||||||||||||
}, commandInfo); | ||||||||||||||||
assert.strictEqual(actual, true); | ||||||||||||||||
}); | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's add a similar test with all possible options. |
||||||||||||||||
|
||||||||||||||||
it('correctly handles OData error when adding a home site', async () => { | ||||||||||||||||
sinon.stub(request, 'post').rejects({ error: { 'odata.error': { message: { value: 'An error has occurred' } } } }); | ||||||||||||||||
|
||||||||||||||||
await assert.rejects(command.action(logger, { options: { url: 'https://....' } } as any), new CommandError('An error has occurred')); | ||||||||||||||||
}); | ||||||||||||||||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's also mention which value is the default value.