diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b66fc4e..ce77b7f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,14 +10,12 @@ jobs: include: - os: ubuntu-20.04 mysql-version: 8.0 + - os: ubuntu-20.04 + mysql-version: 5.7 - os: ubuntu-18.04 mysql-version: 8.0 - os: ubuntu-18.04 mysql-version: 5.7 - - os: ubuntu-16.04 - mysql-version: 8.0 - - os: ubuntu-16.04 - mysql-version: 5.7 - os: macos-11.0 mysql-version: 8.0 - os: macos-11.0 @@ -44,14 +42,47 @@ jobs: mysql-version: 5.6 steps: - uses: actions/checkout@v2 - - uses: ./. + + - name: Install mysql + uses: ./. + with: + mysql-version: ${{ matrix.mysql-version }} + database: testdb + username: "1234" + password: "abcd" + + - name: Install mysql second time + uses: ./. with: mysql-version: ${{ matrix.mysql-version }} database: testdb - - run: mysql --version - - run: mysql -e 'SELECT VERSION()' - - run: mysql -e 'SELECT CURRENT_USER()' - - run: mysql -e 'SELECT DATABASE()' - - run: mysql -e "SHOW VARIABLES LIKE 'socket'" - - run: mysqladmin create testdb2 - - run: mysql -D testdb -e 'SELECT DATABASE()' + username: "5678" + password: "efgh" + + - name: Test admin + run: | + mysql --version + mysql -uroot -e 'SELECT * FROM mysql.user;' + mysql -uroot -e 'SELECT VERSION()' + mysql -uroot -e 'SELECT CURRENT_USER()' + mysql -uroot -e 'SELECT DATABASE()' + mysql -uroot -e "SHOW VARIABLES LIKE 'socket'" + mysqladmin -uroot create testdb2 + mysql -uroot -D testdb2 -e 'SELECT DATABASE()' + echo Y | mysqladmin -uroot drop testdb2 + + - name: Test first user + run: | + mysql --version + mysql -u1234 -pabcd -e 'SELECT VERSION()' + mysql -u1234 -pabcd -e 'SELECT CURRENT_USER()' + mysql -u1234 -pabcd -e 'SELECT DATABASE()' + mysql -u1234 -pabcd -e "SHOW VARIABLES LIKE 'socket'" + + - name: Test second user + run: | + mysql --version + mysql -u5678 -pefgh -e 'SELECT VERSION()' + mysql -u5678 -pefgh -e 'SELECT CURRENT_USER()' + mysql -u5678 -pefgh -e 'SELECT DATABASE()' + mysql -u5678 -pefgh -e "SHOW VARIABLES LIKE 'socket'" diff --git a/README.md b/README.md index 6462722..0863309 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,17 @@ Specify a version with: mysql-version: 8.0 ``` +## Optional User and password + +Optionally you can add an additional user. The user can have an optional password. + +```yml + - uses: ankane/setup-mysql@v1 + with: + mysql-version: 8.0 + username: user + password: password +``` Currently supports diff --git a/action.yml b/action.yml index 4956d74..73713e9 100644 --- a/action.yml +++ b/action.yml @@ -1,9 +1,24 @@ name: Setup MySQL +description: install and start the mysql server inputs: mysql-version: description: The MySQL version to download (if necessary) and use + required: true database: description: Database to create + required: false + username: + description: Username for the database + required: false + default: "" + password: + description: Password for the user + default: "" + required: false + install-directory: + description: Installation path of MySQL. Only relevant on Windows + default: ${{ runner.workspace }}\MySQL + required: false runs: using: node12 main: index.js diff --git a/index.js b/index.js index fb0bbd4..174fe79 100644 --- a/index.js +++ b/index.js @@ -12,9 +12,68 @@ function run(command) { execSync(command, {stdio: 'inherit', env: env}); } +function copyFileSync( source, target ) { + // Source https://stackoverflow.com/a/26038979/2127939 + var targetFile = target; + + // If target is a directory, a new file with the same name will be created + if ( fs.existsSync( target ) ) { + if ( fs.lstatSync( target ).isDirectory() ) { + targetFile = path.join( target, path.basename( source ) ); + } + } + + fs.writeFileSync(targetFile, fs.readFileSync(source)); +} + +function copyFolderRecursiveSync( source, target ) { + // Source https://stackoverflow.com/a/26038979/2127939 + var files = []; + + // Check if folder needs to be created or integrated + var targetFolder = path.join( target, path.basename( source ) ); + if ( !fs.existsSync( targetFolder ) ) { + fs.mkdirSync( targetFolder ); + } + + // Copy + if ( fs.lstatSync( source ).isDirectory() ) { + files = fs.readdirSync( source ); + files.forEach( function ( file ) { + var curSource = path.join( source, file ); + if ( fs.lstatSync( curSource ).isDirectory() ) { + copyFolderRecursiveSync( curSource, targetFolder ); + } else { + copyFileSync( curSource, targetFolder ); + } + } ); + } +} + +function integrateFolderRecursiveSync(source, target) { + var files = []; + + // Check if folder needs to be created or integrated + var targetFolder = target; + if ( !fs.existsSync( targetFolder ) ) { + fs.mkdirSync( targetFolder ); + } + // Copy + if ( fs.lstatSync( source ).isDirectory() ) { + files = fs.readdirSync( source ); + files.forEach( function ( file ) { + var curSource = path.join( source, file ); + if ( fs.lstatSync( curSource ).isDirectory() ) { + copyFolderRecursiveSync( curSource, targetFolder ); + } else { + copyFileSync( curSource, targetFolder ); + } + } ); + } +} + function runSafe() { const args = Array.from(arguments); - console.log(args.join(' ')); const command = args.shift(); // spawn is safer and more lightweight than exec const ret = spawnSync(command, args, {stdio: 'inherit'}); @@ -23,6 +82,15 @@ function runSafe() { } } +function checkInstalled(package) { + command = "dpkg -l | grep " + package; + const args = Array.from(arguments); + let env = Object.assign({}, process.env); + delete env.CI; // for Homebrew on macos-11.0 + const ret = execSync(command).toString(); + return !ret || ret !== ""; +} + function addToPath(newPath) { fs.appendFileSync(process.env.GITHUB_PATH, `${newPath}\n`); } @@ -30,7 +98,9 @@ function addToPath(newPath) { const image = process.env['ImageOS']; const defaultVersion = (image == 'ubuntu16' || image == 'ubuntu18') ? '5.7' : '8.0'; const mysqlVersion = parseFloat(process.env['INPUT_MYSQL-VERSION'] || defaultVersion).toFixed(1); - +const username = process.env['INPUT_USERNAME'] || ""; +const password = process.env['INPUT_PASSWORD'] || ""; +const mysqlInstallDirectory = process.env['INPUT_install-directory'] || ""; // TODO make OS-specific if (!['8.0', '5.7', '5.6'].includes(mysqlVersion)) { throw `MySQL version not supported: ${mysqlVersion}`; @@ -45,7 +115,7 @@ function useTmpDir() { process.chdir(tmpDir); } -if (process.platform == 'darwin') { +function installMac() { // install run(`brew install mysql@${mysqlVersion}`); @@ -54,62 +124,78 @@ if (process.platform == 'darwin') { run(`${bin}/mysql.server start`); // add user - run(`${bin}/mysql -e "CREATE USER '$USER'@'localhost' IDENTIFIED BY ''"`); - run(`${bin}/mysql -e "GRANT ALL PRIVILEGES ON *.* TO '$USER'@'localhost'"`); - run(`${bin}/mysql -e "FLUSH PRIVILEGES"`); - + if(username && username !== "") { + run(`${bin}/mysql -e "CREATE USER '${username}'@'localhost' IDENTIFIED BY '${password}'"`); + run(`${bin}/mysql -e "GRANT ALL PRIVILEGES ON *.* TO '${username}'@'localhost'"`); + run(`${bin}/mysql -e "FLUSH PRIVILEGES"`); + } // set path addToPath(bin); -} else if (process.platform == 'win32') { - // install + return bin; +} + +function installWindwos() { + // install const versionMap = { '8.0': '8.0.22', '5.7': '5.7.32', '5.6': '5.6.50' }; - const fullVersion = versionMap[mysqlVersion]; - useTmpDir(); - run(`curl -Ls -o mysql.zip https://dev.mysql.com/get/Downloads/MySQL-${mysqlVersion}/mysql-${fullVersion}-winx64.zip`) - run(`unzip -q mysql.zip`); - fs.mkdirSync(`C:\\Program Files\\MySQL`); - fs.renameSync(`mysql-${fullVersion}-winx64`, `C:\\Program Files\\MySQL\\MySQL Server ${mysqlVersion}`); - - // start - bin = `C:\\Program Files\\MySQL\\MySQL Server ${mysqlVersion}\\bin`; - if (mysqlVersion != '5.6') { - run(`"${bin}\\mysqld" --initialize-insecure`); + bin = `${mysqlInstallDirectory}\\bin`; + if (! fs.existsSync(mysqlInstallDirectory)) { + const fullVersion = versionMap[mysqlVersion]; + useTmpDir(); + run(`curl -Ls -o mysql.zip https://dev.mysql.com/get/Downloads/MySQL-${mysqlVersion}/mysql-${fullVersion}-winx64.zip`) + run(`unzip -q mysql.zip`); + integrateFolderRecursiveSync(`mysql-${fullVersion}-winx64`, mysqlInstallDirectory); + + // start + if (mysqlVersion != '5.6') { + run(`"${bin}\\mysqld" --initialize-insecure`); + } + run(`"${bin}\\mysqld" --install`); + run(`net start MySQL`); + addToPath(bin); + // create windows only user odbc + run(`"${bin}\\mysql" -u root -e "CREATE USER 'ODBC'@'localhost' IDENTIFIED BY ''"`); + run(`"${bin}\\mysql" -u root -e "GRANT ALL PRIVILEGES ON *.* TO 'ODBC'@'localhost'"`); + run(`"${bin}\\mysql" -u root -e "FLUSH PRIVILEGES"`); } - run(`"${bin}\\mysqld" --install`); - run(`net start MySQL`); - - addToPath(bin); run(`"${bin}\\mysql" -u root -e "SELECT VERSION()"`); // add user - run(`"${bin}\\mysql" -u root -e "CREATE USER 'ODBC'@'localhost' IDENTIFIED BY ''"`); - run(`"${bin}\\mysql" -u root -e "GRANT ALL PRIVILEGES ON *.* TO 'ODBC'@'localhost'"`); - run(`"${bin}\\mysql" -u root -e "FLUSH PRIVILEGES"`); -} else { - if (image == 'ubuntu20') { - if (mysqlVersion != '8.0') { - // install - run(`sudo apt-get install mysql-server-${mysqlVersion}`); - } - } else { - if (mysqlVersion != '5.7') { - if (mysqlVersion == '5.6') { - throw `MySQL version not supported yet: ${mysqlVersion}`; - } + if(username && username !== "") { + run(`"${bin}\\mysql" -u root -e "CREATE USER '${username}'@'localhost' IDENTIFIED BY '${password}'"`); + run(`"${bin}\\mysql" -u root -e "GRANT ALL PRIVILEGES ON *.* TO '${username}'@'localhost'"`); + run(`"${bin}\\mysql" -u root -e "FLUSH PRIVILEGES"`); + } + return bin; +} - // install - useTmpDir(); - run(`wget -q -O mysql-apt-config.deb https://dev.mysql.com/get/mysql-apt-config_0.8.16-1_all.deb`); - run(`echo mysql-apt-config mysql-apt-config/select-server select mysql-${mysqlVersion} | sudo debconf-set-selections`); - run(`sudo dpkg -i mysql-apt-config.deb`); - // TODO only update single list - run(`sudo apt-get update`); - run(`sudo apt-get install mysql-server`); +function installLinux() { + // check if it is installed + if(!checkInstalled("mysql-server-${mysqlVersion}")) { + if (image == 'ubuntu20') { + if (mysqlVersion != '8.0') { + // install + run(`sudo apt-get install mysql-server-${mysqlVersion}`); + } + } else { + if (mysqlVersion != '5.7') { + if (mysqlVersion == '5.6') { + throw `MySQL version not supported yet: ${mysqlVersion}`; + } + + // install + useTmpDir(); + run(`wget -q -O mysql-apt-config.deb https://dev.mysql.com/get/mysql-apt-config_0.8.16-1_all.deb`); + run(`echo mysql-apt-config mysql-apt-config/select-server select mysql-${mysqlVersion} | sudo debconf-set-selections`); + run(`sudo dpkg -i mysql-apt-config.deb`); + // TODO only update single list + run(`sudo apt-get update`); + run(`sudo apt-get install mysql-server`); + } } } @@ -117,16 +203,38 @@ if (process.platform == 'darwin') { run('sudo systemctl start mysql'); // remove root password - run(`sudo mysqladmin -proot password ''`); + try { + run(`sudo mysqladmin -proot password ''`); + } catch (error) { + console.error("error on remove password: ", error); + } // add user - run(`sudo mysql -e "CREATE USER '$USER'@'localhost' IDENTIFIED BY ''"`); - run(`sudo mysql -e "GRANT ALL PRIVILEGES ON *.* TO '$USER'@'localhost'"`); - run(`sudo mysql -e "FLUSH PRIVILEGES"`); - + if(username && username !== "") { + run(`sudo mysql -e "CREATE USER '${username}'@'localhost' IDENTIFIED BY '${password}'"`); + run(`sudo mysql -e "GRANT ALL PRIVILEGES ON *.* TO '${username}'@'localhost'"`); + run(`sudo mysql -e "FLUSH PRIVILEGES"`); + } bin = `/usr/bin`; + return bin; +} + + +if (process.platform == 'darwin') { + bin = installMac(); +} else if (process.platform == 'win32') { + bin = installWindwos(); +} else if (process.platform == 'linux') { + bin = installLinux(); +} else { + console.error(process.platform + " is not supported"); } if (database) { - runSafe(path.join(bin, 'mysqladmin'), 'create', database); +try { + run(path.join(bin, 'mysqladmin'), ' -u root create', database); +} catch (error) { + console.error("error on create database: ", error); +} + }