docker #12
Workflow file for this run
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: docker | |
| run-name: ${{ inputs.run-name }} | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| run-name: | |
| description: 'set run-name for workflow (multiple calls)' | |
| type: string | |
| required: false | |
| default: 'docker' | |
| release: | |
| description: 'set WORKFLOW_GITHUB_RELEASE' | |
| required: false | |
| default: 'false' | |
| readme: | |
| description: 'set WORKFLOW_GITHUB_README' | |
| required: false | |
| default: 'false' | |
| image: | |
| description: 'set IMAGE' | |
| required: false | |
| uid: | |
| description: 'set IMAGE_UID' | |
| required: false | |
| gid: | |
| description: 'set IMAGE_GID' | |
| required: false | |
| semverprefix: | |
| description: 'prefix for semver tags' | |
| required: false | |
| semversuffix: | |
| description: 'suffix for semver tags' | |
| required: false | |
| jobs: | |
| docker: | |
| runs-on: ubuntu-22.04 | |
| services: | |
| registry: | |
| image: registry:2 | |
| ports: | |
| - 5000:5000 | |
| permissions: | |
| actions: read | |
| contents: write | |
| packages: write | |
| security-events: write | |
| steps: | |
| - name: init / checkout | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 | |
| with: | |
| ref: ${{ github.ref_name }} | |
| fetch-depth: 0 | |
| - name: init / setup environment | |
| uses: actions/github-script@62c3794a3eb6788d9a2a72b219504732c0c9a298 | |
| with: | |
| script: | | |
| const { existsSync, readFileSync } = require('node:fs'); | |
| const { resolve } = require('node:path'); | |
| const inputs = `${{ toJSON(github.event.inputs) }}`; | |
| const opt = {input:{}, dot:{}}; | |
| try{ | |
| if(inputs.length > 0){ | |
| opt.input = JSON.parse(inputs); | |
| } | |
| }catch(e){ | |
| core.warning('could not parse github.event.inputs'); | |
| } | |
| try{ | |
| const path = resolve('.json'); | |
| if(existsSync(path)){ | |
| try{ | |
| opt.dot = 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); | |
| } | |
| const docker = { | |
| image:{ | |
| name:(opt.input?.image || opt.dot.image), | |
| arch:(opt.dot.arch || 'linux/amd64,linux/arm64'), | |
| prefix:((opt.input?.semverprefix) ? `${opt.input?.semverprefix}-` : ''), | |
| suffix:((opt.input?.semversuffix) ? `-${opt.input?.semversuffix}` : ''), | |
| description:(opt.dot?.readme?.description || ''), | |
| tags:[], | |
| }, | |
| app:{ | |
| image:opt.dot.image, | |
| name:opt.dot.name, | |
| version:opt.dot.semver.version, | |
| root:opt.dot.root, | |
| UID:(opt.input?.uid || 1000), | |
| GID:(opt.input?.gid || 1000), | |
| no_cache:new Date().getTime(), | |
| }, | |
| cache:{ | |
| registry:'localhost:5000/', | |
| } | |
| }; | |
| docker.cache.name = `${docker.image.name}:${docker.image.prefix}buildcache${docker.image.suffix}`; | |
| docker.cache.grype = `${docker.cache.registry}${docker.image.name}:${docker.image.prefix}grype${docker.image.suffix}`; | |
| docker.app.prefix = docker.image.prefix; | |
| docker.app.suffix = docker.image.suffix; | |
| // setup tags | |
| const semver = opt.dot.semver.version.split('.'); | |
| docker.image.tags.push(`${context.sha.substring(0,7)}`); | |
| if(Array.isArray(semver)){ | |
| if(semver.length >= 1) docker.image.tags.push(`${semver[0]}`); | |
| if(semver.length >= 2) docker.image.tags.push(`${semver[0]}.${semver[1]}`); | |
| if(semver.length >= 3) docker.image.tags.push(`${semver[0]}.${semver[1]}.${semver[2]}`); | |
| } | |
| if(opt.dot.semver?.stable && new RegExp(opt.dot.semver.stable, 'ig').test(docker.image.tags.join(','))) docker.image.tags.push('stable'); | |
| if(opt.dot.semver?.latest && new RegExp(opt.dot.semver.latest, 'ig').test(docker.image.tags.join(','))) docker.image.tags.push('latest'); | |
| for(let i=0; i<docker.image.tags.length; i++){ | |
| docker.image.tags[i] = `${docker.image.name}:${docker.image.prefix}${docker.image.tags[i]}${docker.image.suffix}`; | |
| } | |
| // setup build arguments | |
| const arguments = []; | |
| for(const argument in docker.app){ | |
| arguments.push(`APP_${argument.toUpperCase()}=${docker.app[argument]}`); | |
| } | |
| // export to environment | |
| core.exportVariable('DOCKER_CACHE_REGISTRY', docker.cache.registry); | |
| core.exportVariable('DOCKER_CACHE_NAME', docker.cache.name); | |
| core.exportVariable('DOCKER_CACHE_GRYPE', docker.cache.grype); | |
| core.exportVariable('DOCKER_IMAGE_NAME', docker.image.name); | |
| core.exportVariable('DOCKER_IMAGE_ARCH', docker.image.arch); | |
| core.exportVariable('DOCKER_IMAGE_TAGS', docker.image.tags.join(',')); | |
| core.exportVariable('DOCKER_IMAGE_DESCRIPTION', docker.image.description); | |
| core.exportVariable('DOCKER_IMAGE_ARGUMENTS', arguments.join("\r\n")); | |
| core.exportVariable('WORKFLOW_CREATE_RELEASE', (opt.input?.release || true)); | |
| core.exportVariable('WORKFLOW_CREATE_README', (opt.input?.readme || true)); | |
| core.exportVariable('WORKFLOW_GRYPE_FAIL_ON_SEVERITY', (opt.json?.grpye?.fail || true)); | |
| core.exportVariable('WORKFLOW_GRYPE_SEVERITY_CUTOFF', (opt.json?.grpye?.severity || 'high')); | |
| # DOCKER | |
| - name: docker / login to hub | |
| uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 | |
| with: | |
| username: 11notes | |
| password: ${{ secrets.DOCKER_TOKEN }} | |
| - name: docker / setup qemu | |
| uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a | |
| - name: docker / setup buildx | |
| uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 | |
| with: | |
| driver-opts: network=host | |
| - name: docker / build & push & tag grype | |
| id: docker-build | |
| uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d | |
| with: | |
| context: . | |
| file: arch.dockerfile | |
| push: true | |
| platforms: ${{ env.DOCKER_IMAGE_ARCH }} | |
| cache-from: type=registry,ref=${{ env.DOCKER_CACHE_NAME }} | |
| cache-to: type=registry,ref=${{ env.DOCKER_CACHE_REGISTRY }}${{ env.DOCKER_CACHE_NAME }},mode=max,compression=zstd,force-compression=true | |
| build-args: | | |
| ${{ env.DOCKER_IMAGE_ARGUMENTS }} | |
| tags: | | |
| ${{ env.DOCKER_CACHE_GRYPE }} | |
| - name: grype / scan | |
| id: grype | |
| uses: anchore/scan-action@abae793926ec39a78ab18002bc7fc45bbbd94342 | |
| with: | |
| image: ${{ env.DOCKER_CACHE_GRYPE }} | |
| fail-build: ${{ env.WORKFLOW_GRYPE_FAIL_ON_SEVERITY }} | |
| severity-cutoff: ${{ env.WORKFLOW_GRYPE_SEVERITY_CUTOFF }} | |
| output-format: 'sarif' | |
| by-cve: true | |
| cache-db: true | |
| - name: grype / fail | |
| if: failure() || steps.grype.outcome == 'failure' | |
| uses: anchore/scan-action@abae793926ec39a78ab18002bc7fc45bbbd94342 | |
| with: | |
| image: ${{ env.DOCKER_CACHE_GRYPE }} | |
| fail-build: false | |
| severity-cutoff: ${{ env.WORKFLOW_GRYPE_SEVERITY_CUTOFF }} | |
| output-format: 'table' | |
| by-cve: true | |
| cache-db: true | |
| - name: docker / build & push | |
| uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d | |
| with: | |
| context: . | |
| file: arch.dockerfile | |
| push: true | |
| sbom: true | |
| provenance: mode=max | |
| platforms: ${{ env.DOCKER_IMAGE_ARCH }} | |
| cache-from: type=registry,ref=${{ env.DOCKER_CACHE_REGISTRY }}${{ env.DOCKER_CACHE_NAME }} | |
| cache-to: type=registry,ref=${{ env.DOCKER_CACHE_NAME }},mode=max,compression=zstd,force-compression=true | |
| build-args: | | |
| ${{ env.DOCKER_IMAGE_ARGUMENTS }} | |
| tags: | | |
| ${{ env.DOCKER_IMAGE_TAGS }} | |
| # RELEASE | |
| - name: github / release / log | |
| continue-on-error: true | |
| id: git-log | |
| run: | | |
| LOCAL_LAST_TAG=$(git describe --abbrev=0 --tags `git rev-list --tags --skip=1 --max-count=1`) | |
| echo "using last tag: ${LOCAL_LAST_TAG}" | |
| LOCAL_COMMITS=$(git log ${LOCAL_LAST_TAG}..HEAD --oneline) | |
| EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) | |
| echo "commits<<${EOF}" >> ${GITHUB_OUTPUT} | |
| echo "${LOCAL_COMMITS}" >> ${GITHUB_OUTPUT} | |
| echo "${EOF}" >> ${GITHUB_OUTPUT} | |
| - name: github / release / markdown | |
| if: env.WORKFLOW_CREATE_RELEASE == 'true' && steps.git-log.outcome == 'success' | |
| id: git-release | |
| uses: 11notes/action-docker-release@v1 | |
| with: | |
| git_log: ${{ steps.git-log.outputs.commits }} | |
| - name: github / release / create | |
| if: env.WORKFLOW_CREATE_RELEASE == 'true' && steps.git-release.outcome == 'success' | |
| uses: actions/create-release@4c11c9fe1dcd9636620a16455165783b20fc7ea0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| tag_name: ${{ github.ref }} | |
| release_name: ${{ github.ref }} | |
| body: ${{ steps.git-release.outputs.release }} | |
| draft: false | |
| prerelease: false | |
| # README | |
| - name: github / checkout master | |
| continue-on-error: true | |
| run: | | |
| git checkout master | |
| - name: github / create README.md | |
| id: github-readme | |
| continue-on-error: true | |
| if: env.WORKFLOW_CREATE_README == 'true' && steps.docker-build.outcome == 'success' | |
| uses: 11notes/action-docker-readme@v1 | |
| with: | |
| sarif_file: ${{ steps.grype.outputs.sarif }} | |
| build_output_metadata: ${{ steps.docker-build.outputs.metadata }} | |
| - name: github / commit & push | |
| continue-on-error: true | |
| if: steps.github-readme.outcome == 'success' && hashFiles('README.md') != '' | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git add README.md | |
| if [ -f compose.yaml ]; then | |
| git add compose.yaml | |
| fi | |
| git commit -m "auto update README.md" | |
| git push | |
| - name: docker / push README.md to docker hub | |
| continue-on-error: true | |
| if: steps.github-readme.outcome == 'success' && hashFiles('README_DOCKER.md') != '' | |
| uses: christian-korneck/update-container-description-action@d36005551adeaba9698d8d67a296bd16fa91f8e8 | |
| env: | |
| DOCKER_USER: 11notes | |
| DOCKER_PASS: ${{ secrets.DOCKER_TOKEN }} | |
| with: | |
| destination_container_repo: ${{ env.DOCKER_IMAGE_NAME }} | |
| provider: dockerhub | |
| short_description: ${{ env.DOCKER_IMAGE_DESCRIPTION }} | |
| readme_file: 'README_DOCKER.md' | |
| # REPOSITORY SETTINGS | |
| - name: github / update description and set repo defaults | |
| run: | | |
| curl --request PATCH \ | |
| --url https://api.github.com/repos/${{ github.repository }} \ | |
| --header 'authorization: Bearer ${{ secrets.REPOSITORY_TOKEN }}' \ | |
| --header 'content-type: application/json' \ | |
| --data '{ | |
| "description":"${{ env.DOCKER_IMAGE_DESCRIPTION }}", | |
| "homepage":"", | |
| "has_issues":true, | |
| "has_discussions":true, | |
| "has_projects":false, | |
| "has_wiki":false | |
| }' \ | |
| --fail |