def test_update_no_changes(clone_from_github_mock, check_output_mock):
    repo_mock = Mock()
    repo_mock.diff_name_status.return_value = []
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect

    manager = Mock()
    manager.attach_mock(clone_from_github_mock, 'clone_from_github')
    manager.attach_mock(check_output_mock, 'check_output')
    manager.attach_mock(repo_mock, 'repo')

    google_api_ruby_client.update('/tmp', common.GITHUB_ACCOUNT)
    assert manager.mock_calls == [
        call.clone_from_github('google/google-api-ruby-client',
                               '/tmp/google-api-ruby-client',
                               github_account=common.GITHUB_ACCOUNT),
        call.check_output(['bundle', 'install', '--path', 'vendor/bundle'],
                          cwd='/tmp/google-api-ruby-client'),
        call.check_output(['rm', '-rf', 'generated'],
                          cwd='/tmp/google-api-ruby-client'),
        call.check_output([
            'git', 'checkout', 'generated/google/apis/discovery_v1.rb',
            'generated/google/apis/discovery_v1'
        ],
                          cwd='/tmp/google-api-ruby-client'),
        call.check_output(['./script/generate'],
                          cwd='/tmp/google-api-ruby-client'),
        call.repo.diff_name_status(staged=False)
    ]
def test_update_no_changes(clone_from_github_mock, temporary_directory_mock,
                           makedirs_mock, check_output_mock, environ_mock):
    repo_mock = Mock()
    repo_mock.diff_name_status.return_value = []
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect
    temporary_directory_mock.return_value.__enter__.return_value = '/tmp/go'
    environ_mock.copy.return_value = {}

    manager = Mock()
    manager.attach_mock(clone_from_github_mock, 'clone_from_github')
    manager.attach_mock(makedirs_mock, 'makedirs')
    manager.attach_mock(check_output_mock, 'check_output')
    manager.attach_mock(repo_mock, 'repo')

    discovery_artifact_manager.update('/tmp', common.GITHUB_ACCOUNT)
    assert manager.mock_calls == [
        call.clone_from_github('googleapis/discovery-artifact-manager',
                               '/tmp/discovery-artifact-manager',
                               github_account=common.GITHUB_ACCOUNT),
        call.makedirs('/tmp/go/src'),
        call.check_output([
            'ln', '-s', '/tmp/discovery-artifact-manager/src',
            '/tmp/go/src/discovery-artifact-manager'
        ]),
        call.check_output(['go', 'run', 'src/main/updatedisco/main.go'],
                          cwd='/tmp/discovery-artifact-manager',
                          env={'GOPATH': '/tmp/go'}),
        call.repo.add(['discoveries']),
        call.repo.diff_name_status()
    ]
def test_release_latest_version_mismatch(clone_from_github_mock,
                                         check_output_mock):
    repo_mock = Mock()
    repo_mock.latest_tag.return_value = '0.13.6'
    repo_mock.authors_since.return_value = ['*****@*****.**']
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect
    check_output_mock.return_value = 'google-api-client (1.0.0)'

    manager = Mock()
    manager.attach_mock(clone_from_github_mock, 'clone_from_github')
    manager.attach_mock(check_output_mock, 'check_output')
    manager.attach_mock(repo_mock, 'repo')

    with pytest.raises(Exception) as excinfo:
        google_api_ruby_client.release('/tmp', common.GITHUB_ACCOUNT,
                                       _RUBYGEMS_ACCOUNT)
    assert str(excinfo.value) == (
        'latest tag does not match the latest package version on'
        ' RubyGems: 0.13.6 != 1.0.0')
    assert manager.mock_calls == [
        call.clone_from_github('google/google-api-ruby-client',
                               '/tmp/google-api-ruby-client',
                               github_account=common.GITHUB_ACCOUNT),
        call.repo.latest_tag(),
        call.repo.authors_since('0.13.6'),
        call.check_output(['gem', 'search', '-r', '^google-api-client$']),
    ]
def test_release_latest_version_mismatch(clone_from_github_mock,
                                         check_output_mock):
    repo_mock = Mock()
    repo_mock.latest_tag.return_value = '20.1.0'
    repo_mock.authors_since.return_value = ['*****@*****.**']
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect
    check_output_mock.return_value = '20.0.0'

    manager = Mock()
    manager.attach_mock(clone_from_github_mock, 'clone_from_github')
    manager.attach_mock(check_output_mock, 'check_output')
    manager.attach_mock(repo_mock, 'repo')

    with pytest.raises(Exception) as excinfo:
        google_api_nodejs_client.release(
            '/tmp', common.GITHUB_ACCOUNT, _NPM_ACCOUNT)
    assert str(excinfo.value) == (
        'latest tag does not match the latest package version on npm:'
        ' 20.1.0 != 20.0.0')
    assert manager.mock_calls == [
        call.clone_from_github('google/google-api-nodejs-client',
                               '/tmp/google-api-nodejs-client',
                               github_account=common.GITHUB_ACCOUNT),
        call.repo.latest_tag(),
        call.repo.authors_since('20.1.0'),
        call.check_output(['npm', 'view', 'googleapis', 'version'])
    ]
def test_release(clone_from_github_mock, check_output_mock):
    repo_mock = Mock()
    repo_mock.latest_tag.return_value = 'v0.1'
    repo_mock.authors_since.return_value = ['*****@*****.**', '*****@*****.**']
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect

    manager = Mock()
    manager.attach_mock(clone_from_github_mock, 'clone_from_github')
    manager.attach_mock(check_output_mock, 'check_output')
    manager.attach_mock(repo_mock, 'repo')

    google_api_php_client_services.release('/tmp', common.GITHUB_ACCOUNT)
    assert manager.mock_calls == [
        call.clone_from_github('google/google-api-php-client-services',
                               '/tmp/google-api-php-client-services',
                               github_account=common.GITHUB_ACCOUNT),
        call.repo.latest_tag(),
        call.repo.authors_since('v0.1'),
        call.check_output(['composer', 'update'],
                          cwd='/tmp/google-api-php-client-services'),
        call.check_output(['vendor/bin/phpunit', '-c', '.'],
                          cwd='/tmp/google-api-php-client-services'),
        call.repo.tag('v0.2'),
        call.repo.push(tags=True)
    ]
def test_discovery_documents_preferred(clone_from_github_mock, glob_mock,
                                       open_mock):
    repo_mock = Mock()
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect
    glob_mock.glob.return_value = _DISCOVERY_FILENAMES
    open_mock.side_effect = [
        mock_open(read_data='{"id":"discovery:v1"}').return_value,
        mock_open(read_data='{"id":"admin:directory_v1"}').return_value,
        mock_open(read_data='{"id":"admin:datatransfer_v1"}').return_value,
        mock_open(read_data='{"id":"foo:v1"}').return_value,
        # Test that a Discovery document with the same ID as a previous one
        # isn't returned.
        mock_open(read_data='{"id":"foo:v1"}').return_value,
        mock_open(read_data='{"id":"baz:v1"}').return_value,
        mock_open(
            read_data=('{"items":['
                       '{"id":"discovery:v1","preferred":true},'
                       '{"id":"admin:directory_v1","preferred":false},'
                       '{"id":"admin:datatransfer_v1","preferred":false},'
                       '{"id":"foo:v1","preferred":true},'
                       '{"id":"baz:v1","preferred":false}]}')).return_value
    ]
    assert discovery_artifact_manager.discovery_documents(
        '/tmp', preferred=True) == {
            'discovery:v1': 'discoveries/discovery.v1.json',
            'admin:directory_v1': 'discoveries/admin.directory_v1.json',
            'admin:datatransfer_v1': 'discoveries/admin.datatransfer_v1.json',
            'foo:v1': 'discoveries/foo.v1.json'
        }
def test_release_force(clone_from_github_mock,
                       check_output_mock,
                       open_mock,
                       date_mock,
                       expanduser_mock):
    repo_mock = Mock()
    repo_mock.latest_tag.return_value = '20.1.0'
    repo_mock.authors_since.return_value = ['*****@*****.**', '*****@*****.**']
    repo_mock.diff_name_status.return_value = [
        ('apis/foo/v1.ts', _git.Status.ADDED),
        ('apis/baz/v1.ts', _git.Status.UPDATED),
    ]
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect
    check_output_mock.return_value = '20.1.0'
    open_package_json_mock = mock_open(read_data=('{"version": "20.1.0"}'))
    open_changelog_md_mock = mock_open(read_data='...\n')
    open_npmrc_mock = mock_open()
    open_index_md_mock = mock_open(
        read_data=('...\n\n'
                   '### ...\n\n'
                   '* [v20.1.0 (latest)](...)\n'
                   '...\n'))
    open_mock.side_effect = [
        open_package_json_mock.return_value,
        open_package_json_mock.return_value,
        open_changelog_md_mock.return_value,
        open_changelog_md_mock.return_value,
        open_npmrc_mock.return_value,
        open_index_md_mock.return_value,
        open_index_md_mock.return_value
    ]
    date_mock.today.return_value.strftime.return_value = '1 September 2017'
    expanduser_mock.side_effect = lambda x: '/home/test' + x[1:]

    google_api_nodejs_client.release(
        '/tmp', common.GITHUB_ACCOUNT, _NPM_ACCOUNT, force=True)
    # We don't bother verifying all calls in this case, since we only want to
    # verify that the different authors check was passed.
    assert repo_mock.mock_calls == [
        call.latest_tag(),
        call.authors_since('20.1.0'),
        call.diff_name_status(rev='20.1.0'),
        call.commit('20.2.0', 'Alice', '*****@*****.**'),
        call.tag('20.2.0'),
        call.push(),
        call.push(tags=True),
        call.checkout('gh-pages'),
        call.add(['latest', '20.2.0']),
        call.commit('20.2.0', 'Alice', '*****@*****.**'),
        call.push(branch='gh-pages'),
        call.checkout('master')
    ]
def test_update_no_changes(clone_from_github_mock, temporary_directory_mock,
                           listdir_mock, check_output_mock):
    repo_mock = Mock()
    repo_mock.diff_name_status.side_effect = [[], [], []]
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect
    discovery_documents = {'foo:v1': 'foo.v1.json'}
    temporary_directory_mock.return_value.__enter__.return_value = '/tmp2'
    listdir_mock.side_effect = [['Foo', 'Foo.php']]

    manager = Mock()
    manager.attach_mock(clone_from_github_mock, 'clone_from_github')
    manager.attach_mock(check_output_mock, 'check_output')
    manager.attach_mock(repo_mock, 'repo')

    google_api_php_client_services.update('/tmp', common.GITHUB_ACCOUNT,
                                          discovery_documents)
    assert manager.mock_calls == [
        call.clone_from_github('google/google-api-php-client-services',
                               '/tmp/google-api-php-client-services',
                               github_account=common.GITHUB_ACCOUNT),
        call.check_output([
            'virtualenv', '/tmp/google-api-php-client-services/venv', '-p',
            'python2.7'
        ]),
        call.check_output([
            '/tmp/google-api-php-client-services/venv/bin/pip', 'install',
            'google-apis-client-generator==1.4.3'
        ]),
        call.check_output([
            '/tmp/google-api-php-client-services/venv/bin/generate_library',
            '--input=foo.v1.json', '--language=php',
            '--language_variant=1.2.0', '--output_dir=/tmp2'
        ]),
        call.check_output([
            'rm', '-rf',
            '/tmp/google-api-php-client-services/src/Google/Service/Foo.php',
            '/tmp/google-api-php-client-services/src/Google/Service/Foo'
        ]),
        call.check_output([
            'cp', '/tmp2/Foo.php',
            ('/tmp/google-api-php-client-services/src/Google/Service'
             '/Foo.php')
        ]),
        call.check_output([
            'cp', '-r', '/tmp2/Foo',
            '/tmp/google-api-php-client-services/src/Google/Service/Foo'
        ]),
        call.repo.add(['src']),
        call.repo.diff_name_status()
    ]
def test_release_force(clone_from_github_mock, check_output_mock):
    repo_mock = Mock()
    repo_mock.latest_tag.return_value = 'v0.1'
    repo_mock.authors_since.return_value = ['*****@*****.**', '*****@*****.**']
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect

    google_api_php_client_services.release('/tmp',
                                           common.GITHUB_ACCOUNT,
                                           force=True)
    # We don't bother verifying all calls in this case, since we only want to
    # verify that the different authors check was passed.
    assert repo_mock.mock_calls == [
        call.latest_tag(),
        call.authors_since('v0.1'),
        call.tag('v0.2'),
        call.push(tags=True)
    ]
def test_release_different_authors_since_latest_tag(clone_from_github_mock):
    repo_mock = Mock()
    repo_mock.latest_tag.return_value = 'v0.1'
    repo_mock.authors_since.return_value = ['*****@*****.**', '*****@*****.**']
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect

    manager = Mock()
    manager.attach_mock(clone_from_github_mock, 'clone_from_github')
    manager.attach_mock(repo_mock, 'repo')

    google_api_php_client_services.release('/tmp', common.GITHUB_ACCOUNT)
    assert manager.mock_calls == [
        call.clone_from_github('google/google-api-php-client-services',
                               '/tmp/google-api-php-client-services',
                               github_account=common.GITHUB_ACCOUNT),
        call.repo.latest_tag(),
        call.repo.authors_since('v0.1')
    ]
def test_release_force(clone_from_github_mock, check_output_mock, open_mock,
                       expanduser_mock, chmod_mock):
    repo_mock = Mock()
    repo_mock.latest_tag.return_value = '0.13.6'
    repo_mock.authors_since.return_value = ['*****@*****.**', '*****@*****.**']
    repo_mock.diff_name_status.return_value = [
        ('generated/google/apis/foo_v1.rb', _git.Status.ADDED),
        ('generated/google/apis/baz_v1.rb', _git.Status.UPDATED),
    ]
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect
    check_output_mock.return_value = 'google-api-client (0.13.6)'
    open_version_rb_mock = mock_open(
        read_data=('...\n'
                   'module Google\n'
                   '    module Apis\n'
                   '        # Client library version\n'
                   '        VERSION = \'0.13.6\'\n'
                   '    ...\n'))
    open_changelog_md_mock = mock_open(read_data='...\n')
    open_credentials_mock = mock_open()
    open_mock.side_effect = [
        open_version_rb_mock.return_value, open_version_rb_mock.return_value,
        open_changelog_md_mock.return_value,
        open_changelog_md_mock.return_value, open_credentials_mock.return_value
    ]
    expanduser_mock.side_effect = lambda x: '/home/test' + x[1:]

    google_api_ruby_client.release('/tmp',
                                   common.GITHUB_ACCOUNT,
                                   _RUBYGEMS_ACCOUNT,
                                   force=True)
    # We don't bother verifying all calls in this case, since we only want to
    # verify that the different authors check was passed.
    assert repo_mock.mock_calls == [
        call.latest_tag(),
        call.authors_since('0.13.6'),
        call.diff_name_status(rev='0.13.6'),
        call.commit('0.13.7', 'Alice', '*****@*****.**'),
        call.tag('0.13.7'),
        call.push(),
        call.push(tags=True),
    ]
def test_update(clone_from_github_mock, check_output_mock, date_mock):
    repo_mock = Mock()
    repo_mock.diff_name_status.return_value = [
        ('generated/google/apis/foo_v1.rb', _git.Status.ADDED),
        ('generated/google/apis/bar_v1.rb', _git.Status.UPDATED),
        ('generated/google/apis/baz_v1.rb', _git.Status.DELETED)
    ]
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect
    date_mock.today.return_value.isoformat.return_value = '2000-01-01'

    manager = Mock()
    manager.attach_mock(clone_from_github_mock, 'clone_from_github')
    manager.attach_mock(check_output_mock, 'check_output')
    manager.attach_mock(repo_mock, 'repo')

    google_api_ruby_client.update('/tmp', common.GITHUB_ACCOUNT)
    assert manager.mock_calls == [
        call.clone_from_github('google/google-api-ruby-client',
                               '/tmp/google-api-ruby-client',
                               github_account=common.GITHUB_ACCOUNT),
        call.check_output(['bundle', 'install', '--path', 'vendor/bundle'],
                          cwd='/tmp/google-api-ruby-client'),
        call.check_output(['rm', '-rf', 'generated'],
                          cwd='/tmp/google-api-ruby-client'),
        call.check_output([
            'git', 'checkout', 'generated/google/apis/discovery_v1.rb',
            'generated/google/apis/discovery_v1'
        ],
                          cwd='/tmp/google-api-ruby-client'),
        call.check_output(['./script/generate'],
                          cwd='/tmp/google-api-ruby-client'),
        call.repo.diff_name_status(staged=False),
        call.check_output(['bundle', 'exec', 'rake', 'spec'],
                          cwd='/tmp/google-api-ruby-client'),
        call.repo.add(['api_names_out.yaml', 'generated']),
        call.repo.commit(('Autogenerated update (2000-01-01)\n'
                          '\nAdd:\n- foo_v1\n'
                          '\nDelete:\n- baz_v1\n'
                          '\nUpdate:\n- bar_v1'), 'Alice', '*****@*****.**'),
        call.repo.push()
    ]
def test_release_no_commits_since_latest_tag(clone_from_github_mock):
    repo_mock = Mock()
    repo_mock.latest_tag.return_value = '20.1.0'
    repo_mock.authors_since.return_value = []
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect

    manager = Mock()
    manager.attach_mock(clone_from_github_mock, 'clone_from_github')
    manager.attach_mock(repo_mock, 'repo')

    google_api_nodejs_client.release(
        '/tmp', common.GITHUB_ACCOUNT, _NPM_ACCOUNT)
    assert manager.mock_calls == [
        call.clone_from_github('google/google-api-nodejs-client',
                               '/tmp/google-api-nodejs-client',
                               github_account=common.GITHUB_ACCOUNT),
        call.repo.latest_tag(),
        call.repo.authors_since('20.1.0')
    ]
def test_release_invalid_latest_tag(clone_from_github_mock):
    repo_mock = Mock()
    repo_mock.latest_tag.return_value = 'v1.0'
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect

    manager = Mock()
    manager.attach_mock(clone_from_github_mock, 'clone_from_github')
    manager.attach_mock(repo_mock, 'repo')

    with pytest.raises(Exception) as excinfo:
        google_api_php_client_services.release('/tmp', common.GITHUB_ACCOUNT)
    assert str(excinfo.value) == ('latest tag does not match the pattern'
                                  r' "^v0\.([0-9]+)$": v1.0')
    assert manager.mock_calls == [
        call.clone_from_github('google/google-api-php-client-services',
                               '/tmp/google-api-php-client-services',
                               github_account=common.GITHUB_ACCOUNT),
        call.repo.latest_tag()
    ]
def test_discovery_documents(clone_from_github_mock, glob_mock, open_mock):
    repo_mock = Mock()
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect
    glob_mock.glob.return_value = _DISCOVERY_FILENAMES
    open_mock.side_effect = [
        mock_open(read_data='{"id":"discovery:v1"}').return_value,
        mock_open(read_data='{"id":"admin:directory_v1"}').return_value,
        mock_open(read_data='{"id":"admin:datatransfer_v1"}').return_value,
        mock_open(read_data='{"id":"foo:v1"}').return_value,
        mock_open(read_data='{"id":"foo:v1"}').return_value,
        mock_open(read_data='{"id":"baz:v1"}').return_value
    ]
    assert discovery_artifact_manager.discovery_documents('/tmp') == {
        'discovery:v1': 'discoveries/discovery.v1.json',
        'admin:directory_v1': 'discoveries/admin.directory_v1.json',
        'admin:datatransfer_v1': 'discoveries/admin.datatransfer_v1.json',
        'foo:v1': 'discoveries/foo.v1.json',
        'baz:v1': 'discoveries/baz.v1.json'
    }
def test_update(clone_from_github_mock, check_output_mock, date_mock):
    repo_mock = Mock()
    repo_mock.diff_name_status.return_value = [
        ('apis/foo/v1.ts', _git.Status.ADDED),
        ('apis/bar/v1.ts', _git.Status.UPDATED),
        ('apis/baz/v1.ts', _git.Status.DELETED)
    ]
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect
    date_mock.today.return_value.isoformat.return_value = '2000-01-01'

    manager = Mock()
    manager.attach_mock(clone_from_github_mock, 'clone_from_github')
    manager.attach_mock(check_output_mock, 'check_output')
    manager.attach_mock(repo_mock, 'repo')

    google_api_nodejs_client.update('/tmp', common.GITHUB_ACCOUNT)
    assert manager.mock_calls == [
        call.clone_from_github('google/google-api-nodejs-client',
                               '/tmp/google-api-nodejs-client',
                               github_account=common.GITHUB_ACCOUNT),
        call.check_output(['npm', 'install'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.check_output(['node', '--max_old_space_size=2000', '/usr/bin/npm',
                           'run', 'generate-apis'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.repo.diff_name_status(staged=False),
        call.check_output(['node', '--max_old_space_size=2000', '/usr/bin/npm',
                           'run', 'build'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.check_output(['npm', 'run', 'test'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.repo.add(['apis']),
        call.repo.commit(('Autogenerated update (2000-01-01)\n'
                          '\nAdd:\n- foo:v1\n'
                          '\nDelete:\n- baz:v1\n'
                          '\nUpdate:\n- bar:v1'),
                         'Alice',
                         '*****@*****.**'),
        call.repo.push()
    ]
def test_release_no_commits_since_latest_tag(clone_from_github_mock):
    repo_mock = Mock()
    repo_mock.latest_tag.return_value = '1.0.0'
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect

    manager = Mock()
    manager.attach_mock(clone_from_github_mock, 'clone_from_github')
    manager.attach_mock(repo_mock, 'repo')

    with pytest.raises(Exception) as excinfo:
        google_api_ruby_client.release('/tmp', common.GITHUB_ACCOUNT,
                                       _RUBYGEMS_ACCOUNT)
    assert str(excinfo.value) == ('latest tag does not match the pattern'
                                  r' "^0\.([0-9]+)\.([0-9]+)$": 1.0.0')
    assert manager.mock_calls == [
        call.clone_from_github('google/google-api-ruby-client',
                               '/tmp/google-api-ruby-client',
                               github_account=common.GITHUB_ACCOUNT),
        call.repo.latest_tag(),
    ]
def test_update_no_changes(clone_from_github_mock, check_output_mock):
    repo_mock = Mock()
    repo_mock.diff_name_status.return_value = []
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect

    manager = Mock()
    manager.attach_mock(clone_from_github_mock, 'clone_from_github')
    manager.attach_mock(check_output_mock, 'check_output')
    manager.attach_mock(repo_mock, 'repo')

    google_api_nodejs_client.update('/tmp', common.GITHUB_ACCOUNT)
    assert manager.mock_calls == [
        call.clone_from_github('google/google-api-nodejs-client',
                               '/tmp/google-api-nodejs-client',
                               github_account=common.GITHUB_ACCOUNT),
        call.check_output(['npm', 'install'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.check_output(['make', 'generate'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.repo.diff_name_status(staged=False)
    ]
def test_release_major(clone_from_github_mock, check_output_mock, open_mock,
                       date_mock, expanduser_mock):
    repo_mock = Mock()
    repo_mock.latest_tag.return_value = '20.1.0'
    repo_mock.authors_since.return_value = ['*****@*****.**', '*****@*****.**']
    repo_mock.diff_name_status.return_value = [
        ('apis/foo/v1.ts', _git.Status.ADDED),
        ('apis/bar/v1.ts', _git.Status.DELETED),
        ('apis/baz/v1.ts', _git.Status.UPDATED),
    ]
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect
    check_output_mock.return_value = '20.1.0'
    open_package_json_mock = mock_open(read_data=('{"version": "20.1.0"}'))
    open_changelog_md_mock = mock_open(read_data='...\n')
    open_npmrc_mock = mock_open()
    open_index_md_mock = mock_open(read_data=('...\n\n'
                                              '### ...\n\n'
                                              '* [v20.1.0 (latest)](...)\n'
                                              '...\n'))
    open_mock.side_effect = [
        open_package_json_mock.return_value,
        open_package_json_mock.return_value,
        open_changelog_md_mock.return_value,
        open_changelog_md_mock.return_value, open_npmrc_mock.return_value,
        open_index_md_mock.return_value, open_index_md_mock.return_value
    ]
    date_mock.today.return_value.strftime.return_value = '1 September 2017'
    expanduser_mock.side_effect = lambda x: '/home/test' + x[1:]

    manager = Mock()
    manager.attach_mock(clone_from_github_mock, 'clone_from_github')
    manager.attach_mock(check_output_mock, 'check_output')
    manager.attach_mock(open_mock, 'open')
    manager.attach_mock(repo_mock, 'repo')
    manager.attach_mock(open_package_json_mock, 'open_package_json')
    manager.attach_mock(open_changelog_md_mock, 'open_changelog_md')
    manager.attach_mock(open_npmrc_mock, 'open_npmrc')
    manager.attach_mock(open_index_md_mock, 'open_index_md')

    google_api_nodejs_client.release('/tmp', common.GITHUB_ACCOUNT,
                                     _NPM_ACCOUNT)
    assert manager.mock_calls == [
        call.clone_from_github('google/google-api-nodejs-client',
                               '/tmp/google-api-nodejs-client',
                               github_account=common.GITHUB_ACCOUNT),
        call.repo.latest_tag(),
        call.repo.authors_since('20.1.0'),
        call.check_output(['npm', 'view', 'googleapis', 'version']),
        call.repo.diff_name_status(rev='20.1.0'),
        call.open('/tmp/google-api-nodejs-client/package.json'),
        call.open_package_json().__enter__(),
        call.open_package_json().read(),
        call.open_package_json().__exit__(None, None, None),
        call.open('/tmp/google-api-nodejs-client/package.json', 'w'),
        call.open_package_json().__enter__(),
        call.open_package_json().write('{\n  "version": "21.0.0"\n}'),
        call.open_package_json().__exit__(None, None, None),
        call.open('/tmp/google-api-nodejs-client/CHANGELOG.md'),
        call.open_changelog_md().__enter__(),
        call.open_changelog_md().read(),
        call.open_changelog_md().__exit__(None, None, None),
        call.open('/tmp/google-api-nodejs-client/CHANGELOG.md', 'w'),
        call.open_changelog_md().__enter__(),
        call.open_changelog_md().write(('##### 21.0.0 - 1 September 2017\n\n'
                                        '###### Breaking changes\n'
                                        '- Deleted `bar`\n\n'
                                        '###### Backwards compatible changes\n'
                                        '- Added `foo`\n'
                                        '- Updated `baz`\n\n'
                                        '...\n')),
        call.open_changelog_md().__exit__(None, None, None),
        call.check_output(['npm', 'install'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.check_output(['make', 'build'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.check_output(['make', 'test'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.repo.commit('21.0.0', 'Alice', '*****@*****.**'),
        call.repo.tag('21.0.0'),
        call.repo.push(),
        call.repo.push(tags=True),
        call.open('/home/test/.npmrc', 'w'),
        call.open_npmrc().__enter__(),
        call.open_npmrc().write(
            '//registry.npmjs.org/:_authToken=auth_token\n'),
        call.open_npmrc().__exit__(None, None, None),
        call.check_output(['npm', 'publish'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.check_output(['make', 'docs'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.repo.checkout('gh-pages'),
        call.check_output(['rm', '-rf', 'latest'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.check_output(['cp', '-r', 'doc/googleapis/21.0.0', 'latest'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.check_output(['cp', '-r', 'doc/googleapis/21.0.0', '21.0.0'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.open('/tmp/google-api-nodejs-client/index.md'),
        call.open_index_md().__enter__(),
        call.open_index_md().readlines(),
        call.open_index_md().__exit__(None, None, None),
        call.open('/tmp/google-api-nodejs-client/index.md', 'w'),
        call.open_index_md().__enter__(),
        call.open_index_md().write(
            ('...\n\n'
             '### ...\n\n'
             '* [v21.0.0 (latest)]'
             '(http://google.github.io/google-api-nodejs-client/21.0.0'
             '/index.html)\n'
             '* [v20.1.0](...)\n'
             '...\n')),
        call.open_index_md().__exit__(None, None, None),
        call.repo.add(['latest', '21.0.0']),
        call.repo.commit('21.0.0', 'Alice', '*****@*****.**'),
        call.repo.push(branch='gh-pages'),
        call.repo.checkout('master')
    ]
def test_update(clone_from_github_mock, temporary_directory_mock, listdir_mock,
                check_output_mock, date_mock):
    repo_mock = Mock()
    repo_mock.diff_name_status.side_effect = [
        [('src/Google/Service/Foo.php', _git.Status.ADDED),
         ('src/Google/Service/Foo/FooBar.php', _git.Status.ADDED)],
        [('src/Google/Service/Bar.php', _git.Status.UPDATED),
         ('src/Google/Service/Bar/BarFoo.php', _git.Status.ADDED)],
        []  # No change to "baz:v1".
    ]
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect
    discovery_documents = {
        'foo:v1': 'foo.v1.json',
        'bar:v1': 'bar.v1.json',
        'baz:v1': 'baz.v1.json'
    }
    temporary_directory_mock.return_value.__enter__.return_value = '/tmp2'
    listdir_mock.side_effect = [['Foo', 'Foo.php'], ['Bar.php', 'Bar'],
                                ['Baz.php', 'Baz']]
    date_mock.today.return_value.isoformat.return_value = '2000-01-01'

    manager = Mock()
    manager.attach_mock(clone_from_github_mock, 'clone_from_github')
    manager.attach_mock(check_output_mock, 'check_output')
    manager.attach_mock(repo_mock, 'repo')

    google_api_php_client_services.update('/tmp', common.GITHUB_ACCOUNT,
                                          discovery_documents)
    assert manager.mock_calls == [
        call.clone_from_github('google/google-api-php-client-services',
                               '/tmp/google-api-php-client-services',
                               github_account=common.GITHUB_ACCOUNT),
        call.check_output([
            'virtualenv', '/tmp/google-api-php-client-services/venv', '-p',
            'python2.7'
        ]),
        call.check_output([
            '/tmp/google-api-php-client-services/venv/bin/pip', 'install',
            'google-apis-client-generator==1.4.3'
        ]),
        call.check_output([
            '/tmp/google-api-php-client-services/venv/bin/generate_library',
            '--input=foo.v1.json', '--language=php',
            '--language_variant=1.2.0', '--output_dir=/tmp2'
        ]),
        call.check_output([
            'rm', '-rf',
            '/tmp/google-api-php-client-services/src/Google/Service/Foo.php',
            '/tmp/google-api-php-client-services/src/Google/Service/Foo'
        ]),
        call.check_output([
            'cp', '/tmp2/Foo.php',
            ('/tmp/google-api-php-client-services/src/Google/Service'
             '/Foo.php')
        ]),
        call.check_output([
            'cp', '-r', '/tmp2/Foo',
            '/tmp/google-api-php-client-services/src/Google/Service/Foo'
        ]),
        call.repo.add(['src']),
        call.repo.diff_name_status(),
        call.repo.commit('', '_', '_'),
        call.check_output([
            '/tmp/google-api-php-client-services/venv/bin/generate_library',
            '--input=bar.v1.json', '--language=php',
            '--language_variant=1.2.0', '--output_dir=/tmp2'
        ]),
        call.check_output([
            'rm', '-rf',
            '/tmp/google-api-php-client-services/src/Google/Service/Bar.php',
            '/tmp/google-api-php-client-services/src/Google/Service/Bar'
        ]),
        call.check_output([
            'cp', '/tmp2/Bar.php',
            ('/tmp/google-api-php-client-services/src/Google/Service'
             '/Bar.php')
        ]),
        call.check_output([
            'cp', '-r', '/tmp2/Bar',
            '/tmp/google-api-php-client-services/src/Google/Service/Bar'
        ]),
        call.repo.add(['src']),
        call.repo.diff_name_status(),
        call.repo.commit('', '_', '_'),
        call.check_output([
            '/tmp/google-api-php-client-services/venv/bin/generate_library',
            '--input=baz.v1.json', '--language=php',
            '--language_variant=1.2.0', '--output_dir=/tmp2'
        ]),
        call.check_output([
            'rm', '-rf',
            '/tmp/google-api-php-client-services/src/Google/Service/Baz.php',
            '/tmp/google-api-php-client-services/src/Google/Service/Baz'
        ]),
        call.check_output([
            'cp', '/tmp2/Baz.php',
            ('/tmp/google-api-php-client-services/src/Google/Service'
             '/Baz.php')
        ]),
        call.check_output([
            'cp', '-r', '/tmp2/Baz',
            '/tmp/google-api-php-client-services/src/Google/Service/Baz'
        ]),
        call.repo.add(['src']),
        call.repo.diff_name_status(),
        call.check_output(['composer', 'update'],
                          cwd='/tmp/google-api-php-client-services'),
        call.check_output(['vendor/bin/phpunit', '-c', '.'],
                          cwd='/tmp/google-api-php-client-services'),
        call.repo.soft_reset('HEAD~2'),
        call.repo.commit(('Autogenerated update (2000-01-01)\n'
                          '\nAdd:\n- foo:v1\n'
                          '\nUpdate:\n- bar:v1'), 'Alice', '*****@*****.**'),
        call.repo.push()
    ]
def test_release_invalid_index_md(clone_from_github_mock,
                                  check_output_mock,
                                  open_mock,
                                  date_mock,
                                  expanduser_mock):
    repo_mock = Mock()
    repo_mock.latest_tag.return_value = '20.1.0'
    repo_mock.authors_since.return_value = ['*****@*****.**', '*****@*****.**']
    repo_mock.diff_name_status.return_value = [
        ('apis/foo/v1.ts', _git.Status.ADDED),
        ('apis/baz/v1.ts', _git.Status.UPDATED),
    ]
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect
    check_output_mock.return_value = '20.1.0'
    open_package_json_mock = mock_open(read_data=('{"version": "20.1.0"}'))
    open_changelog_md_mock = mock_open(read_data='...\n')
    open_npmrc_mock = mock_open()
    open_index_md_mock = mock_open(read_data=('...\n'))
    open_mock.side_effect = [
        open_package_json_mock.return_value,
        open_package_json_mock.return_value,
        open_changelog_md_mock.return_value,
        open_changelog_md_mock.return_value,
        open_npmrc_mock.return_value,
        open_index_md_mock.return_value,
    ]
    date_mock.today.return_value.strftime.return_value = '1 September 2017'
    expanduser_mock.side_effect = lambda x: '/home/test' + x[1:]

    manager = Mock()
    manager.attach_mock(clone_from_github_mock, 'clone_from_github')
    manager.attach_mock(check_output_mock, 'check_output')
    manager.attach_mock(open_mock, 'open')
    manager.attach_mock(repo_mock, 'repo')
    manager.attach_mock(open_package_json_mock, 'open_package_json')
    manager.attach_mock(open_changelog_md_mock, 'open_changelog_md')
    manager.attach_mock(open_npmrc_mock, 'open_npmrc')
    manager.attach_mock(open_index_md_mock, 'open_index_md')

    with pytest.raises(Exception) as excinfo:
        google_api_nodejs_client.release(
            '/tmp', common.GITHUB_ACCOUNT, _NPM_ACCOUNT)
    assert str(excinfo.value) == 'index.md has an unexpected format'
    assert manager.mock_calls == [
        call.clone_from_github('google/google-api-nodejs-client',
                               '/tmp/google-api-nodejs-client',
                               github_account=common.GITHUB_ACCOUNT),
        call.repo.latest_tag(),
        call.repo.authors_since('20.1.0'),
        call.check_output(['npm', 'view', 'googleapis', 'version']),
        call.repo.diff_name_status(rev='20.1.0'),
        call.open('/tmp/google-api-nodejs-client/package.json'),
        call.open_package_json().__enter__(),
        call.open_package_json().read(),
        call.open_package_json().__exit__(None, None, None),
        call.open('/tmp/google-api-nodejs-client/package.json', 'w'),
        call.open_package_json().__enter__(),
        call.open_package_json().write('{\n  "version": "20.2.0"\n}'),
        call.open_package_json().__exit__(None, None, None),
        call.open('/tmp/google-api-nodejs-client/CHANGELOG.md'),
        call.open_changelog_md().__enter__(),
        call.open_changelog_md().read(),
        call.open_changelog_md().__exit__(None, None, None),
        call.open('/tmp/google-api-nodejs-client/CHANGELOG.md', 'w'),
        call.open_changelog_md().__enter__(),
        call.open_changelog_md().write(('##### 20.2.0 - 1 September 2017\n\n'
                                        '###### Backwards compatible changes\n'
                                        '- Added `foo`\n'
                                        '- Updated `baz`\n\n'
                                        '...\n')),
        call.open_changelog_md().__exit__(None, None, None),
        call.check_output(['npm', 'install'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.check_output(['node', '--max_old_space_size=2000', '/usr/bin/npm',
                           'run', 'build'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.check_output(['npm', 'run', 'test'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.repo.commit('20.2.0', 'Alice', '*****@*****.**'),
        call.repo.tag('20.2.0'),
        call.repo.push(),
        call.repo.push(tags=True),
        call.open('/home/test/.npmrc', 'w'),
        call.open_npmrc().__enter__(),
        call.open_npmrc().write(
            '//registry.npmjs.org/:_authToken=auth_token\n'),
        call.open_npmrc().__exit__(None, None, None),
        call.check_output(['npm', 'publish'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.check_output(['npm', 'run', 'doc'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.repo.checkout('gh-pages'),
        call.check_output(['rm', '-rf', 'latest'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.check_output(['cp', '-r', 'doc/googleapis/20.2.0', 'latest'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.check_output(['cp', '-r', 'doc/googleapis/20.2.0', '20.2.0'],
                          cwd='/tmp/google-api-nodejs-client'),
        call.open('/tmp/google-api-nodejs-client/index.md'),
        call.open_index_md().__enter__(),
        call.open_index_md().readlines(),
        call.open_index_md().__exit__(None, None, None),
    ]
def test_release_patch(clone_from_github_mock, check_output_mock, open_mock,
                       expanduser_mock, chmod_mock):
    repo_mock = Mock()
    repo_mock.latest_tag.return_value = '0.13.6'
    repo_mock.authors_since.return_value = ['*****@*****.**', '*****@*****.**']
    repo_mock.diff_name_status.return_value = [
        ('generated/google/apis/foo_v1.rb', _git.Status.ADDED),
        ('generated/google/apis/baz_v1.rb', _git.Status.UPDATED),
    ]
    side_effect = common.clone_from_github_mock_side_effect(repo_mock)
    clone_from_github_mock.side_effect = side_effect
    check_output_mock.return_value = 'google-api-client (0.13.6)'
    open_version_rb_mock = mock_open(
        read_data=('...\n'
                   'module Google\n'
                   '    module Apis\n'
                   '        # Client library version\n'
                   '        VERSION = \'0.13.6\'\n'
                   '    ...\n'))
    open_changelog_md_mock = mock_open(read_data='...\n')
    open_credentials_mock = mock_open()
    open_mock.side_effect = [
        open_version_rb_mock.return_value, open_version_rb_mock.return_value,
        open_changelog_md_mock.return_value,
        open_changelog_md_mock.return_value, open_credentials_mock.return_value
    ]
    expanduser_mock.side_effect = lambda x: '/home/test' + x[1:]

    manager = Mock()
    manager.attach_mock(clone_from_github_mock, 'clone_from_github')
    manager.attach_mock(check_output_mock, 'check_output')
    manager.attach_mock(open_mock, 'open')
    manager.attach_mock(repo_mock, 'repo')
    manager.attach_mock(chmod_mock, 'chmod')
    manager.attach_mock(open_version_rb_mock, 'open_version_rb')
    manager.attach_mock(open_changelog_md_mock, 'open_changelog_md')
    manager.attach_mock(open_credentials_mock, 'open_credentials')

    google_api_ruby_client.release('/tmp', common.GITHUB_ACCOUNT,
                                   _RUBYGEMS_ACCOUNT)
    assert manager.mock_calls == [
        call.clone_from_github('google/google-api-ruby-client',
                               '/tmp/google-api-ruby-client',
                               github_account=common.GITHUB_ACCOUNT),
        call.repo.latest_tag(),
        call.repo.authors_since('0.13.6'),
        call.check_output(['gem', 'search', '-r', '^google-api-client$']),
        call.repo.diff_name_status(rev='0.13.6'),
        call.open('/tmp/google-api-ruby-client/lib/google/apis/version.rb'),
        call.open_version_rb().__enter__(),
        call.open_version_rb().read(),
        call.open_version_rb().__exit__(None, None, None),
        call.open('/tmp/google-api-ruby-client/lib/google/apis/version.rb',
                  'w'),
        call.open_version_rb().__enter__(),
        call.open_version_rb().write(('...\n'
                                      'module Google\n'
                                      '    module Apis\n'
                                      '        # Client library version\n'
                                      '        VERSION = \'0.13.7\'\n'
                                      '    ...\n')),
        call.open_version_rb().__exit__(None, None, None),
        call.open('/tmp/google-api-ruby-client/CHANGELOG.md'),
        call.open_changelog_md().__enter__(),
        call.open_changelog_md().read(),
        call.open_changelog_md().__exit__(None, None, None),
        call.open('/tmp/google-api-ruby-client/CHANGELOG.md', 'w'),
        call.open_changelog_md().__enter__(),
        call.open_changelog_md().write(('# 0.13.7\n'
                                        '* Backwards compatible changes:\n'
                                        '  * Added `foo_v1`\n'
                                        '  * Updated `baz_v1`\n\n'
                                        '...\n')),
        call.open_changelog_md().__exit__(None, None, None),
        call.check_output(['bundle', 'install', '--path', 'vendor/bundle'],
                          cwd='/tmp/google-api-ruby-client'),
        call.check_output(['bundle', 'exec', 'rake', 'spec'],
                          cwd='/tmp/google-api-ruby-client'),
        call.repo.commit('0.13.7', 'Alice', '*****@*****.**'),
        call.repo.tag('0.13.7'),
        call.repo.push(),
        call.repo.push(tags=True),
        call.check_output(['./script/package'],
                          cwd='/tmp/google-api-ruby-client'),
        call.open('/home/test/.gem/credentials', 'w'),
        call.open_credentials().__enter__(),
        call.open_credentials().write('---\n:rubygems_api_key: api_key\n'),
        call.open_credentials().__exit__(None, None, None),
        call.chmod('/home/test/.gem/credentials', 0o600),
        call.check_output(['gem', 'push', 'pkg/google-api-client-0.13.7.gem'],
                          cwd='/tmp/google-api-ruby-client')
    ]