{"id":15040604,"url":"https://github.com/aa8y/dave","last_synced_at":"2026-01-23T02:38:19.800Z","repository":{"id":79893850,"uuid":"109502928","full_name":"aa8y/dave","owner":"aa8y","description":"A helper to build, test and push Docker images and template Dockerfiles.","archived":false,"fork":false,"pushed_at":"2024-06-24T00:29:38.000Z","size":9023,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-09T04:29:01.181Z","etag":null,"topics":["docker","docker-helper","dockerfile","helper"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aa8y.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-11-04T14:45:09.000Z","updated_at":"2024-06-24T00:29:41.000Z","dependencies_parsed_at":null,"dependency_job_id":"efacd6ed-53c1-4583-97fb-ab14a7ec896a","html_url":"https://github.com/aa8y/dave","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/aa8y/dave","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aa8y%2Fdave","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aa8y%2Fdave/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aa8y%2Fdave/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aa8y%2Fdave/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aa8y","download_url":"https://codeload.github.com/aa8y/dave/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aa8y%2Fdave/sbom","scorecard":{"id":158470,"data":{"date":"2025-08-11","repo":{"name":"github.com/aa8y/dave","commit":"5763afc33fc82329aa6e66be7bdac4553b89d5dd"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.2,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":7,"reason":"3 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-76p7-773f-r4q5"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-16T12:37:54.657Z","repository_id":79893850,"created_at":"2025-08-16T12:37:54.657Z","updated_at":"2025-08-16T12:37:54.657Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28679137,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-23T01:00:35.747Z","status":"online","status_checked_at":"2026-01-23T02:00:08.296Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","docker-helper","dockerfile","helper"],"created_at":"2024-09-24T20:44:48.723Z","updated_at":"2026-01-23T02:38:19.788Z","avatar_url":"https://github.com/aa8y.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Dave\n\n[![Build Status](https://travis-ci.org/aa8y/dave.svg?branch=master)](https://travis-ci.org/aa8y/dave)\n[![codecov](https://codecov.io/gh/aa8y/dave/branch/master/graph/badge.svg)](https://codecov.io/gh/aa8y/dave)\n\nDave is a tool which is intended to help with Docker image authoring. It tries to fill the gaps Docker Hub has around building images, which are:\n* Lack of support for build arguments.\n* The only way to build multiple tags being the usage of a different `Dockerfile` for each tag which goes against the DRY philosophy.\n* No testing infrastructure so that tags are published only after passing (a) test(s).\n\n**Dave** is an acronym for _Docker Authoring made Very Easy_. Actually that's not completely true since I came up with the name first and then the acronym. And if you're wondering where the name came from, here's a hint.\n\n![](https://raw.githubusercontent.com/aa8y/dave/master/.images/dave.gif)\n\n*NOTE:* It is still work in progress. So suffice to many things might change. Hopefully not too many though.\n\n## Features\n\nDave would do perform its operations by using metadata in a [YAML](http://yaml.org/) serialized manifest file. The format is explained [later](#manifest_file). The following operations are supported.\n\n* **all**: This command will execute all commands except `template` in the order of `pull`, `build`, `test` and `push`.\n* **build**: Builds one or more images using the given Docker build command template and its arguments.\n* **pull**: Pulls one or more images from a Docker registry like Docker Hub.\n* **push**: Pushes a local image using the given Docker push command template and its arguments.\n* **template**: Builds one or more `Dockerfile`s using the given template. This helps keep your `Dockerfile`s DRY.\n* **test**: Tests a Docker image by invoking a certain command on the image. A non-zero exit status code fails the test.\n\nAll templating is done using [Mustache](https://mustache.github.io/). `pull` and `template` commands won't be supported in the first release which would be `0.1.0`.\n\n## Usage\n\nThe command-line utility requires at least one command to be passed.\n```\ndave \u003ccommand1\u003e [\u003ccommand2\u003e ...] [OPTIONS]\n```\nThe options that it accepts are:\n\n* `--context` or `-c`: Accepts a string denoting the location of the `Dockerfile`. If just the context is passed, the command(s) would be invoked on all tags pertaining to the context.\n* `--tags` or `-t`: Accepts a list tags separated by spaces. Requires the context to be passed as well. If the context is not passed, the tags would be ignored.\n* `--manifest` or `-m`: Accepts a path to the manifest file. Defaults to `manifest.yml` in the current directory.\n\nIf no other parameters are passed, the command(s) would be executed for all contexts and all tags in the manifest.\n\n## Manifest File\n\nThe manifest file follows a trickle down format. What this means that all the values in the parent node trickle down but can be overridden by the child node. Here's a sample format.\n\n```yaml\nparameters:\n  repository: aa8y/spark\n  hadoopVersion: 2.7.4\ntemplates:\n  push: docker push {{{repository}}}:{{tag}}\n  test: docker run --rm -it {{{repository}}}:{{tag}} spark-shell --version\ncontexts:\n  stable:\n    tagKeys:\n      - sparkVersion\n    templates:\n      build: \u003e\n        docker build -t {{{repository}}}:{{tag}}\n          --build-arg HADOOP_VERSION={{hadoopVersion}}\n          --build-arg SPARK_VERSION={{sparkVersion}} {{context}}\n    tags:\n      '1.6.3':\n        hadoopVersion: 2.6.5\n      '2.2.0':\n      '1.6':\n        hadoopVersion: 2.6.5\n        sparkVersion: 1.6.3\n      '2.2':\n        sparkVersion: 2.2.0\n      'latest':\n        sparkVersion: 2.2.0\n  edge:\n    parameters:\n      scalaVersion: '2.11'\n    templates:\n      build: \u003e\n        docker build -t {{{repository}}}:{{tag}}\n          --build-arg HADOOP_VERSION={{hadoopVersion}}\n          --build-arg SCALA_VERSION={{scalaVersion}}\n          --build-arg SPARK_BRANCH={{branch}} {{context}}\n    tags:\n      edge-1.6:\n        branch: branch-1.6\n        hadoopVersion: 2.6.5\n        scalaVersion: '2.10'\n      edge-2.2:\n        branch: branch-2.2\n      edge:\n        branch: master\n```\n\nLet's go through it part by part. Here's the first part.\n\n```yaml\nparameters:\n  repository: aa8y/spark\n  hadoopVersion: 2.7.4\ntemplates:\n  push: docker push {{{repository}}}:{{tag}}\n  test: docker run --rm -it {{{repository}}}:{{tag}} spark-shell --version\n```\n\nThis is the first part of the manifest, which refers to the global defaults will get assigned to all contexts and from there to all tags. Supported keys are `parameters` and `templates`. `parameters` contains parameters for the `build`, `pull`, `push` and `test` templates. And `templates` contains the Docker build, pull, push and test [Mustache](https://mustache.github.io/) command templates. Here, we used the `{{{}}}` for the repository vs `{{}}` for the tag as the former contains a `/` which would otherwise be HTML-encoded. These defaults can be overridden by redefining the keys on any level from where they'll trickle down to the lowest level, i.e. for each tag.\n\nHere's the second part.\n\n```yaml\ncontexts:\n  stable:\n    ...\n  edge:\n    ...\n```\n\nThe second part of the manifest, `contexts` refers to a Docker context. That basically means the location where the `Dockerfile` would exist and which would also be the source for the `COPY` commands in the said `Dockerfile`. Each context key is automatically assigned as a value to a key called `context` in the parameters, which can be used in the templates.\n\nHere's the next part.\n\n```yaml\nstable:\n  tagKeys:\n    - sparkVersion\n  templates:\n    build: \u003e\n      docker build -t {{{repository}}}:{{tag}}\n        --build-arg HADOOP_VERSION={{hadoopVersion}}\n        --build-arg SPARK_VERSION={{sparkVersion}} {{context}}\n  tags:\n    '1.6.3':\n      hadoopVersion: 2.6.5\n    '2.2.0':\n    '1.6':\n      hadoopVersion: 2.6.5\n      sparkVersion: 1.6.3\n    '2.2':\n      sparkVersion: 2.2.0\n    'latest':\n      sparkVersion: 2.2.0\n```\n\n`tags` refers to the tags which would be built. In the aforementioned snippet, we would therefore be building 5 tags for the `stable` context. The build command for each of these tags would be the one defined in the context templates and the push command would be the one which would trickle down from the global templates discussed before. A tag key gets automatically assigned as a value to the `tag` key along with any other tag keys defined in `tagKeys`, if present, and can be used in templates. So, for example, in the above snippet the value of `sparkVersion` for tag `1.6.3` would be `1.6.3` whereas `2.2` would override the value from its tag-specific parameters.\n\nAnd here's the last part.\n\n```yaml\nedge:\n  parameters:\n    scalaVersion: '2.11'\n  templates:\n    build: \u003e\n      docker build -t {{{repository}}}:{{tag}}\n        --build-arg HADOOP_VERSION={{hadoopVersion}}\n        --build-arg SCALA_VERSION={{scalaVersion}}\n        --build-arg SPARK_BRANCH={{branch}} {{context}}\n  tags:\n    edge-1.6:\n      branch: branch-1.6\n      hadoopVersion: 2.6.5\n      scalaVersion: '2.10'\n    edge-2.2:\n      branch: branch-2.2\n    edge:\n      branch: master\n```\n\nIn the last part, the only special thing to be seen is a new local global parameter, `scalaVersion` has been defined. This would then be assigned to each tag and can also be overridden as it is for the `edge-1.6` tag.\n\nAnd while the manifest file can be named anything, the default name assumed is `manifest.yml` in the current directory. Also, although the sample manifest has keys in `lowerCamelCase`, `lower_snake_case` and `lower-kebab-case` are also supported.\n\n## Examples\n\nHere are projects where Dave is being utilized to build, test and push images. See `manifest.yml` to see how the metadata has been stored and `.travis.yml` to see how Dave can be leveraged.\n\n* [aa8y/docker-scala](https://github.com/aa8y/docker-scala): A simple Docker project with one `Dockerfile` (i.e. one context) from which all Docker images are built.\n\n## CI Builds\n\n### TravisCI\n\nHere's an example `.travis.yml` to use it with TravisCI.\n\n```\nsudo: required\nservices:\n  - docker\nlanguage: node_js\nnode_js:\n  - stable\nbefore_install:\n  - git clone https://github.com/aa8y/dave.git\ninstall:\n  - npm install -g dave/\nbefore_script:\n  - dave build\nscript:\n  - dave test\nafter_success:\n  - docker login -u \u003cusername\u003e -p \"$DOCKER_PASSWORD\"\n  - dave push\n```\n\nIf all you want to do is build and test the images, you can ignore the `after_success` section. But if you do want to push the images after they have been tested, you would need a way to authenticate your Docker user. For that, follow [this guide](https://docs.travis-ci.com/user/docker/#Pushing-a-Docker-Image-to-a-Registry). I, personally, only like to encrypt my password as the username for Docker registry is usually also the namespace for the images. Also, I am working on acquiring the [Dave package namespace](https://www.npmjs.com/package/dave) on NPM, so that the installation process is easier.\n\n## Future Work\n\n* Add support to pull images. This should help pulling cached layers which can make building images faster on a CI instance. I expect to add this in the 0.2.0 release.\n* Add support for templating `Dockerfile`s. I expect to add this in the 0.3.0 release.\n* Verify the metadata read from the manifest against a schema. Maybe use [JSON Schema](http://json-schema.org/)?\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faa8y%2Fdave","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faa8y%2Fdave","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faa8y%2Fdave/lists"}