{"id":28496900,"url":"https://github.com/salsita/cci-pingu","last_synced_at":"2025-07-07T17:38:22.743Z","repository":{"id":4821783,"uuid":"51287091","full_name":"salsita/cci-pingu","owner":"salsita","description":"Periodically check for new builds (artifacts) on CircleCI and install them in turn.","archived":false,"fork":false,"pushed_at":"2025-07-01T23:59:53.000Z","size":826,"stargazers_count":1,"open_issues_count":11,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-07-02T00:31:09.618Z","etag":null,"topics":["artifact","artifacts","automated","circleci","continuous","deployment"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/salsita.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"zenodo":null}},"created_at":"2016-02-08T08:48:16.000Z","updated_at":"2023-02-24T02:47:19.000Z","dependencies_parsed_at":"2023-07-05T21:02:12.413Z","dependency_job_id":"65b9f4e2-1b3e-487a-9635-6b7abd033835","html_url":"https://github.com/salsita/cci-pingu","commit_stats":{"total_commits":201,"total_committers":4,"mean_commits":50.25,"dds":"0.34328358208955223","last_synced_commit":"c723157a1ecc43daaeb72b63a87a89ffe10c22c4"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/salsita/cci-pingu","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salsita%2Fcci-pingu","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salsita%2Fcci-pingu/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salsita%2Fcci-pingu/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salsita%2Fcci-pingu/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/salsita","download_url":"https://codeload.github.com/salsita/cci-pingu/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salsita%2Fcci-pingu/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263056749,"owners_count":23406815,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["artifact","artifacts","automated","circleci","continuous","deployment"],"created_at":"2025-06-08T12:31:41.066Z","updated_at":"2025-07-02T21:32:35.768Z","avatar_url":"https://github.com/salsita.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Dependency Status](https://img.shields.io/david/salsita/cci-pingu.svg)](https://david-dm.org/salsita/cci-pingu)\n[![devDependency Status](https://img.shields.io/david/dev/salsita/cci-pingu.svg)](https://david-dm.org/salsita/cci-pingu?type=dev)\n![Downloads](https://img.shields.io/npm/dm/cci-pingu.svg?style=flat)\n![Licence](https://img.shields.io/npm/l/cci-pingu.svg?style=flat)\n[![Known Vulnerabilities](https://snyk.io/test/github/salsita/cci-pingu/badge.svg)](https://snyk.io/test/github/salsita/cci-pingu)\n\n# cci-pingu\n\nPeriodically check for new builds (artifacts) on CircleCI and install them locally in turn.\n\n## Installation\n\n```\n$ npm i cci-pingu\n```\n\nInstalling this module adds a runnable file into your `node_modules/.bin` directory. If installed globally (with the `-g` option), you can run `cci-pingu`, otherwise you can run `./node_modules/.bin/cci-pingu`.\n\nTo use the tool, you need to provide configuration file to it. You can copy the [config template](https://github.com/salsita/cci-pingu/blob/master/config/default.json), edit it with actual values and you are good to go!\n\n## Configuration file format\n\nConfig file is a JSON file with configuration object. The keys there have the following meaning:\n\n| Name | Mandatory | Type | Default | Meaning |\n| ---- |:---------:|:----:|:-------:| ------- |\n| cci_url | | string | `https://circleci.com` | Base-URL of CircleCI. Use with self-hosted CircleCI installations. |\n| token | * | string | | Your CircleCI API token that will be used when talking to CircleCI. Make sure you can access your project with this token. |\n| hosting | * | string | | \"github\" or \"bitbucket\"; where you repo is hosted. |\n| organisation | * | string | | The name of your github / bitbucket organisation (or user) under which the monitored project lives on CircleCI. |\n| project | * | string | | The name of the project you'd like to watch and install locally. |\n| branch (1) | | string| | The project repository branch to monitor. |\n| ignore_branch (1) | | boolean | `false` | If set to `true`, process builds from all branches. |\n| workflows_job_name | | string | | When specified, the tool only looks for successful builds created as part of worflows by job with specified name. |\n| artifacts | * | array of strings | | List of artifact names that will be downloaded for successful build. Actually, it is list of artifact name *substrings* so that you can have \"test\" string in the `artifacts` array and it would match \"test-1.2.3.tgz\" artifact on CircleCI. |\n| order_by | | string | `build_num` | When looking for the latest build, use this field in [response](https://circleci.com/docs/api/v1-reference/#recent-builds-project) to define the order (`stop_time` could be an interesting option for someone, too). |\n| script | * | string | | Filename of executable (typically script) that is able to install the artifacts locally. |\n| interval | | integer | `60` | When running in continuous mode, this number specifies the number of seconds between two consecutive checks on CircleCI. |\n| directory | | string | `/tmp` | The name of the directory in which build-related sub-directories storing the artifacts will be created. Make sure the directory exists and you have write permissions there. |\n| last | | integer | `0` | The number of the latest build successfully installed locally. This field is auto-updated by the tool after each successful installation. |\n| timeout | | integer | `45` | How long to wait for downloading an artifact (per-artifact-download setting). If downloading takes longer than provided number of seconds, it is considered failed. |\n\n(1) One of \"branch\" and \"ignore_branch\" fields must be provided. If \"ignore_branch\" is set to `false` (default),\nthe \"branch\" field must be provided.\n\n## How it works\n\nWhen the tool is started, it reads the configuration file specified as command-line argument. The structure of the configuration file is described above.\n\nUnless you also pass specific CircleCI build number, the first thing cci-pingu does is figuring out what is the latest successful CircleCI build for given project on specified branch, or any branch in case ignore_branch is set to `true`.  The order in which the latest successful build is looked up is defined with the `order_by` configuration option, and it is looked up in 100 lastest builds by `build_num`. In case `workflows_job_name` configuration option is provided, the successful builds are filtered on this specified workflows job name, other builds are not even considered.\n\nThis number (or number passed explicitly on command line as the build number to install) is then compared with the number of the latest CircleCI build installed locally (and stored in config file under `last` key).\n\nIf that build is already installed locally, it is either installed again (in case you used `--install` option), or the build is ignored. Then the tool either terminates (when started with `--run-once` or `--install` option), or (in continuous mode, which is the default operation mode) it waits `interval` seconds and tries again.\n\nWhen the tool finds out that the latest CircleCI build (or the build provided on command line explicitly) is not installed locally, it retrieves the information about given build, including the artifacts of the build, and then compiles a list of artifacts that needs to be downloaded by comparing the list of artifacts listed in configuration file. As mentioned above, the list from configuration file is actually list of artifact name *substrings*, so when you have \"test\" in the `artifacts` array of the configuration file, and the build info indicates that there are two artifacts on CircleCI, \"test-1.2.3.tgz\" and \"test-db-0.1.2.dump\", then both the artifacts will match the substring and will be added to the list of artifacts to be donwloaded.\n\nOnce we know the list of the artifacts, the tool will create a new directory under `directory` from the config file. The name of the directory is `build-\u003cCCI-build-number\u003e[.installation-attempt-number]`. The installation attempt number is only used in case there already was some attempt to install the exact same build, but it failed for any reason.\n\nAfter the directory is created, cci-pingu will download all the artifacts from the compiled list.\n\nWhen all of the artifacts are downloaded into that directory, the tool starts executable (typically installation bash script) specified in the configuration file as `script`. This script must take two command line arguments, which are:\n* the name of the directory into which the artifacts from CircleCI were downloaded, and\n* the build number currently processed.\nIt is expected that the script knows how to use the artifacts and what exactly to do with them to successfuly install them locally.\n\nIt might be a good idea to delete the directories from previous installations, and leave the last *N* artifact directories there, to keep the disk space occupied with these directories limited.\n\n```\n(ls -td build-* | head -n 5; ls -d build-*) | sort | uniq -u | xargs rm -rf\n```\n\nIn case the return value of the installation script is 0, the installation is considered successful (in which case the `last` field of the configuration file is updated), otherwise it is considered failed.\n\nIn continuous mode (the default operation mode) the tool waits `interval` seconds and starts the check / installation again. If started with `--run-once` or when the CircleCI build number is passed explicitly on command line, then cci-pingu terminates.\n\n## Command line options\n\n| Long name | Short name | Mandatory | Value type | Description |\n| --------- |:----------:|:---------:|:----------:| ----------- |\n| `--config` | `-c` | * | string | Path to configuration JSON file. |\n| `--debug` | `-d` | | boolean | Log verbosely. |\n| `--silent` | `-s` | | boolean | Log errors only. |\n| `--no-time` | | | boolean | Do NOT prefix output lines with timestamp and log-level. |\n| `--run-once` | `-1` | | boolean | Do NOT run as a monitoring daemon. |\n| `--help` | `-h` | | boolean | Print help and exit. |\n| `--version` | `-v` | | boolean | Print version and exit. |\n| `--install` | `-i` | | integer | Install given build (ignore cfg `branch`). |\n\nAll logs go to `stdout`, feel free to redirect as needed.\n\n## Building from code\n\n```\n$ git clone git@github.com:salsita/cci-pingu.git\n$ cd cci-pingu\n$ npm i\n$ npm run build\n```\n\n### `package.json` npm scripts\n\n```\n$ npm run build\n```\nGenerate version file, lint the ES6 source code, transpile the ES6 source code into `dist` directory, and verify the (transpiled) tests pass on the (transpiled) code.\n\n```\n$ npm run babel\n```\nTranspiles (using babel with `.babelrc` configuration file) the ES6 source code from `lib` directory and `cci-pingu.js` file into `dist` directory, that is referenced from binary `bin/cci-pingu`.\n\n```\n$ npm run gen-ver\n```\nGenerate `lib/version.js` file exporting the current version of the tool, as taken from `package.json` itself.\n\n```\n$ npm run lint\n```\nLint the (ES6) source code, using `.eslintrc.json` configuration file.\n\n```\n$ npm test\n```\nVerify the (transpiled) tests pass on the (traspiled) code. The test runner is mocha.\n\n```\n$ npm start\n```\nStart the tool in tool with `config/default.json` configuration file in debug mode. Note: the tool must be built first (so you need to run `npm run build` prior to `npm start`). Also, the `default.json` file needs to be updated with project-related information and CCI API token before starting the tool.\n\n## Licence\n\nThe MIT License (MIT)\n\nCopyright (c) 2016--2019 Salsita Software\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsalsita%2Fcci-pingu","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsalsita%2Fcci-pingu","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsalsita%2Fcci-pingu/lists"}