From 5840b5b78bda8475f859162f395e5919f44b90be Mon Sep 17 00:00:00 2001 From: Dave McConnell Date: Mon, 2 Mar 2020 15:38:29 +0000 Subject: [PATCH] Squashing commits for first pass at implementing action --- .github/workflows/main.yml | 13 ++- README.md | 67 ++++++------- action.yml | 12 ++- index.js | 196 +++++++++++++++++++++---------------- 4 files changed, 158 insertions(+), 130 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c4b14d2..7ee4561 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,17 +1,16 @@ on: [push] jobs: - hello_world_job: + Test_Job: runs-on: ubuntu-latest - name: A job to say hello + name: Test job steps: - # To use this repository's private action, you must check out the repository - # - name: Checkout - # uses: actions/checkout@v2 + - name: Checkout + uses: actions/checkout@v2 - name: Test this action - uses: ./ # Uses an action in the root directory + uses: ./ with: access-token: ${{ secrets.CR_TOKEN }} source-charts-folder: 'test-charts' - destination-repo: ${{ secrets.CR_TOKEN }} + destination-repo: dave-mcconnell/helm-charts destination-charts-folder: 'charts' diff --git a/README.md b/README.md index 6a57898..2fd0b8d 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,15 @@ -# Helm Publish +# Helm Publish For Microservices GitHub Action to package and deploy your Helm charts to GitHub Pages -Based upon [gatsby-gh-pages-action](https://github.com/enriikke/gatsby-gh-pages-action) +Based upon [helm-gh-pages-action](https://github.com/funkypenguin/helm-gh-pages-action) ## Usage -This GitHub Action will run `helm package` for every chart folder in the `charts` directory of your repository and -deploy it to GitHub Pages for you! Here's a basic workflow example: +This GitHub Action allows you to co-locate your Helm Chart alongside your application code. When pushing/submitting a pull request, the Helm Chart can be produced as an artifact to a Helm Chart repository hosted using GitHub Pages. + +The Action will run `helm package` for every chart folder in the `charts` directory of your repository and +deploy it to GitHub Pages. A basic example workflow is below: ```yml name: Helm Publish @@ -22,12 +24,14 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - - uses: J12934/helm-gh-pages-action@master + - uses: dave-mcconnell/helm-gh-pages-microservices@master with: - access-token: ${{ secrets.ACCESS_TOKEN }} + access-token: ${{ secrets.CR_TOKEN }} + source-charts-folder: 'test-charts' // location of helm charts in your code repo + destination-repo: yourusername/helm-charts-repo ``` -### Knobs & Handles +### Configuration Options This Action is fairly simple but it does provide you with a couple of configuration options: @@ -37,13 +41,20 @@ configuration options: Helm finished building it. You should store this as a [secret][github-repo-secret] in your repository. Provided as an [input][github-action-input]. -- **deploy-branch**: The branch expected by GitHub to have the static files - needed for your site. For org and user pages it should always be `master`. - This is where the packaged charts and index.yaml will be pushed to. Provided as an - [input][github-action-input]. - Defaults to `master`. +- **source-charts-folder**: The folder to package helm charts from. +Defaults to `charts`. + +- **destination-repo**: The destination repository you want to push your Helm chart to. +This is a required field. + +- **destination-branch**: The destination branch you want to push your Helm chart to. +Defaults to `master`. -- **charts-folder**: Charts folder of your repository. Defaults to `charts` +- **destination-charts-folder**: The destination folder you want to copy the packages Helm chart to. +Defaults to `charts`. + +- **destination-charts-folder**: The version of Helm you're using - either v2 or v3. +Defaults to `v3`. ### Org or User Pages @@ -51,29 +62,9 @@ Create a repository with the format `.github.io`, push your helm sources to a branch other than `master` and add this GitHub Action to your workflow! 🚀😃 -### CNAME - -You have a custom domain you would like to use? Fancy! 😎 This Action's got you -covered! Assuming you have already set up your DNS provider as defined in the -[GitHub Pages docs][github-pages-domain-docs], all we need next is a `CNAME` -file at the root of your project with the domain you would like to use. For -example: - -```CNAME -imenrique.com -``` - -> Notice that it's **all capitals CNAME** 😊. - -### Assumptions - -TODO - -## That's It - -Have fun building! ✨ +## Related Links -[github-access-token]: https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line -[github-action-input]: https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idstepswith -[github-pages-domain-docs]: https://help.github.com/en/articles/using-a-custom-domain-with-github-pages -[github-repo-secret]: https://help.github.com/en/articles/virtual-environments-for-github-actions#creating-and-using-secrets-encrypted-variables +- [github-access-token]: https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line +- [github-action-input]: https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idstepswith +- [github-pages-domain-docs]: https://help.github.com/en/articles/using-a-custom-domain-with-github-pages +- [github-repo-secret]: https://help.github.com/en/articles/virtual-environments-for-github-actions#creating-and-using-secrets-encrypted-variables diff --git a/action.yml b/action.yml index 21e6c54..1836d3a 100644 --- a/action.yml +++ b/action.yml @@ -7,6 +7,10 @@ inputs: access-token: description: 'A personal access token needed to push your site after it has been built.' required: true + source-charts-folder: + description: 'The folder to package helm charts from' + required: false + default: 'charts' destination-repo: description: 'The destination repository you want to push your Helm chart to.' required: true @@ -14,10 +18,14 @@ inputs: description: 'The destination branch you want to push your Helm chart to.' required: false default: 'master' - charts-folder: - description: 'The folder in which the helm charts are located' + destination-charts-folder: + description: 'The folder to copy packaged helm charts into' required: false default: 'charts' + helm-version: + description: 'The version of Helm being used - either v2 or v3' + required: false + default: 'v3' runs: using: 'node12' main: 'index.js' diff --git a/index.js b/index.js index 357bfa1..f266057 100644 --- a/index.js +++ b/index.js @@ -7,22 +7,31 @@ const ioUtil = require('@actions/io/lib/io-util'); const { readdirSync } = require('fs'); const path = require('path'); -const getDirectories = fileName => - readdirSync(fileName, { - withFileTypes: true, - }) - .filter(dirent => dirent.isDirectory()) - .filter(dirent => !(/(^|\/)\.[^\/\.]/g).test(dirent)) - .map(dirent => dirent.name); - async function run() { + try { - const sourceBranch = github.context.ref const accessToken = core.getInput('access-token'); - const sourceChartsDir = core.getInput('source-charts-folder') | 'charts'; + + const sourceRepo = `${github.context.repo.owner}/${github.context.repo.repo}`; + const sourceBranch = github.context.ref.replace('refs/heads/', '') + const sourceChartsDir = core.getInput('source-charts-folder') ? core.getInput('source-charts-folder') : 'charts'; + const destinationRepo = core.getInput('destination-repo'); - const destinationBranch = core.getInput('destination-branch') | 'master' - const destinationChartsDir = core.getInput('destination-charts-folder') | 'charts'; + const destinationBranch = core.getInput('destination-branch') ? core.getInput('destination-branch') : 'master' + const destinationChartsDir = core.getInput('destination-charts-folder') ?core.getInput('destination-charts-folder') : 'charts'; + + let useHelm3 = true; + if (!core.getInput('helm-version')) { + useHelm3 = true + } + else useHelm3 = core.getInput('helm-version') === 'v3' ? true : false; + + console.log('Running Push Helm Chart job with:') + console.log('Source Branch:' + sourceBranch) + console.log('Source Charts Directory:' + sourceChartsDir) + console.log('Destination Repo:' + destinationRepo) + console.log('Destination Branch:' + destinationBranch) + console.log('Destination Charts Directory:' + destinationChartsDir) if (!accessToken) { core.setFailed( @@ -38,87 +47,108 @@ async function run() { return; } - const sourceRepo = `${github.context.repo.owner}/${github.context.repo.repo}`; - const sourceRepoURL = `https://${accessToken}@github.com/${sourceRepo}.git`; - const destinationRepoURL = `https://${accessToken}@github.com/${destinationRepo}.git`; - - // clone source repo - console.log(`Deploying to repo: ${sourceRepo} and branch: ${sourceBranch}`); - await exec.exec(`git clone`, ['-b', sourceBranch, sourceRepoURL, 'output'], { - cwd: './sourceRepo', - }); - - // git config - await exec.exec(`git config user.name`, [github.context.actor], { - cwd: './output', - }); - await exec.exec( - `git config user.email`, - [`${github.context.actor}@users.noreply.github.com`], - { cwd: './output' } - ); - - // package helm charts - const chartDirectories = getDirectories(path.resolve(`./sourceRepo/${sourceChartsDir}`)); - - console.log('Charts dir content'); - await exec.exec(`ls`, ['-I ".*"'], { cwd: `./sourceRepo/${sourceChartsDir}` }); - for (const chartDirname of chartDirectories) { - console.log(`Resolving helm chart dependency in directory ${chartDirname}`); - await exec.exec( - `helm dependency update`, - [], - { cwd: `./sourceRepo/${sourceChartsDir}/${chartDirname}` } - ); - - console.log(`Packaging helm chart in directory ${chartDirname}`); - await exec.exec( - `helm package`, - [chartDirname, '--destination', '../output'], - { cwd: `./sourceRepo/${sourceChartsDir}` } - ); + if (useHelm3) { + await InstallHelm3Latest(); } - console.log('Packaged all helm charts.'); + await ConfigureGit() + await CloneGitRepo(sourceRepo, sourceBranch, accessToken, 'sourceRepo') + await CloneGitRepo(destinationRepo, destinationBranch, accessToken, 'destinationRepo') - const cnameExists = await ioUtil.exists('./CNAME'); - if (cnameExists) { - console.log('Copying CNAME over.'); - await io.cp('./CNAME', './output/CNAME', { force: true }); - console.log('Finished copying CNAME.'); - } + await PackageHelmCharts(`./sourceRepo/${sourceChartsDir}`, `../../destinationRepo/${destinationChartsDir}`) + await GenerateIndex() + await AddCommitPushToGitRepo(`./destinationRepo`, `${github.context.sha}`, destinationBranch) + + } catch (error) { + core.setFailed(error.message); + } +} + +const getDirectories = fileName => + readdirSync(fileName, { + withFileTypes: true, + }) + .filter(dirent => dirent.isDirectory()) + .filter(dirent => !(/(^|\/)\.[^\/\.]/g).test(dirent)) + .map(dirent => dirent.name); + +const InstallHelm3Latest = async () => { + await exec.exec(`curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3`, [], { cwd: `./` }); + await exec.exec(`chmod 700 get_helm.sh`, [], { cwd: `./` }); + await exec.exec(`./get_helm.sh`, [], { cwd: `./` }); + + await exec.exec(`helm version`, [], { cwd: `./` } + ) +} + +const ConfigureGit = async () => { + + await exec.exec(`git config --global user.name`, [github.context.actor], { + cwd: './', + }); + + await exec.exec( + `git config --global user.email`, + [`${github.context.actor}@users.noreply.github.com`], + { cwd: './' } + ); +} + +const CloneGitRepo = async (repoName, branchName, accessToken, cloneDirectory) => { + + const repoURL = `https://${accessToken}@github.com/${repoName}.git`; + await exec.exec(`git clone`, ['-b', branchName, repoURL, cloneDirectory], { + cwd: './', + }); + +} - // clone destination repo - await exec.exec(`git clone`, ['-b', destinationBranch, destinationRepoURL, 'destinationRepo'], { - cwd: './', - }); +const PackageHelmCharts = async (chartsDir, destinationChartsDir) => { - // move published chart - await exec.exec(`mv`, ['./sourceRepo/*.tgz', `./DestinationRepo/${destinationChartsDir}`], { - cwd: './', - }); + const chartDirectories = getDirectories(path.resolve(chartsDir)); - // push to - await exec.exec(`git add`, ['.'], { cwd: './DestinationRepo' }); + console.log('Charts dir content'); + await exec.exec(`ls`, ['-I ".*"'], { cwd: chartsDir }); + for (const chartDirname of chartDirectories) { + + console.log(`Resolving helm chart dependency in directory ${chartDirname}`); await exec.exec( - `git commit`, - ['-m', `Deployed via Helm Publish Action for ${github.context.sha}`], - { cwd: './output' } + `helm dependency update`, + [], + { cwd: `${chartsDir}/${chartDirname}` } + ); + + console.log(`Packaging helm chart in directory ${chartDirname}`); + await exec.exec( + `helm package`, + [chartDirname, '--destination', destinationChartsDir], + { cwd: chartsDir } ); - await exec.exec(`git push`, ['-u', 'origin', `${destinationBranch}`], { - cwd: './output', - }); - console.log('Finished deploying your site.'); + } + console.log('Packaged all helm charts.'); +} - console.log('Enjoy! ✨'); - // generate index - console.log(`Building index.yaml`); - await exec.exec(`helm repo index`, `./output`); +const GenerateIndex = async () => { - console.log(`Successfully build index.yaml.`); - } catch (error) { - core.setFailed(error.message); - } + // generate index + console.log(`Building index.yaml`); + await exec.exec(`helm repo index`, `./destinationRepo`); + console.log(`Successfully generated index.yaml.`); +} + +const AddCommitPushToGitRepo = async (workingDir, gitSha, branch) => { + await exec.exec(`git status`, [], { cwd: workingDir }); + await exec.exec(`git add`, ['.'], { cwd: workingDir }); + await exec.exec(`git status`, [], { cwd: workingDir }); + await exec.exec( + `git commit`, + ['-m', `Deployed via Helm Publish Action for ${gitSha}`], + { cwd: workingDir } + ); + await exec.exec(`git push`, ['-u', 'origin', `${branch}`], + { cwd: workingDir } + ); + console.log(`Pushed to ${workingDir}`); } run();