From 9932b03c5ec88c4638b554ef50643f0804c7b08f Mon Sep 17 00:00:00 2001 From: "microsoft-github-operations[bot]" <55726097+microsoft-github-operations[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2019 08:12:12 +0000 Subject: [PATCH] Initial commit --- .gitignore | 332 +++++++++++++++++++++++++++++++++++++++++++++ CODE_OF_CONDUCT.md | 9 ++ LICENSE | 21 +++ README.md | 141 +++++++++++++++++++ SECURITY.md | 41 ++++++ action.yml | 17 +++ package-lock.json | 35 +++++ package.json | 29 ++++ src/main.ts | 135 ++++++++++++++++++ src/utils.ts | 47 +++++++ tsconfig.json | 60 ++++++++ 11 files changed, 867 insertions(+) create mode 100644 .gitignore create mode 100644 CODE_OF_CONDUCT.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 SECURITY.md create mode 100644 action.yml create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/main.ts create mode 100644 src/utils.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..407eeaf --- /dev/null +++ b/.gitignore @@ -0,0 +1,332 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +lib + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..c72a574 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,9 @@ +# Microsoft Open Source Code of Conduct + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). + +Resources: + +- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) +- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) +- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3d8b93b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/README.md b/README.md new file mode 100644 index 0000000..c2221e6 --- /dev/null +++ b/README.md @@ -0,0 +1,141 @@ +# Azure CLI GitHub Action + + +With Azure CLI GitHub Action, you can automate your workflow by executing [Azure CLI](https://github.com/Azure/azure-cli) commands to manage Azure resources inside of an Action. + +The action executes the Azure CLI Bash script on a user defined Azure CLI version. If the user does not specify a version, latest CLI version is used. +Read more about various Azure CLI versions [here](https://github.com/Azure/azure-cli/releases). + +- `azcliversion` – **Optional** Example: 2.0.72, Default: latest +- `inlineScript` – **Required** + +The definition of this GitHub Action is in [action.yml](https://github.com/Azure/CLI/blob/master/action.yml). The action status is determined by the exit code returned by the script rather than StandardError stream. + +## Sample workflow + +### Dependencies on other GitHub Actions +* [Azure Login](https://github.com/Azure/login) – **Required** Login with your Azure credentials +* [Checkout](https://github.com/actions/checkout) – **Optional** To execute the scripts present in your repository +### Workflow to execute an AZ CLI script of a specific CLI version +``` +# File: .github/workflows/workflow.yml + +on: [push] + +name: AzureCLISample + +jobs: + + build-and-deploy: + runs-on: ubuntu-latest + steps: + + - name: Azure Login + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Azure CLI script + uses: azure/CLI@v1 + with: + azcliversion: 2.0.72 + inlineScript: | + az account show + az storage -h +``` + +### Workflow to execute an AZ CLI script of a specific CLI version via file present in your repository. +``` +# File: .github/workflows/workflowForFile.yml + +on: [push] + +name: AzureCLISampleForFile + +jobs: + + build-and-deploy: + runs-on: ubuntu-latest + steps: + + - name: Azure Login + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Checkout + uses: actions/checkout@v1 + + - name: Azure CLI script file + uses: azure/CLI@v1 + with: + azcliversion: 2.0.72 + inlineScript: | + chmod +x $GITHUB_WORKSPACE/sampleScript.sh + $GITHUB_WORKSPACE/sampleScript.sh +``` + * [GITHUB_WORKSPACE](https://help.github.com/en/github/automating-your-workflow-with-github-actions/virtual-environments-for-github-hosted-runners) is the environment variable provided by GitHub which represents the root of your repository. + +### Configure Azure credentials as GitHub Secret: + +To use any credentials like Azure Service Principal,add them as [secrets](https://help.github.com/en/articles/virtual-environments-for-github-actions#creating-and-using-secrets-encrypted-variables) in the GitHub repository and then use them in the workflow. + +Follow the steps to configure the secret: + * Define a new secret under your repository settings, Add secret menu + * Store the output of the below [az cli](https://docs.microsoft.com/en-us/cli/azure/?view=azure-cli-latest) command as the value of secret variable 'AZURE_CREDENTIALS' +```bash + + az ad sp create-for-rbac --name "myApp" --role contributor \ + --scopes /subscriptions/{subscription-id}/resourceGroups/{resource-group} \ + --sdk-auth + + # Replace {subscription-id}, {resource-group} with the subscription, resource group details + + # The command should output a JSON object similar to this: + + { + "clientId": "", + "clientSecret": "", + "subscriptionId": "", + "tenantId": "", + (...) + } + +``` + * Now in the workflow file in your branch: `.github/workflows/workflow.yml` replace the secret in Azure login action with your secret (Refer to the example above) + + +## Azure CLI Action metadata file + +``` +# File: action.yml + +# Automate your GitHub workflows using Azure CLI scripts. +name: 'Azure CLI' +description: 'The action is used to execute Azure CLI commands' +inputs: + inlineScript: + description: 'Specify the script here' + required: true + azcliversion: + description: 'Azure CLI version to be used to execute the script' + required: false + default: 'latest' +runs: + using: 'node12' + main: 'lib/main.js' +``` + +# Contributing + +This project welcomes contributions and suggestions. Most contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us +the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. + +When you submit a pull request, a CLA bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..7ab49eb --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,41 @@ + + +## Security + +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). + +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). + +If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). + + diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..7c41371 --- /dev/null +++ b/action.yml @@ -0,0 +1,17 @@ +# Azure CLI Action +name: 'Azure CLI' +description: 'Automate your GitHub workflows using Azure CLI scripts.' +inputs: + inlineScript: + description: 'Specify the script here' + required: true + azcliversion: + description: 'Azure CLI version to be used to execute the script. If not provided, latest version is used' + required: false + default: 'latest' +branding: + icon: 'login.svg' + color: 'blue' +runs: + using: 'node12' + main: 'lib/main.js' diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..6729d57 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,35 @@ +{ + "name": "cli", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@actions/core": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.0.tgz", + "integrity": "sha512-ZKdyhlSlyz38S6YFfPnyNgCDZuAF2T0Qv5eHflNWytPS8Qjvz39bZFMry9Bb/dpSnqWcNeav5yM2CTYpJeY+Dw==" + }, + "@actions/exec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.0.1.tgz", + "integrity": "sha512-nvFkxwiicvpzNiCBF4wFBDfnBvi7xp/as7LE1hBxBxKG2L29+gkIPBiLKMVORL+Hg3JNf07AKRfl0V5djoypjQ==" + }, + "@actions/io": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.0.1.tgz", + "integrity": "sha512-rhq+tfZukbtaus7xyUtwKfuiCRXd1hWSfmJNEpFgBQJ4woqPEpsBw04awicjwz9tyG2/MVhAEMfVn664Cri5zA==" + }, + "@types/node": { + "version": "12.12.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.0.tgz", + "integrity": "sha512-6N8Sa5AaENRtJnpKXZgvc119PKxT1Lk9VPy4kfT8JF23tIe1qDfaGkBR2DRKJFIA7NptMz+fps//C6aLi1Uoug==", + "dev": true + }, + "typescript": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.4.tgz", + "integrity": "sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..a51169f --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "cli", + "version": "1.0.0", + "description": "Automate your GitHub workflows using Azure CLI scripts.", + "main": "lib/main.js", + "scripts": { + "build": "tsc", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Azure/CLI.git" + }, + "author": "Microsoft", + "license": "MIT", + "devDependencies": { + "@types/node": "^12.7.11", + "typescript": "^3.6.3" + }, + "dependencies": { + "@actions/core": "^1.1.3", + "@actions/exec": "^1.0.1", + "@actions/io": "^1.0.1" + }, + "bugs": { + "url": "https://github.com/Azure/CLI/issues" + }, + "homepage": "https://github.com/Azure/CLI#readme" +} diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..df65912 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,135 @@ +import * as core from '@actions/core'; +import * as exec from '@actions/exec'; +import * as io from '@actions/io'; +import * as os from 'os'; +import * as path from 'path'; + +import { createScriptFile, TEMP_DIRECTORY, NullOutstreamStringWritable, deleteFile, getCurrentTime } from './utils'; + +const START_SCRIPT_EXECUTION_MARKER: string = `Starting script execution via docker image mcr.microsoft.com/azure-cli:`; +const BASH_ARG: string = `bash --noprofile --norc -e `; +const CONTAINER_WORKSPACE: string = '/github/workspace'; +const CONTAINER_TEMP_DIRECTORY: string = '/_temp'; + +const run = async () => { + var scriptFileName: string = ''; + const CONTAINER_NAME = `MICROSOFT_AZURE_CLI_${getCurrentTime()}_CONTAINER`; + try { + if (process.env.RUNNER_OS != 'Linux') { + core.setFailed('Please use Linux based OS as a runner.'); + return; + } + + let inlineScript: string = core.getInput('inlineScript', { required: true }); + let azcliversion: string = core.getInput('azcliversion', { required: true }).trim().toLowerCase(); + + if (!(await checkIfValidCLIVersion(azcliversion))) { + core.setFailed('Please enter a valid azure cli version. \nSee available versions: https://github.com/Azure/azure-cli/releases.'); + return; + } + + if (!inlineScript.trim()) { + core.setFailed('Please enter a valid script.'); + return; + } + inlineScript = ` set -e >&2; echo '${START_SCRIPT_EXECUTION_MARKER}' >&2; ${inlineScript}`; + scriptFileName = await createScriptFile(inlineScript); + let startCommand: string = ` ${BASH_ARG}${CONTAINER_TEMP_DIRECTORY}/${scriptFileName} `; + + /* + For the docker run command, we are doing the following + - Set the working directory for docker continer + - volume mount the GITHUB_WORKSPACE env variable (path where users checkout code is present) to work directory of container + - voulme mount .azure session token file between host and container, + - volume mount temp directory between host and container, inline script file is created in temp directory + */ + let command: string = `run --workdir ${CONTAINER_WORKSPACE} -v ${process.env.GITHUB_WORKSPACE}:${CONTAINER_WORKSPACE} `; + command += ` -v ${process.env.HOME}/.azure:/root/.azure -v ${TEMP_DIRECTORY}:${CONTAINER_TEMP_DIRECTORY} `; + command += `-e GITHUB_WORKSPACE=${CONTAINER_WORKSPACE} --name ${CONTAINER_NAME}`; + command += ` mcr.microsoft.com/azure-cli:${azcliversion} ${startCommand}`; + console.log(`${START_SCRIPT_EXECUTION_MARKER}${azcliversion}`); + await executeDockerCommand(command); + console.log("az script ran successfully."); + } catch (error) { + core.error(error); + core.setFailed(error.stderr); + } + finally { + // clean up + const scriptFilePath: string = path.join(TEMP_DIRECTORY, scriptFileName); + await deleteFile(scriptFilePath); + console.log("cleaning up container..."); + await executeDockerCommand(` container rm --force ${CONTAINER_NAME} `, true); + } +}; + +const checkIfValidCLIVersion = async (azcliversion: string): Promise => { + const allVersions: Array = await getAllAzCliVersions(); + if (!allVersions || allVersions.length == 0) { + return true; + } + return allVersions.some((eachVersion) => eachVersion.toLowerCase() === azcliversion); +} + +const getAllAzCliVersions = async (): Promise> => { + var outStream: string = ''; + var execOptions: any = { + outStream: new NullOutstreamStringWritable({ decodeStrings: false }), + listeners: { + stdout: (data: any) => outStream += data.toString() + os.EOL, //outstream contains the list of all the az cli versions + } + }; + + try { + await exec.exec(`curl --location -s https://mcr.microsoft.com/v2/azure-cli/tags/list`, [], execOptions) + if (outStream && JSON.parse(outStream).tags) { + return JSON.parse(outStream).tags; + } + } catch (error) { + // if output is 404 page not found, please verify the url + core.warning(`Unable to fetch all az cli versions, please report it as an issue on https://github.com/Azure/CLI/issues. Output: ${outStream}, Error: ${error}`); + } + return []; +} + +const executeDockerCommand = async (dockerCommand: string, continueOnError: boolean = false): Promise => { + + const dockerTool: string = await io.which("docker", true); + var errorStream: string = ''; + var shouldOutputErrorStream: boolean = false; + var execOptions: any = { + outStream: new NullOutstreamStringWritable({ decodeStrings: false }), + listeners: { + stdout: (data: any) => console.log(data.toString()), //to log the script output while the script is running. + errline: (data: string) => { + if (!shouldOutputErrorStream) { + errorStream += data + os.EOL; + } + else { + console.log(data); + } + if (data.trim() === START_SCRIPT_EXECUTION_MARKER) { + shouldOutputErrorStream = true; + errorStream = ''; // Flush the container logs. After this, script error logs will be tracked. + } + } + } + }; + var exitCode; + try { + exitCode = await exec.exec(`"${dockerTool}" ${dockerCommand}`, [], execOptions); + } catch (error) { + if (!continueOnError) { + throw error; + } + core.warning(error); + } + finally { + if (exitCode !== 0 && !continueOnError) { + throw new Error(errorStream || 'az cli script failed.'); + } + core.warning(errorStream) + } +} + +run(); \ No newline at end of file diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..594d315 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,47 @@ +import stream = require('stream'); +import * as exec from '@actions/exec'; +import * as core from '@actions/core'; +import * as path from 'path'; +import * as os from 'os'; +import * as fs from 'fs'; + +export const TEMP_DIRECTORY: string = process.env.RUNNER_TEMP || os.tmpdir(); + +export const createScriptFile = async (inlineScript: string): Promise => { + const fileName: string = `AZ_CLI_GITHUB_ACTION_${getCurrentTime().toString()}.sh`; + const filePath: string = path.join(TEMP_DIRECTORY, fileName); + fs.writeFileSync(filePath, `${inlineScript}`); + await giveExecutablePermissionsToFile(filePath); + return fileName; +} + + +export const deleteFile = async (filePath: string) => { + if (fs.existsSync(filePath)) { + try { + fs.unlinkSync(filePath); + } + catch (err) { + core.warning(err.toString()); + } + } +} + +export const giveExecutablePermissionsToFile = async (filePath: string): Promise => await exec.exec(`chmod +x ${filePath}`, [], { silent: true }) + +export const getCurrentTime = (): number => { + return new Date().getTime(); +} + +export class NullOutstreamStringWritable extends stream.Writable { + + constructor(options: any) { + super(options); + } + + _write(data: any, encoding: string, callback: Function): void { + if (callback) { + callback(); + } + } +}; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..8f3e098 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,60 @@ +{ + "compilerOptions": { + /* Basic Options */ + "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./lib", /* Redirect output structure to the directory. */ + "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": false, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + } + } \ No newline at end of file