org.update #16
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: org.update | |
| env: | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| etc: | |
| description: 'base64 encoded json string' | |
| required: true | |
| release: | |
| description: 'create a release' | |
| required: false | |
| default: 'true' | |
| readme: | |
| description: 'create a readme' | |
| required: false | |
| default: 'true' | |
| jobs: | |
| update: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| actions: read | |
| contents: write | |
| steps: | |
| # ╔═════════════════════════════════════════════════════╗ | |
| # ║ SETUP ENVIRONMENT ║ | |
| # ╚═════════════════════════════════════════════════════╝ | |
| # CHECKOUT | |
| - name: init / checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| ref: 'master' | |
| fetch-depth: 0 | |
| # INSTALL SEMVER PACKAGE | |
| - name: update / setup node | |
| uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 | |
| with: | |
| node-version: '24' | |
| - run: npm i semver | |
| # ╔═════════════════════════════════════════════════════╗ | |
| # ║ COMPARE SEMVER ║ | |
| # ╚═════════════════════════════════════════════════════╝ | |
| # COMPARE SEMVER OF CURRENT AND LATEST AND TAGS | |
| - name: update / compare latest with current version | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 | |
| with: | |
| script: | | |
| (async()=>{ | |
| const { Buffer } = require('node:buffer'); | |
| const { inspect } = require('node:util'); | |
| const { existsSync, readFileSync, writeFileSync } = require('node:fs'); | |
| const { resolve } = require('node:path'); | |
| const semver = require('semver'); | |
| const semverExceptions = (s) => { | |
| switch('${{ github.event.repository.name }}'){ | |
| case 'docker-chrony': core.warning(`semver exception found for chrony version ${s}, setting version to major.minor`); return(s.split('.').slice(0, 2).join('.')); | |
| case 'docker-cron': core.warning(`semver exception found for cron version ${s}, setting version to major.minor`); return(s.split('.').slice(0, 2).join('.')); | |
| } | |
| return(s); | |
| } | |
| // defaults | |
| const json = `${{ toJSON(github.event.inputs) }}`; | |
| const job = {inputs:{}, json:{}, fail:false}; | |
| // check if inputs is valid base64 encoded json | |
| try{ | |
| if(json.length > 0){ | |
| const n = JSON.parse(json); | |
| if(n?.etc){ | |
| try{ | |
| job.inputs = JSON.parse(Buffer.from(n.etc, 'base64').toString('ascii')); | |
| if(!job.inputs?.version){ | |
| core.setFailed(`input does not contain valid semver version: ${inspect(job.inputs, {showHidden:false, depth:null, colors:true})}`); | |
| }else if(!job.inputs?.tag){ | |
| core.setFailed(`input does not contain valid git tag: ${inspect(job.inputs, {showHidden:false, depth:null, colors:true})}`); | |
| }else if(job.inputs.version == 'null' || null === job.inputs.version){ | |
| core.warning(`input version is null: ${inspect(job.inputs, {showHidden:false, depth:null, colors:true})}`); | |
| job.fail = true; | |
| } | |
| }catch(e){ | |
| core.setFailed(`could not parse github.event.inputs.etc: ${n.etc} (${Buffer.from(n.etc, 'base64').toString('ascii')})`); | |
| } | |
| } | |
| } | |
| }catch(e){ | |
| core.setFailed(`could not parse github.event.inputs: ${json}`); | |
| } | |
| if(!job.fail){ | |
| // check if .json exists | |
| try{ | |
| const path = resolve('.json'); | |
| if(existsSync(path)){ | |
| try{ | |
| job.json = JSON.parse(readFileSync(path).toString()); | |
| }catch(e){ | |
| throw new Error('could not parse .json'); | |
| } | |
| }else{ | |
| throw new Error('.json does not exist!'); | |
| } | |
| }catch(e){ | |
| core.setFailed(e); | |
| } | |
| // semver | |
| const latest = semverExceptions(semver.valid(semver.coerce(job.inputs.version))); | |
| const current = semverExceptions(semver.valid(semver.coerce(job.json.semver.version))); | |
| const tag = semver.valid(semver.coerce(job.inputs.tag)); | |
| const checks = {latestTagExists:false}; | |
| try{ | |
| const tag = await fetch(`https://hub.docker.com/v2/repositories/${job.json.image}/tags/${latest}`); | |
| if(tag.status === 200){ | |
| checks.latestTagExists = true; | |
| core.warning(`${latest} tag already exists, aborting`); | |
| } | |
| }catch(e){ | |
| core.warning(e); | |
| } | |
| // compare | |
| if(latest && latest !== current && !checks.latestTagExists){ | |
| core.info(`new ${semver.diff(current, latest)} release found (${latest}), updating ...`) | |
| job.json.semver.version = latest; | |
| // check if app has additional parameters | |
| const build = {}; | |
| if(job.inputs?.build && typeof(job.inputs.build) === 'string'){ | |
| build.args = { | |
| version_build:job.inputs.build, | |
| }; | |
| job.json.build.args.version_build = job.inputs.build; | |
| }else if(job.inputs?.build?.args){ | |
| build.args = job.inputs.build.args; | |
| job.json.build.args.version_build = job.inputs.build.args; | |
| } | |
| // update .json | |
| try{ | |
| writeFileSync(resolve('.json'), JSON.stringify(job.json, null, 2)); | |
| // export variables | |
| core.exportVariable('WORKFLOW_UPDATE', true); | |
| core.exportVariable('WORKFLOW_UPDATE_BASE64JSON', Buffer.from(JSON.stringify({build:build, update:true, update_etc:job.inputs})).toString('base64')); | |
| if(job.inputs?.unraid){ | |
| core.exportVariable('WORKFLOW_UPDATE_UNRAID', 'true'); | |
| core.exportVariable('WORKFLOW_UPDATE_UNRAID_BASE64JSON', Buffer.from(JSON.stringify({semversuffix:"unraid", uid:99, gid:100, build:build, update:true, update_etc:job.inputs})).toString('base64')); | |
| } | |
| if(job.inputs?.nobody){ | |
| core.exportVariable('WORKFLOW_UPDATE_NOBODY', 'true'); | |
| core.exportVariable('WORKFLOW_UPDATE_NOBODY_BASE64JSON', Buffer.from(JSON.stringify({semversuffix:"nobody", uid:65534, gid:65534, build:build, update:true, update_etc:job.inputs})).toString('base64')); | |
| } | |
| core.exportVariable('LATEST_TAG', semver.inc(tag, semver.diff(current, latest))); | |
| core.exportVariable('LATEST_VERSION', latest); | |
| if(job.inputs?.build) core.exportVariable('LATEST_BUILD', job.inputs.build); | |
| }catch(e){ | |
| core.setFailed(e); | |
| } | |
| }else{ | |
| core.info('no update required') | |
| } | |
| } | |
| core.info(inspect(job, {showHidden:false, depth:null, colors:true})); | |
| })(); | |
| - name: update / checkout | |
| id: checkout | |
| if: env.WORKFLOW_UPDATE == 'true' | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| echo "WORKFLOW_UPDATE_PRE_COMMIT=$(git log --oneline | head -n 1 | awk -F ' ' '{print $1}')" >> "${GITHUB_ENV}" | |
| git add .json | |
| git commit -m "chore: auto upgrade to v${{ env.LATEST_VERSION }}" | |
| git push origin HEAD:master | |
| - name: update / tag | |
| if: env.WORKFLOW_UPDATE == 'true' && steps.checkout.outcome == 'success' | |
| run: | | |
| SHA256=$(git rev-list --branches --max-count=1) | |
| git tag -a v${{ env.LATEST_TAG }} -m "v${{ env.LATEST_TAG }}" ${SHA256} | |
| git push --follow-tags | |
| - name: update / build container image | |
| id: build | |
| if: env.WORKFLOW_UPDATE == 'true' && steps.checkout.outcome == 'success' | |
| uses: benc-uk/workflow-dispatch@31e2b3319479a63f0ab15bf800eff9e913504e26 #v1.3.2 | |
| with: | |
| workflow: org.container.yml | |
| wait-for-completion: true | |
| token: "${{ secrets.REPOSITORY_TOKEN }}" | |
| inputs: '{ "release":"${{ github.event.inputs.release }}", "readme":"${{ github.event.inputs.readme }}", "run-name":"update v${{ env.LATEST_VERSION }}", "etc":"${{ env.WORKFLOW_UPDATE_BASE64JSON }}" }' | |
| ref: "v${{ env.LATEST_TAG }}" | |
| sync-status: true | |
| wait-interval-seconds: 30 | |
| - name: "update / revert if build failed" | |
| if: env.WORKFLOW_UPDATE == 'true' && failure() | |
| run: | | |
| git reset --hard ${{ env.WORKFLOW_UPDATE_PRE_COMMIT }} | |
| git push -f | |
| git push --delete origin v${{ env.LATEST_TAG }} | |
| - name: update / build container image for unraid | |
| if: env.WORKFLOW_UPDATE_UNRAID == 'true' && steps.build.conclusion == 'success' | |
| uses: benc-uk/workflow-dispatch@31e2b3319479a63f0ab15bf800eff9e913504e26 #v1.3.2 | |
| with: | |
| workflow: org.container.yml | |
| wait-for-completion: false | |
| token: "${{ secrets.REPOSITORY_TOKEN }}" | |
| inputs: '{ "release":"false", "readme":"false", "run-name":"update unraid v${{ env.LATEST_VERSION }}", "etc":"${{ env.WORKFLOW_UPDATE_UNRAID_BASE64JSON }}" }' | |
| ref: "v${{ env.LATEST_TAG }}" | |
| - name: update / build container image for nobody | |
| if: env.WORKFLOW_UPDATE_NOBODY == 'true' && steps.build.conclusion == 'success' | |
| uses: benc-uk/workflow-dispatch@31e2b3319479a63f0ab15bf800eff9e913504e26 #v1.3.2 | |
| with: | |
| workflow: org.container.yml | |
| wait-for-completion: false | |
| token: "${{ secrets.REPOSITORY_TOKEN }}" | |
| inputs: '{ "release":"false", "readme":"false", "run-name":"update nobody v${{ env.LATEST_VERSION }}", "etc":"${{ env.WORKFLOW_UPDATE_NOBODY_BASE64JSON }}" }' | |
| ref: "v${{ env.LATEST_TAG }}" |