Consolidate studio site set-* commands into single command - #2355
Conversation
|
Reviewing this now |
fredrikekelund
left a comment
There was a problem hiding this comment.
LGTM 👍 This turned out great. I left a couple of small comments on the test file. My only real concern is about cli/lib/run-wp-cli-command.ts, where I'm not sure why we need that change. It would be good to straighten that out before landing this. I'm still approving now to unblock you, though.
| if ( wpChanged ) { | ||
| logger.reportStart( LoggerAction.SET_WP_VERSION, __( 'Changing WordPress version…' ) ); | ||
| const phpVersion = validatePhpVersion( site.phpVersion ); | ||
| const zipUrl = getWordPressVersionUrl( wp! ); |
There was a problem hiding this comment.
| const zipUrl = getWordPressVersionUrl( wp! ); | |
| const zipUrl = getWordPressVersionUrl( wp ); |
Nit, but we don't need to override TS here.
| it( 'should update site name without restart', async () => { | ||
| await runCommand( testSitePath, { name: 'New Name' } ); | ||
|
|
||
| const savedAppdata = ( saveAppdata as jest.Mock ).mock.calls[ 0 ][ 0 ]; | ||
| expect( savedAppdata.sites[ 0 ].name ).toBe( 'New Name' ); | ||
| expect( stopWordPressServer ).not.toHaveBeenCalled(); | ||
| expect( startWordPressServer ).not.toHaveBeenCalled(); | ||
| } ); | ||
|
|
||
| it( 'should not restart running site when only name changes', async () => { | ||
| ( isServerRunning as jest.Mock ).mockResolvedValue( testProcessDescription ); | ||
|
|
||
| await runCommand( testSitePath, { name: 'New Name' } ); | ||
|
|
||
| expect( stopWordPressServer ).not.toHaveBeenCalled(); | ||
| expect( startWordPressServer ).not.toHaveBeenCalled(); | ||
| } ); |
There was a problem hiding this comment.
These two tests are almost identical. We could move the isServerRunning mock to the first test case and remove the second one.
| const createTestSite = (): SiteData => ( { | ||
| id: 'site-1', | ||
| name: 'Test Site', | ||
| path: testSitePath, | ||
| port: 8080, | ||
| phpVersion: '8.0', | ||
| adminUsername: 'admin', | ||
| adminPassword: 'password123', | ||
| } ); | ||
|
|
||
| const createTestSiteWithDomain = (): SiteData => ( { |
There was a problem hiding this comment.
| const createTestSite = (): SiteData => ( { | |
| id: 'site-1', | |
| name: 'Test Site', | |
| path: testSitePath, | |
| port: 8080, | |
| phpVersion: '8.0', | |
| adminUsername: 'admin', | |
| adminPassword: 'password123', | |
| } ); | |
| const createTestSiteWithDomain = (): SiteData => ( { | |
| const getTestSite = (): SiteData => ( { | |
| id: 'site-1', | |
| name: 'Test Site', | |
| path: testSitePath, | |
| port: 8080, | |
| phpVersion: '8.0', | |
| adminUsername: 'admin', | |
| adminPassword: 'password123', | |
| } ); | |
| const getTestSiteWithDomain = (): SiteData => ( { |
Truly nitpicking, but create seems to potentially imply that this function has side effects, whereas get implies that it doesn't. Up to you, though.
| it( 'should update HTTPS setting', async () => { | ||
| const siteWithDomain = createTestSiteWithDomain(); | ||
| ( getSiteByFolder as jest.Mock ).mockResolvedValue( siteWithDomain ); | ||
| ( readAppdata as jest.Mock ).mockResolvedValue( { | ||
| sites: [ siteWithDomain ], | ||
| snapshots: [], | ||
| } ); | ||
|
|
||
| await runCommand( testSitePath, { https: true } ); | ||
|
|
||
| const savedAppdata = ( saveAppdata as jest.Mock ).mock.calls[ 0 ][ 0 ]; | ||
| expect( savedAppdata.sites[ 0 ].enableHttps ).toBe( true ); | ||
| } ); | ||
|
|
||
| it( 'should restart running site when HTTPS changes', async () => { | ||
| const siteWithDomain = createTestSiteWithDomain(); | ||
| ( getSiteByFolder as jest.Mock ).mockResolvedValue( siteWithDomain ); | ||
| ( readAppdata as jest.Mock ).mockResolvedValue( { | ||
| sites: [ siteWithDomain ], | ||
| snapshots: [], | ||
| } ); | ||
| ( isServerRunning as jest.Mock ).mockResolvedValue( testProcessDescription ); | ||
|
|
||
| await runCommand( testSitePath, { https: true } ); | ||
|
|
||
| expect( stopWordPressServer ).toHaveBeenCalledWith( 'site-1' ); | ||
| expect( startWordPressServer ).toHaveBeenCalled(); |
There was a problem hiding this comment.
Let's differentiate these tests by asserting that stopWordPressServer and startWordPressServer weren't called in the first test.
| it( 'should update PHP version', async () => { | ||
| await runCommand( testSitePath, { php: '8.2' } ); | ||
|
|
||
| const savedAppdata = ( saveAppdata as jest.Mock ).mock.calls[ 0 ][ 0 ]; | ||
| expect( savedAppdata.sites[ 0 ].phpVersion ).toBe( '8.2' ); | ||
| } ); | ||
|
|
||
| it( 'should restart running site when PHP version changes', async () => { | ||
| ( isServerRunning as jest.Mock ).mockResolvedValue( testProcessDescription ); | ||
|
|
||
| await runCommand( testSitePath, { php: '8.2' } ); | ||
|
|
||
| expect( stopWordPressServer ).toHaveBeenCalledWith( 'site-1' ); | ||
| expect( startWordPressServer ).toHaveBeenCalled(); |
There was a problem hiding this comment.
Same thing here: let's differentiate the tests by asserting that stopWordPressServer and startWordPressServer weren't called in the first test.
| const mockWpCliResponse = { | ||
| exitCode: Promise.resolve( 0 ), | ||
| }; | ||
|
|
||
| beforeEach( () => { | ||
| ( runWpCliCommand as jest.Mock ).mockResolvedValue( [ | ||
| mockWpCliResponse, | ||
| jest.fn().mockResolvedValue( undefined ), | ||
| ] ); | ||
| } ); |
There was a problem hiding this comment.
| const mockWpCliResponse = { | |
| exitCode: Promise.resolve( 0 ), | |
| }; | |
| beforeEach( () => { | |
| ( runWpCliCommand as jest.Mock ).mockResolvedValue( [ | |
| mockWpCliResponse, | |
| jest.fn().mockResolvedValue( undefined ), | |
| ] ); | |
| } ); | |
| beforeEach( () => { | |
| ( runWpCliCommand as jest.Mock ).mockResolvedValue( [ | |
| { exitCode: Promise.resolve( 0 ) }, | |
| jest.fn().mockResolvedValue( undefined ), | |
| ] ); | |
| } ); |
Another true nit, but we might as well make this a bit more compact.
| it( 'should update isWpAutoUpdating when setting to latest', async () => { | ||
| await runCommand( testSitePath, { wp: 'latest' } ); | ||
|
|
||
| // Second saveAppdata call updates isWpAutoUpdating | ||
| expect( saveAppdata ).toHaveBeenCalledTimes( 2 ); | ||
| } ); |
There was a problem hiding this comment.
| it( 'should update isWpAutoUpdating when setting to latest', async () => { | |
| await runCommand( testSitePath, { wp: 'latest' } ); | |
| // Second saveAppdata call updates isWpAutoUpdating | |
| expect( saveAppdata ).toHaveBeenCalledTimes( 2 ); | |
| } ); | |
| it( 'should update isWpAutoUpdating to false when using specific version', async () => { | |
| await runCommand( testSitePath, { wp: '6.8' } ); | |
| expect( saveAppdata ).toHaveBeenCalledWith( | |
| expect.objectContaining( { | |
| sites: expect.arrayContaining( [ | |
| expect.objectContaining( { isWpAutoUpdating: false } ), | |
| ] ), | |
| } ) | |
| ); | |
| } ); |
Since isWpAutoUpdating defaults to true, I think it's better to test that we set it to false. Also, let's actually test that and not just check the number of times saveAppdata is called.
| expect( startWordPressServer ).toHaveBeenCalledTimes( 1 ); | ||
| } ); | ||
|
|
||
| it( 'should handle name + domain change (only domain triggers restart)', async () => { |
There was a problem hiding this comment.
| it( 'should handle name + domain change (only domain triggers restart)', async () => { | |
| it( 'should restart if options contain changes that require restart and ones that don\'t', async () => { |
There was a problem hiding this comment.
Could you elaborate on why we need this change, @bcotrim? I seem to remember testing the current setup and not having any trouble with it.
There was a problem hiding this comment.
Changing WP version on a site with a custom domain and https, would make the site no longer accessible.
My assumption was that the command to change wordpress version somehow uses the site url.
Using the correct site URL when running the wp upgrade command succeeded and the site was accessible.
Related issues
Proposed Changes
studio site set-*commands (set-domain,set-https,set-php-version,set-wp-version) with a singlestudio site setcommand--name,--domain,--https,--php,--wp--nameoption to change site name (no restart needed, metadata only)Testing Instructions
studio site create --path /tmp/test-sitestudio site start --path /tmp/test-siteTest single options:
studio site set --name "New Name" --path /tmp/test-site- should update name without restartstudio site set --php 8.2 --path /tmp/test-site- should update PHP and restartTest multiple options:
studio site set --name "Test" --php 8.3 --path /tmp/test-site- should apply both changes with single restartTest edge cases:
studio site set --path /tmp/test-site- should show error "At least one option required"studio site set --name "Test" --path /tmp/test-site(when name is already "Test") - should show "No changes to apply"studio site set --php invalid --path /tmp/test-site- should show valid PHP version choicesTest HTTPS with custom domain:
studio site set --domain test.local --https true --path /tmp/test-site- should work correctly with SSLPre-merge Checklist