Compare commits

..

39 Commits

Author SHA1 Message Date
Ville Brofeldt
5719fefdd4 add rc4 changelog entries 2021-01-16 08:26:11 +02:00
Shuyao Bi
2187d1a409 Fix 500 error when loading dashboards with slice having deleted dataset (#12535) 2021-01-16 08:12:15 +02:00
Beto Dealmeida
c38a5fc1d8 fix: case expression should not have double quotes (#12562) 2021-01-16 08:04:13 +02:00
Beto Dealmeida
147f750829 fix: height on grid results (#12558) 2021-01-16 08:03:54 +02:00
Jesse Yang
5786513cbb fix(viz): missing groupby and broken adhoc metrics for boxplot (#12556) 2021-01-16 08:03:30 +02:00
Hugh A. Miles II
ae6e54025b fix: Add MAX_SQL_ROW value to LIMIT_DROPDOWN (#12555) 2021-01-16 08:03:12 +02:00
Geido
7e0eedccf8 fix: Popover closes on change of dropdowns values (#12410) 2021-01-16 08:02:15 +02:00
Ville Brofeldt
c4e6baef3b add rc3 changelog entries 2021-01-15 17:33:28 +02:00
Amit Miran
b652995b56 chore: rename docker image in build_docker_image.sh, docker-compose.yml and helm values.yaml (#12337) 2021-01-15 17:27:18 +02:00
Ahmed Adel
739ab14136 feat(db-engine): Add support for Apache Solr (#12403)
* [db engine] Add support for Apache Solr

* Fixing typo
2021-01-15 15:12:29 +02:00
Michael S. Molina
a1f53fb645 Fix list filters vertical alignment (#12497) 2021-01-15 13:47:07 +02:00
Kamil Gabryjelski
52b581f922 fix: Select options overflowing Save chart modal on Explore view (#12522)
* Fix select options overflowing modal

* fix unit test

Co-authored-by: Ville Brofeldt <ville.v.brofeldt@gmail.com>
2021-01-15 13:32:12 +02:00
Xiang Fu
5f2de1df71 Fixing Pinot queries for time granularities: WEEKS/MONTHS/QUARTERS/YEARS (#12536) 2021-01-15 11:32:30 +02:00
Jesse Yang
603ab75a62 fix(explore): Add Time section back to FilterBox (#12537) 2021-01-15 11:04:18 +02:00
Jesse Yang
027e2075f5 fix(explore): time table control panel (#12532) 2021-01-15 11:04:05 +02:00
Beto Dealmeida
5791f23e73 fix: lowercase all columns in examples (#12530) 2021-01-15 11:03:38 +02:00
Daniel Vaz Gaspar
cf69f29144 ci: remove refs/tags from docker tags on a release (#12518)
* ci: remove refs/tags from docker tags on a release

* wider head
2021-01-15 10:45:15 +02:00
Daniel Vaz Gaspar
72977fc71f fix: impose dataset ownership check on old API (#12491)
* fix: impose dataset ownership check on old API

* update UPDATING.md

* partially protect the old MVC also

* prevent metric and column add and update
2021-01-15 10:44:51 +02:00
Ville Brofeldt
46fd85a141 update changelog with rc2 entries 2021-01-14 09:50:32 +02:00
Beto Dealmeida
78e4b02305 fix: import ZIP files that have been modified (#12425)
* fix: import ZIP files that have been modified

* Add unit test
2021-01-13 20:39:50 +02:00
Beto Dealmeida
696c9773bd fix (SQL Lab): disappearing results on tab switch (#12472)
* fix (SQL Lab): disappearing results on tab switch

* Remove state

* Fix test
2021-01-13 19:10:31 +02:00
Yongjie Zhao
4f35234f3e fix(timepicker): make pyparsing thread safe (#12489)
* fix: make pyparsing thread safe

* remove parenthesis for decorator
2021-01-13 19:06:08 +02:00
Jesse Yang
b213c1cb1f fix(dashboard): use datasource id from slice metadata (#12483) 2021-01-13 19:05:50 +02:00
Grace Guo
b3e7ef2da6 fix: do not show vertical scrollbar for charts in dashboard (#12478)
* fix: do not show vertical scrollbar for charts in dashboard

* Proper fix for #11419

Co-authored-by: Jesse Yang <jesse.yang@airbnb.com>
2021-01-13 19:05:31 +02:00
Evan Rusackas
ea54e0a7cf chore: bump superset-ui deckgl plugin (#12466) 2021-01-13 19:05:12 +02:00
Phillip Kelley-Dotson
3a553c9ef2 bump superset-ui packages for rolling window change (#12426) 2021-01-13 19:04:51 +02:00
Kasia Kucharczyk
34da995dd9 fix(dashboard): artefacts shown while drag and dropping deck.gl charts (#12418)
* [12181] Fix artifacts while drag and dropping deck.gl charts.

* Run prettier
2021-01-13 19:04:36 +02:00
Kamil Gabryjelski
288f6bb88c feat: Resizable dataset and controls panels on Explore view (#12411)
* Implement resizable panels on explore view

* Optimize chart rendering while resizing

* Make dataset column narrower

Co-authored-by: Evan Rusackas <evan@preset.io>
2021-01-13 19:03:00 +02:00
Michael S. Molina
507302d639 Fixes control panel fields styling (#12236) (#12326) 2021-01-13 19:02:55 +02:00
Yongjie Zhao
35c15b8b3a refactor: from superset.utils.core break down date_parser (#12408) 2021-01-13 19:00:54 +02:00
Ville Brofeldt
90915db60d fix(native-filters): incorrect queriesData state (#12409) 2021-01-12 14:34:01 +02:00
Agata Stawarz
d940cae8d5 fix: Refresh Interval Modal dropdown (#12406) 2021-01-12 14:33:18 +02:00
Junlin Chen
a83653735f chore: change Datasource to Dataset in Explore ui (#12402)
* chore(explore):change dataset to datasource in ui

* modal

* Add space

* Changing it back🤦🏾‍♀️

* Chargeback
2021-01-12 14:32:58 +02:00
Yongjie Zhao
e3b65f2519 feat(explore): add tooltip to timepicker label (#12401) 2021-01-12 14:32:36 +02:00
Jesse Yang
f2afee9832 chore: upgrade eslint, babel, and prettier (#12393) 2021-01-12 14:32:14 +02:00
Junlin Chen
bd6525fdf5 chore: Fix typo “Rest” to “Reset” (#12392) 2021-01-12 14:31:57 +02:00
Geido
dc203c174c chore: Show datasets when search input is empty (#12391) 2021-01-12 14:31:26 +02:00
Yongjie Zhao
6d59351462 fix(explore): long metric name display (#12387)
* fix(explore): long metric name display

* add tooltip to control
2021-01-12 14:30:57 +02:00
Daniel Gaspar
c837c1c739 release: bump to 1.0.0 and CHANGELOG 2021-01-09 23:37:45 +02:00
7209 changed files with 402264 additions and 1154241 deletions

View File

@@ -52,50 +52,3 @@ github:
squash: true
merge: false
rebase: false
ghp_branch: gh-pages
ghp_path: /
protected_branches:
master:
required_status_checks:
# strict means "Require branches to be up to date before merging".
strict: false
# contexts are the names of checks that must pass
# unfortunately AFAICT for `matrix:` jobs, we have to itemize every
# combination here.
contexts:
- lint-check
- cypress-matrix (0, chrome)
- cypress-matrix (1, chrome)
- cypress-matrix (2, chrome)
- cypress-matrix (3, chrome)
- cypress-matrix (4, chrome)
- cypress-matrix (5, chrome)
- dependency-review
- frontend-build
- pre-commit (current)
- pre-commit (next)
- pre-commit (previous)
- test-mysql
- test-postgres (current)
- test-postgres (next)
- test-postgres-hive
- test-postgres-presto
- test-sqlite
- unit-tests (current)
- unit-tests (next)
required_pull_request_reviews:
dismiss_stale_reviews: false
require_code_owner_reviews: true
required_approving_review_count: 1
required_signatures: false
gh-pages:
required_pull_request_reviews:
dismiss_stale_reviews: false
require_code_owner_reviews: true
required_approving_review_count: 1
required_signatures: false

View File

@@ -1,35 +1,11 @@
codecov:
notify:
after_n_builds: 4
ignore:
- "superset/migrations/versions/*.py"
- "superset-frontend/packages/superset-ui-demo/**/*"
- "**/*.stories.tsx"
- "**/*.stories.jsx"
coverage:
status:
project:
default:
informational: true
# Commits pushed to master should not make the overall
# project coverage decrease:
target: auto
threshold: 0%
core-packages-ts:
target: 100%
paths:
- 'superset-frontend/packages'
- '!superset-frontend/packages/**/*.jsx'
- '!superset-frontend/packages/**/*.tsx'
core-packages-tsx:
target: 50%
paths:
- 'superset-frontend/packages/**/*.jsx'
- 'superset-frontend/packages/**/*.tsx'
patch:
default:
informational: true
threshold: 0%
flag_management:
default_rules:
carryforward: true

View File

@@ -15,9 +15,6 @@
# limitations under the License.
#
**/__pycache__/
**/.git
**/.apache_superset.egg-info
**/.github
**/.mypy_cache
**/.pytest_cache
**/.tox
@@ -33,17 +30,11 @@
**/*.pyc
**/*.sqllite
**/*.swp
**/.terser-plugin-cache/
**/.storybook/
**/node_modules/
tests/
docs/
install/
superset-frontend/cypress-base/
superset-frontend/node_modules/
superset-frontend/cypress/
superset-frontend/coverage/
superset-frontend/.temp_cache/
superset/static/assets/
superset-websocket/dist/
venv
.venv

View File

@@ -15,4 +15,4 @@
# limitations under the License.
#
FLASK_APP="superset.app:create_app()"
FLASK_DEBUG=true
FLASK_ENV="development"

3
.gitattributes vendored
View File

@@ -1,3 +0,0 @@
docker/**/*.sh text eol=lf
*.svg binary
*.ipynb binary

32
.github/CODEOWNERS vendored
View File

@@ -1,32 +0,0 @@
# Notify all committers of DB migration changes, per SIP-59
# https://github.com/apache/superset/issues/13351
/superset/migrations/ @mistercrunch @michael-s-molina @betodealmeida @eschutho
# Notify some committers of changes in the components
/superset-frontend/src/components/Select/ @michael-s-molina @geido @kgabryje
/superset-frontend/src/components/MetadataBar/ @michael-s-molina @geido @kgabryje
/superset-frontend/src/components/DropdownContainer/ @michael-s-molina @geido @kgabryje
# Notify Helm Chart maintainers about changes in it
/helm/superset/ @craig-rueda @dpgaspar @villebro @nytai @michael-s-molina
# Notify E2E test maintainers of changes
/superset-frontend/cypress-base/ @sadpandajoe @geido @eschutho @rusackas @betodealmeida
# Notify PMC members of changes to GitHub Actions
/.github/ @villebro @geido @eschutho @rusackas @betodealmeida @nytai @mistercrunch @craig-rueda @kgabryje @dpgaspar
# Notify PMC members of changes to required GitHub Actions
/.asf.yaml @villebro @geido @eschutho @rusackas @betodealmeida @nytai @mistercrunch @craig-rueda @kgabryje @dpgaspar
# Maps are a finicky contribution process we care about
**/*.geojson @villebro @rusackas
/superset-frontend/plugins/legacy-plugin-chart-country-map/ @villebro @rusackas

View File

@@ -1,99 +0,0 @@
name: Bug report
description: Report a bug to improve Superset's stability
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Hello Superset Community member! Please keep things tidy by putting your post in the proper place:
🚨 Reporting a security issue: send an email to security@superset.apache.org. DO NOT USE GITHUB ISSUES TO REPORT SECURITY PROBLEMS.
🐛 Reporting a bug: use this form.
🙏 Asking a question or getting help: post in the [Superset Slack chat](http://bit.ly/join-superset-slack) or [GitHub Discussions](https://github.com/apache/superset/discussions) under "Q&A / Help".
💡 Requesting a new feature: Search [GitHub Discussions](https://github.com/apache/superset/discussions) to see if it exists already. If not, add a new post there under "Ideas".
- type: textarea
id: bug-description
attributes:
label: Bug description
description: A clear description of what the bug is, including reproduction steps and expected behavior.
placeholder: |
The bug is that...
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
validations:
required: true
- type: textarea
id: screenshots-recordings
attributes:
label: Screenshots/recordings
description: If applicable, add screenshots or recordings to help explain your problem.
- type: markdown
attributes:
value: |
### Environment
Please specify your environment. If your environment does not match the alternatives, you need to upgrade your environment before submitting the issue as it may have already been fixed. For additional information about the releases, see [Release Process](https://github.com/apache/superset/wiki/Release-Process).
- type: dropdown
id: superset-version
attributes:
label: Superset version
options:
- master / latest-dev
- "4.1.1"
- "4.0.2"
validations:
required: true
- type: dropdown
id: python-version
attributes:
label: Python version
options:
- "3.9"
- "3.10"
- "3.11"
- Not applicable
- I don't know
validations:
required: true
- type: dropdown
id: node-version
attributes:
label: Node version
options:
- "16"
- "17"
- "18 or greater"
- Not applicable
- I don't know
validations:
required: true
- type: dropdown
id: browser
attributes:
label: Browser
options:
- Chrome
- Firefox
- Safari
- Not applicable
validations:
required: true
- type: textarea
id: additional-context
attributes:
label: Additional context
description: |
Add any other context about the problem here such as the feature flags that you have enabled, any customizations you have made, the data source you are querying, etc.
- type: checkboxes
id: checklist
attributes:
label: Checklist
description: Make sure to follow these steps before submitting your issue - thank you!
options:
- label: I have searched Superset docs and Slack and didn't find a solution to my problem.
- label: I have searched the GitHub issue tracker and didn't find a similar bug report.
- label: I have checked Superset's logs for errors and if I found a relevant Python stacktrace, I included it here as text in the "additional context" section.
validations:
required: true

47
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,47 @@
---
name: Bug report
about: Create a report to help us improve
labels: "#bug"
---
A clear and concise description of what the bug is.
### Expected results
what you expected to happen.
### Actual results
what actually happens.
#### Screenshots
If applicable, add screenshots to help explain your problem.
#### How to reproduce the bug
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
### Environment
(please complete the following information):
- superset version: `superset version`
- python version: `python --version`
- node.js version: `node -v`
### Checklist
Make sure to follow these steps before submitting your issue - thank you!
- [ ] I have checked the superset logs for python stacktraces and included it here as text if there are any.
- [ ] I have reproduced the issue with at least the latest released version of superset.
- [ ] I have checked the issue tracker for the same issue and I haven't found one similar.
### Additional context
Add any other context about the problem here.

View File

@@ -1,12 +0,0 @@
---
blank_issues_enabled: false
contact_links:
- name: Feature Request
url: https://github.com/apache/superset/discussions/new?category=ideas
about: Propose a feature request to the Superset community
- name: Q&A
url: https://github.com/apache/superset/discussions/new?category=q-a-help
about: Open a community Q&A thread on GitHub Discussions
- name: Slack
url: https://bit.ly/join-superset-slack
about: Join the Superset Community on Slack for other discussions and assistance

View File

@@ -2,6 +2,7 @@
name: Cosmetic Issue
about: Describe a cosmetic issue with CSS, positioning, layout, labeling, or similar
labels: "cosmetic-issue"
---
## Screenshot

View File

@@ -0,0 +1,18 @@
---
name: Feature request
about: Suggest an idea for this project
labels: "#enhancement"
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -0,0 +1,12 @@
---
name: Security vulnerability
about: Report a security vulnerability or issue
labels: "#security"
---
## DO NOT REPORT SECURITY VULNERABILITIES HERE
Please report security vulnerabilities to private@superset.apache.org.
In the event a community member discovers a security flaw in Superset, it is important to follow the [Apache Security Guidelines](https://www.apache.org/security/committers.html) and release a fix as quickly as possible before public disclosure. Reporting security vulnerabilities through the usual GitHub Issues channel is not ideal as it will publicize the flaw before a fix can be applied.

View File

@@ -1,15 +1,14 @@
---
name: SIP
about: "Superset Improvement Proposal. See SIP-0 (https://github.com/apache/superset/issues/5602) for details. A SIP introduces any major change into Apache Superset's code or process."
labels: sip
title: "[SIP] Your Title Here (do not add SIP number)"
assignees: "apache/superset-committers"
about: Superset Improvement Proposal
labels: "#SIP"
---
*Please make sure you are familiar with the SIP process documented*
[here](https://github.com/apache/superset/issues/5602). The SIP will be numbered by a committer upon acceptance.
(here)[https://github.com/apache/superset/issues/5602]
## [SIP] Proposal for ...<title>
## [SIP] Proposal for XXX
### Motivation

View File

@@ -1,27 +1,18 @@
<!---
Please write the PR title following the conventions at https://www.conventionalcommits.org/en/v1.0.0/
Example:
fix(dashboard): load charts correctly
-->
### SUMMARY
<!--- Describe the change below, including rationale and design decisions -->
### BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
<!--- Skip this if not applicable -->
### TESTING INSTRUCTIONS
<!--- Required! What steps can be taken to manually verify the changes? -->
### TEST PLAN
<!--- What steps should be taken to verify the changes -->
### ADDITIONAL INFORMATION
<!--- Check any relevant boxes with "x" -->
<!--- HINT: Include "Fixes #nnn" if you are fixing an existing issue -->
- [ ] Has associated issue:
- [ ] Required feature flags:
- [ ] Changes UI
- [ ] Includes DB Migration (follow approval process in [SIP-59](https://github.com/apache/superset/issues/13351))
- [ ] Migration is atomic, supports rollback & is backwards-compatible
- [ ] Confirm DB migration upgrade and downgrade tested
- [ ] Runtime estimates and downtime expectations provided
- [ ] Requires DB Migration.
- [ ] Confirm DB Migration upgrade and downgrade tested.
- [ ] Introduces new feature or API
- [ ] Removes existing feature or API

38
.github/SECURITY.md vendored
View File

@@ -1,38 +0,0 @@
# Security Policy
This is a project of the [Apache Software Foundation](https://apache.org) and follows the
ASF [vulnerability handling process](https://apache.org/security/#vulnerability-handling).
## Reporting Vulnerabilities
**⚠️ Please do not file GitHub issues for security vulnerabilities as they are public! ⚠️**
Apache Software Foundation takes a rigorous standpoint in annihilating the security issues
in its software projects. Apache Superset is highly sensitive and forthcoming to issues
pertaining to its features and functionality.
If you have any concern or believe you have found a vulnerability in Apache Superset,
please get in touch with the Apache Superset Security Team privately at
e-mail address [security@superset.apache.org](mailto:security@superset.apache.org).
More details can be found on the ASF website at
[ASF vulnerability reporting process](https://apache.org/security/#reporting-a-vulnerability)
We kindly ask you to include the following information in your report:
- Apache Superset version that you are using
- A sanitized copy of your `superset_config.py` file or any config overrides
- Detailed steps to reproduce the vulnerability
Note that Apache Superset is not responsible for any third-party dependencies that may
have security issues. Any vulnerabilities found in third-party dependencies should be
reported to the maintainers of those projects. Results from security scans of Apache
Superset dependencies found on its official Docker image can be remediated at release time
by extending the image itself.
**Your responsible disclosure and collaboration are invaluable.**
## Extra Information
- [Apache Superset documentation](https://superset.apache.org/docs/security)
- [Common Vulnerabilities and Exposures by release](https://superset.apache.org/docs/security/cves)
- [How Security Vulnerabilities are Reported & Handled in Apache Superset (Blog)](https://preset.io/blog/how-security-vulnerabilities-are-reported-and-handled-in-apache-superset/)

View File

@@ -0,0 +1 @@
indent_size = 2

View File

@@ -0,0 +1,3 @@
dist/
lib/
node_modules/

View File

@@ -0,0 +1,26 @@
module.exports = {
plugins: ['jest', '@typescript-eslint'],
extends: ['plugin:jest/all'],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 9,
sourceType: 'module',
},
rules: {
'eslint-comments/no-use': 'off',
'import/no-namespace': 'off',
'no-unused-vars': 'off',
'no-console': 'off',
'jest/prefer-expect-assertions': 'off',
'jest/no-disabled-tests': 'warn',
'jest/no-focused-tests': 'error',
'jest/no-identical-title': 'error',
'jest/prefer-to-have-length': 'warn',
'jest/valid-expect': 'error',
},
env: {
node: true,
es6: true,
'jest/globals': true,
},
};

View File

@@ -0,0 +1,34 @@
name: Tests
on:
pull_request:
paths-ignore:
- '**.md'
push:
branches:
- master
paths-ignore:
- '**.md'
jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, macOS-latest]
name: Test on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: '12.x'
- name: Install dependencies
run: npm ci
- name: Run prettier format check
run: npm run format-check
- name: Build
run: npm run build
- name: Run tests
run: npm run test
- name: Upload code coverage
run: |
bash <(curl -s https://codecov.io/bash)

View File

@@ -0,0 +1,6 @@
lib
coverage
node_modules
!dist
!dist/cache

View File

@@ -0,0 +1,3 @@
dist/
lib/
node_modules/

View File

@@ -0,0 +1,11 @@
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"trailingComma": "all",
"bracketSpacing": true,
"arrowParens": "avoid",
"parser": "typescript"
}

View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2018 GitHub, Inc. and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,212 @@
# cached-dependencies
[![](https://github.com/ktmud/cached-dependencies/workflows/Tests/badge.svg)](https://github.com/ktmud/cached-dependencies/actions?query=workflow%3ATests) [![codecov](https://codecov.io/gh/ktmud/cached-dependencies/branch/master/graph/badge.svg)](https://codecov.io/gh/ktmud/cached-dependencies)
Enable **multi-layer cache** and **shortcut commands** in any workflows.
Manage multiple cache targets in one step. Use either the built-in cache configs for npm, yarn, and pip, or write your own. Create a bash command library to easily reduce redudencies across workflows. Most useful for building webapps that require multi-stage building processes.
This is your all-in-one action for everything related to setting up dependencies with cache.
## Inputs
- **run**: bash commands to run, allows shortcut commands
- **caches**: path to a JS module that defines cache targets, defaults to `.github/workflows/caches.js`
- **bashlib**: path to a BASH scripts that defines shortcut commands, defaults to `.github/workflows/bashlib.sh`
- **parallel**: whether to run the commands in parallel with node subprocesses
## Examples
Following workflow sets up dependencies for a typical Python web app with both `~/.pip` and `~/.npm` cache configured in one simple step:
```yaml
jobs:
build_and_test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Install dependencies
uses: ktmud/cached-dependencies@v1
with:
run: |
npm-install
npm run build
pip-install
python ./bin/manager.py fill_test_data
```
Here we used predefined `npm-install` and `pip-install` commands to install dependencies with correponding caches.
You may also replace `npm-install` with `yarn-install` to install npm pacakges with `yarn.lock`.
```yaml
- name: Install dependencies
uses: ktmud/cached-dependencies@v1
with:
run: |
yarn-install
yarn build
pip-install
python ./bin/manager.py fill_test_data
```
See below for more details.
## Usage
### Cache configs
Under the hood, we use [@actions/cache](https://github.com/marketplace/actions/cache) to manage cache storage. But instead of defining only one cache at a time and specify them in workflow YAMLs, you manage all caches in a spearate JS file: `.github/workflows/caches.js`.
Here is [the default configuration](https://github.com/ktmud/cached-dependencies/blob/master/src/cache/caches.ts) for Linux:
```js
module.exports = {
pip: {
path: [`${process.env.HOME}/.cache/pip`],
hashFiles: ['requirements*.txt'],
keyPrefix: 'pip-',
restoreKeys: 'pip-',
},
npm: {
path: [`${HOME}/.npm`],
hashFiles: [
`package-lock.json`,
`*/*/package-lock.json`,
`!node_modules/*/package-lock.json`,
],
},
yarn: {
path: [`${HOME}/.npm`],
// */* is for supporting lerna monorepo with depth=2
hashFiles: [`yarn.lock`, `*/*/yarn.lock`, `!node_modules/*/yarn.lock`],
},
}
```
In which `hashFiles` and `keyPrefix` will be used to compute the primary cache key used in [@actions/cache](https://github.com/marketplace/actions/cache). `keyPrefix` will default to `${cacheName}-` and `restoreKeys` will default to `keyPrefix` if not specified.
It is recommended to always use absolute paths in these configs so you can share them across different worflows more easily (in case you the action is called from different working directories).
#### Speficy when to restore and save
With the predefined `cache-store` and `cache-save` bash commands, you have full flexibility on when to restore and save cache:
```yaml
steps:
- uses: actions/checkout@v2
- uses: ktmud/cached-dependencies@v1
with:
run: |
cache-restore npm
npm install
cache-save npm
cache-restore pip
pip install -r requirements.txt
cache-save pip
```
### Shortcut commands
All predefined shortcut commands can be found [here](https://github.com/ktmud/cached-dependencies/blob/master/src/scripts/bashlib.sh). You can also customize them or add new ones in `.github/workflows/bashlib.sh`.
For example, if you want to install additional packages for before saving `pip` cache, simply add this to the `bashlib.sh` file:
```bash
# override the default `pip-install` command
pip-install() {
cd $GITHUB_WORKSPACE
cache-restore pip
echo "::group::pip install"
pip install -r requirements.txt # prod requirements
pip install -r requirements-dev.txt # dev requirements
pip install -e ".[postgres,mysql]" # current pacakge with some extras
echo "::endgroup::"
cache-save pip
}
```
### Default setup command
When `run` is not provided:
```yaml
jobs:
name: Build
steps:
- name: Install dependencies
uses: ktmud/cached-depdencies@v1
```
You must provide a `default-setup-command` in the bashlib. For example,
```bash
default-setup-command() {
pip-install & npm-install
}
```
This will start installing pip and npm dependencies at the same time.
### Customize config locations
Both the two config files, `.github/workflows/bashlib.sh` and `.github/workflows/caches.js`, can be placed in other locations:
```yaml
- uses: ktmud/cached-dependencies@v1
with:
caches: ${{ github.workspace }}/.github/configs/caches.js
bashlib: ${{ github.workspace }}/.github/configs/bashlib.sh
```
### Run commands in parallel
When `parallel` is set to `true`, the `run` input will be split into an array of commands and passed to `Promise.all(...)` to execute in parallel. For example,
```yaml
- uses: ktmud/cached-dependencies@v1
with:
parallel: true
run: |
pip-install
npm-install
```
is equivalent to
```yaml
- uses: ktmud/cached-dependencies@v1
with:
run: |
pip-install & npm-install
```
If one or more of your commands must spread across multiple lines, you can add a new line between the parallel commands. Each command within a parallel group will still run sequentially.
```yaml
- uses: ktmud/cached-dependencies@v1
with:
run: |
cache-restore pip
pip install requirements*.txt
# additional pip packages
pip install package1 package2 pacakge2
cache-save pip
npm-install
cache-restore cypress
cd cypress/ && npm install
cache-save cypress
```
## License
This project is released under [the MIT License](LICENSE).

View File

@@ -0,0 +1,124 @@
import path from 'path';
import * as fs from 'fs';
import * as os from 'os';
import * as core from '@actions/core';
import * as cache from '../src/cache';
import * as inputsUtils from '../src/utils/inputs';
import * as actionUtils from '@actions/cache/src/utils/actionUtils';
import defaultCaches from '../src/cache/caches';
import { setInputs, getInput, maybeArrayToString } from '../src/utils/inputs';
import { Inputs, InputName, GitHubEvent, EnvVariable } from '../src/constants';
import caches, { npmExpectedHash } from './fixtures/caches';
describe('patch core states', () => {
it('should log error if states file invalid', () => {
const logWarningMock = jest.spyOn(actionUtils, 'logWarning');
fs.writeFileSync(`${os.tmpdir()}/cached--states.json`, 'INVALID_JSON', {
encoding: 'utf-8',
});
core.getState('haha');
expect(logWarningMock).toHaveBeenCalledTimes(2);
});
it('should persist state', () => {
core.saveState('test', '100');
expect(core.getState('test')).toStrictEqual('100');
});
});
describe('cache runner', () => {
it('should use default cache config', async () => {
await cache.loadCustomCacheConfigs();
// but `npm` actually come from `src/cache/caches.ts`
const inputs = await cache.getCacheInputs('npm');
expect(inputs?.[InputName.Path]).toStrictEqual(
maybeArrayToString(defaultCaches.npm.path),
);
expect(inputs?.[InputName.RestoreKeys]).toStrictEqual('npm-');
});
it('should override cache config', async () => {
setInputs({
[InputName.Caches]: path.resolve(__dirname, 'fixtures/caches'),
});
await cache.loadCustomCacheConfigs();
const inputs = await cache.getCacheInputs('npm');
expect(inputs?.[InputName.Path]).toStrictEqual(
maybeArrayToString(caches.npm.path),
);
expect(inputs?.[InputName.Key]).toStrictEqual(`npm-${npmExpectedHash}`);
expect(inputs?.[InputName.RestoreKeys]).toStrictEqual(
maybeArrayToString(caches.npm.restoreKeys),
);
});
it('should apply inputs and restore cache', async () => {
setInputs({
[InputName.Caches]: path.resolve(__dirname, 'fixtures/caches'),
[EnvVariable.GitHubEventName]: GitHubEvent.PullRequest,
});
const setInputsMock = jest.spyOn(inputsUtils, 'setInputs');
const inputs = await cache.getCacheInputs('npm');
const result = await cache.run('restore', 'npm');
expect(result).toBeUndefined();
// before run
expect(setInputsMock).toHaveBeenNthCalledWith(1, inputs);
// after run
expect(setInputsMock).toHaveBeenNthCalledWith(2, {
[InputName.Key]: '',
[InputName.Path]: '',
[InputName.RestoreKeys]: '',
});
// inputs actually restored to original value
expect(getInput(InputName.Key)).toStrictEqual('');
// pretend still in execution context
setInputs(inputs as Inputs);
// `core.getState` should return the primary key
expect(core.getState('CACHE_KEY')).toStrictEqual(inputs?.[InputName.Key]);
setInputsMock.mockRestore();
});
it('should run saveCache', async () => {
// call to save should also work
const logWarningMock = jest.spyOn(actionUtils, 'logWarning');
setInputs({
[InputName.Parallel]: 'true',
});
await cache.run('save', 'npm');
expect(logWarningMock).toHaveBeenCalledWith(
'Cache Service Url not found, unable to restore cache.',
);
});
it('should exit on invalid args', async () => {
// other calls do generate errors
const processExitMock = jest
.spyOn(process, 'exit')
// @ts-ignore
.mockImplementation(() => {});
// incomplete arguments
await cache.run();
await cache.run('save');
// bad arguments
await cache.run('save', 'unknown-cache');
await cache.run('unknown-action', 'unknown-cache');
setInputs({
[InputName.Caches]: 'non-existent',
});
await cache.run('save', 'npm');
expect(processExitMock).toHaveBeenCalledTimes(5);
});
});

View File

@@ -0,0 +1,5 @@
#!/bin/bash
default-setup-command() {
print-cachescript-path
}

View File

@@ -0,0 +1,14 @@
/**
* Example cache config.
*/
export const npmHashFiles = ['.*ignore'];
export const npmExpectedHash =
'13ed29a1c7ec906e7dcb20626957ebfcd3f0f2174bd2685a012105792bf1ff55';
export default {
npm: {
path: [`~/.npm`],
hashFiles: npmHashFiles,
restoreKeys: 'node-npm-',
},
};

View File

@@ -0,0 +1,101 @@
/**
* Test default runner.
*/
import { setInputs } from '../src/utils/inputs';
import { InputName, DefaultInputs } from '../src/constants';
import * as setup from '../src/setup';
import path from 'path';
const extraBashlib = path.resolve(__dirname, './fixtures/bashlib.sh');
describe('setup runner', () => {
// don't actually run the bash script
const runCommandMock = jest.spyOn(setup, 'runCommand');
it('should allow custom bashlib', async () => {
setInputs({
[InputName.Bashlib]: extraBashlib,
});
await setup.run();
expect(runCommandMock).toHaveBeenCalledTimes(1);
expect(runCommandMock).toHaveBeenCalledWith(
DefaultInputs[InputName.Run],
extraBashlib,
);
});
it('should allow inline bash overrides', async () => {
const processExitMock = jest
.spyOn(process, 'exit')
// @ts-ignore
.mockImplementation(() => {});
setInputs({
[InputName.Bashlib]: '',
[InputName.Parallel]: 'false',
[InputName.Run]: `
${DefaultInputs[InputName.Run]}() {
echo "It works!"
exit 202
}
${DefaultInputs[InputName.Run]}
`,
});
// allow the bash script to run for one test, but override the default
await setup.run();
expect(runCommandMock).toHaveBeenCalledTimes(1);
expect(processExitMock).toHaveBeenCalledTimes(1);
expect(processExitMock).toHaveBeenCalledWith(1);
});
it('should use run commands', async () => {
// don't run the commands when there is no overrides
runCommandMock.mockImplementation(async () => {});
setInputs({
[InputName.Bashlib]: 'non-existent',
[InputName.Run]: 'print-cachescript-path',
});
await setup.run();
expect(runCommandMock).toHaveBeenCalledTimes(1);
expect(runCommandMock).toHaveBeenCalledWith('print-cachescript-path', '');
});
it('should handle single-new-line parallel commands', async () => {
setInputs({
[InputName.Run]: `
test-command-1
test-command-2
`,
[InputName.Parallel]: 'true',
});
await setup.run();
expect(runCommandMock).toHaveBeenNthCalledWith(1, 'test-command-1', '');
expect(runCommandMock).toHaveBeenNthCalledWith(2, 'test-command-2', '');
});
it('should handle multi-new-line parallel commands', async () => {
setInputs({
[InputName.Run]: `
test-1-1
test-1-2
test-2
`,
[InputName.Parallel]: 'true',
});
await setup.run();
expect(runCommandMock).toHaveBeenNthCalledWith(
1,
'test-1-1\n test-1-2',
'',
);
expect(runCommandMock).toHaveBeenNthCalledWith(2, 'test-2', '');
});
});

View File

@@ -0,0 +1,10 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"baseUrl": "./",
"outDir": "../build",
"noEmit": true,
"rootDir": "../"
},
"exclude": ["node_modules"]
}

View File

@@ -0,0 +1,25 @@
name: Cached Dependencies
description: Setup multi-layered cache and dependencies in one step, share predefined commands across workflows
author: Jesse Yang <hello@yjc.me>
branding:
icon: layers
color: yellow
inputs:
caches:
required: false
description: Path to a JS file with cache configs
default: ${{ github.workspace }}/.github/workflows/caches.js
bashlib:
required: false
description: Path to a Bash script with command shortcuts
default: ${{ github.workspace }}/.github/workflows/bashlib.sh
run:
required: false
description: Setup commands to run, can use shortcuts defined in bashlib
default: default-setup-command
parallel:
required: false
description: Whether to run commands in parallel
runs:
using: node12
main: dist/index.js

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,57 @@
'use strict';
const fs = require('fs');
const crypto = require('crypto');
const {parentPort} = require('worker_threads');
const handlers = {
hashFile: (algorithm, filePath) => new Promise((resolve, reject) => {
const hasher = crypto.createHash(algorithm);
fs.createReadStream(filePath)
// TODO: Use `Stream.pipeline` when targeting Node.js 12.
.on('error', reject)
.pipe(hasher)
.on('error', reject)
.on('finish', () => {
const {buffer} = hasher.read();
resolve({value: buffer, transferList: [buffer]});
});
}),
hash: async (algorithm, input) => {
const hasher = crypto.createHash(algorithm);
if (Array.isArray(input)) {
for (const part of input) {
hasher.update(part);
}
} else {
hasher.update(input);
}
const hash = hasher.digest().buffer;
return {value: hash, transferList: [hash]};
}
};
parentPort.on('message', async message => {
try {
const {method, args} = message;
const handler = handlers[method];
if (handler === undefined) {
throw new Error(`Unknown method '${method}'`);
}
const {value, transferList} = await handler(...args);
parentPort.postMessage({id: message.id, value}, transferList);
} catch (error) {
const newError = {message: error.message, stack: error.stack};
for (const [key, value] of Object.entries(error)) {
if (typeof value !== 'object') {
newError[key] = value;
}
}
parentPort.postMessage({id: message.id, error: newError});
}
});

View File

@@ -0,0 +1,21 @@
module.exports = {
clearMocks: true,
moduleFileExtensions: ['js', 'ts'],
testEnvironment: 'node',
testMatch: ['**/*.test.ts'],
transform: {
'^.+\\.ts$': 'ts-jest',
},
transformIgnorePatterns: [
'/node_modules/(?!@actions).+\\.js$',
],
verbose: true,
};
// suppress debug messages
const processStdoutWrite = process.stdout.write.bind(process.stdout);
process.stdout.write = (str, encoding, cb) => {
processStdoutWrite(str.split('\n').filter(x => {
return !/^::debug::/.test(x);
}).join('\n'), encoding, cb);
};

8197
.github/actions/cached-dependencies/package-lock.json generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,47 @@
{
"name": "setup-superset-action",
"version": "1.0.0",
"private": true,
"keywords": [
"actions",
"node",
"setup",
"superset"
],
"main": "dist/run",
"scripts": {
"all": "npm run format && npm run lint && npm run test && npm run build",
"build": "npm run clean && tsc && ncc build -o dist src/run.ts && ncc build -o dist/scripts/cache src/scripts/cache.ts",
"clean": "rm -rf ./lib ./dist",
"coverage": "npm run test && open ./coverage/lcov-report/index.html",
"format": "prettier --write **/*.ts",
"format-check": "prettier --check **/*.ts",
"lint": "eslint src/**/*.ts",
"test": "jest --clearCache && jest --coverage"
},
"dependencies": {
"@actions/cache": "actions/cache#d29c1df198dd38ac88e0ae23a2881b99c2d20e68",
"@actions/core": "1.2.4",
"@actions/exec": "1.0.4",
"@actions/glob": "0.1.0",
"@types/uuid": "7.0.4",
"hasha": "5.2.0",
"tempy": "0.6.0",
"uuid": "7.0.3"
},
"devDependencies": {
"@types/jest": "26.0.7",
"@types/node": "12.12.53",
"@typescript-eslint/eslint-plugin": "3.7.1",
"@typescript-eslint/parser": "3.7.1",
"@zeit/ncc": "0.22.3",
"eslint": "7.5.0",
"eslint-plugin-jest": "23.19.0",
"jest": "26.1.0",
"js-yaml": "3.14.0",
"prettier": "2.0.5",
"prettier-plugin-packagejson": "2.2.5",
"ts-jest": "26.1.4",
"typescript": "3.9.7"
}
}

View File

@@ -0,0 +1,5 @@
{
"extends": [
"config:base"
]
}

View File

@@ -0,0 +1,49 @@
/**
* Default cache configs
*/
import * as os from 'os';
export interface CacheConfig {
path: string[] | string;
hashFiles: string[] | string;
keyPrefix?: string;
restoreKeys?: string[] | string;
}
export interface CacheConfigs {
[cacheName: string]: CacheConfig;
}
const { HOME = '~' } = process.env;
const platform = os.platform() as 'linux' | 'darwin' | 'win32';
const pathByPlatform = {
linux: {
pip: `${HOME}/.cache/pip`,
},
darwin: {
pip: `${HOME}/Library/Caches/pip`,
},
win32: {
pip: `${HOME}\\AppData\\Local\\pip\\Cache`,
},
};
export default {
pip: {
path: pathByPlatform[platform].pip,
hashFiles: 'requirements*.txt',
},
npm: {
path: `${HOME}/.npm`,
hashFiles: [
`package-lock.json`,
// support lerna monorepo with depth=2
`*/*/package-lock.json`,
`!node_modules/*/package-lock.json`,
],
},
yarn: {
path: `${HOME}/.npm`,
hashFiles: [`yarn.lock`, `*/*/yarn.lock`, `!node_modules/*/yarn.lock`],
},
} as CacheConfigs;

View File

@@ -0,0 +1,146 @@
/**
* Execute @actions/cache with predefined cache configs.
*/
import { beginImport, doneImport } from './patch'; // monkey patch @actions modules
beginImport();
import saveCache from '@actions/cache/src/save';
import restoreCache from '@actions/cache/src/restore';
doneImport();
import hasha from 'hasha';
import * as fs from 'fs';
import * as core from '@actions/core';
import * as glob from '@actions/glob';
import { Inputs, InputName, DefaultInputs } from '../constants';
import { applyInputs, getInput, maybeArrayToString } from '../utils/inputs';
import caches from './caches'; // default cache configs
// GitHub uses `sha256` for the built-in `${{ hashFiles(...) }}` expression
// https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#hashfiles
const HASH_OPTION = { algorithm: 'sha256' };
/**
* Load custom cache configs from the `caches` path defined in inputs.
*
* @returns Whether the loading is successfull.
*/
export async function loadCustomCacheConfigs() {
const customCachePath = getInput(InputName.Caches);
try {
core.debug(`Reading cache configs from '${customCachePath}'`);
const customCache = await import(customCachePath);
Object.assign(caches, customCache.default);
} catch (error) {
if (
customCachePath !== DefaultInputs[InputName.Caches] ||
!error.message.includes('Cannot find module')
) {
core.error(error.message);
core.setFailed(
`Failed to load custom cache configs: '${customCachePath}'`,
);
return process.exit(1);
}
}
return true;
}
/**
* Generate SHA256 hash for a list of files matched by glob patterns.
*
* @param {string[]} patterns - The glob pattern.
* @param {string} extra - The extra string to append to the file hashes to
* comptue the final hash.
*/
export async function hashFiles(
patterns: string[] | string,
extra: string = '',
) {
const globber = await glob.create(maybeArrayToString(patterns));
let hash = '';
let counter = 0;
for await (const file of globber.globGenerator()) {
if (!fs.statSync(file).isDirectory()) {
hash += hasha.fromFileSync(file, HASH_OPTION);
counter += 1;
}
}
core.debug(`Computed hash for ${counter} files. Pattern: ${patterns}`);
return hasha(hash + extra, HASH_OPTION);
}
/**
* Generate GitHub Action inputs based on predefined cache config. Will be used
* to override env variables.
*
* @param {string} cacheName - Name of the predefined cache config.
*/
export async function getCacheInputs(
cacheName: string,
): Promise<Inputs | null> {
if (!(cacheName in caches)) {
return null;
}
const { keyPrefix, restoreKeys, path, hashFiles: patterns } = caches[
cacheName
];
const pathString = maybeArrayToString(path);
const prefix = keyPrefix || `${cacheName}-`;
// include `path` to hash, too, so to burse caches in case users change
// the path definition.
const hash = await hashFiles(patterns, pathString);
return {
[InputName.Key]: `${prefix}${hash}`,
[InputName.Path]: pathString,
// only use prefix as restore key if it is never defined
[InputName.RestoreKeys]:
restoreKeys === undefined ? prefix : maybeArrayToString(restoreKeys),
};
}
export const actions = {
restore(inputs: Inputs) {
return applyInputs(inputs, restoreCache);
},
save(inputs: Inputs) {
return applyInputs(inputs, saveCache);
},
};
export type ActionChoice = keyof typeof actions;
export async function run(
action: string | undefined = undefined,
cacheName: string | undefined = undefined,
) {
if (!action || !(action in actions)) {
core.setFailed(`Choose a cache action from: [restore, save]`);
return process.exit(1);
}
if (!cacheName) {
core.setFailed(`Must provide a cache name.`);
return process.exit(1);
}
const runInParallel = getInput(InputName.Parallel);
if (await loadCustomCacheConfigs()) {
if (runInParallel) {
core.info(`${action.toUpperCase()} cache for ${cacheName}`);
} else {
core.startGroup(`${action.toUpperCase()} cache for ${cacheName}`);
}
const inputs = await getCacheInputs(cacheName);
if (inputs) {
core.info(JSON.stringify(inputs, null, 2));
await actions[action as ActionChoice](inputs);
} else {
core.setFailed(`Cache '${cacheName}' not defined, failed to ${action}.`);
return process.exit(1);
}
if (!runInParallel) {
core.endGroup();
}
}
}

View File

@@ -0,0 +1,95 @@
/**
* Monkey patch to safely import and use @action/cache modules
*/
import * as utils from '@actions/cache/src/utils/actionUtils';
import * as core from '@actions/core';
import * as fs from 'fs';
import * as os from 'os';
import { InputName } from '../constants';
import { getInput } from '../utils/inputs';
interface KeyValueStore {
[key: string]: any;
}
const { logWarning, isValidEvent } = utils;
const { getState, saveState } = core;
function getStateStoreFile() {
const cacheName = getInput(InputName.Key);
return `${os.tmpdir()}/cached-${cacheName}-states.json`;
}
/**
* Load states from the persistent store.
*
* The default `core.saveState` only writes states as command output, and
* `core.getState` is only possible to read the state in a later step via ENV
* variables.
*
* So we use a temp file to save and load states, so to allow persistent
* states within the same step.
*
* Since the state output is not uniq to caches, each cache should have their
* own file for persistent states.
*/
function loadStates() {
const stateStore = getStateStoreFile();
const states: KeyValueStore = {};
try {
Object.assign(
states,
JSON.parse(fs.readFileSync(stateStore, { encoding: 'utf-8' })),
);
core.debug(`Loaded states from: ${stateStore}`)
} catch (error) {
// pass
if (error.code !== 'ENOENT') {
utils.logWarning(`Could not load states: ${stateStore}`)
utils.logWarning(error.message);
}
}
return states;
}
/**
* Save states to the persistent storage.
*/
function persistState(name: string, value: any) {
const states = loadStates();
const stateStore = getStateStoreFile();
const valueString = typeof value === 'string' ? value : JSON.stringify(value);
// make sure value is always string
states[name] = valueString;
// persist state in the temp file
fs.writeFileSync(stateStore, JSON.stringify(states, null, 2), {
encoding: 'utf-8',
});
core.debug(`Persist state "${name}=${valueString}" to ${stateStore}`);
// still pass the original value to the original function, though
return saveState(name, value);
}
/**
* Get states from persistent store, fallback to "official" states.
*/
function obtainState(name: string) {
const states = loadStates();
return states[name] || getState(name);
}
export function beginImport() {
Object.defineProperty(utils, 'isValidEvent', { value: () => false });
Object.defineProperty(utils, 'logWarning', { value: () => {} });
}
export function doneImport() {
Object.defineProperty(utils, 'isValidEvent', { value: isValidEvent });
Object.defineProperty(utils, 'logWarning', { value: logWarning });
Object.defineProperty(core, 'saveState', { value: persistState });
Object.defineProperty(core, 'getState', { value: obtainState });
}

View File

@@ -0,0 +1,43 @@
// Possible input names
export enum InputName {
// @actions/cache specific inputs
Key = 'key',
Path = 'path',
RestoreKeys = 'restore-keys',
// setup-webapp specific inputs
Run = 'run',
Caches = 'caches',
Bashlib = 'bashlib',
Parallel = 'parallel',
}
// Possible GitHub event names
export enum GitHubEvent {
Push = 'push',
PullRequest = 'pull_request',
}
// Directly available environment variables
export enum EnvVariable {
GitHubEventName = 'GITHUB_EVENT_NAME',
}
export const EnvVariableNames = new Set(Object.values(EnvVariable) as string[]);
export interface Inputs {
[EnvVariable.GitHubEventName]?: string;
[InputName.Key]?: string;
[InputName.RestoreKeys]?: string;
[InputName.Path]?: string;
[InputName.Caches]?: string;
[InputName.Bashlib]?: string;
[InputName.Run]?: string;
[InputName.Parallel]?: string;
}
export const DefaultInputs = {
[InputName.Caches]: '.github/workflows/caches.js',
[InputName.Bashlib]: '.github/workflows/bashlib.sh',
[InputName.Run]: 'default-setup-command',
} as Inputs;

View File

@@ -0,0 +1,3 @@
import { run } from './setup';
run();

View File

@@ -0,0 +1,61 @@
#!/bin/bash
# -----------------------------------------------
# Predefined command shortcuts
# -----------------------------------------------
# Exit on any command fails
set -e
bashSource=${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]:-${(%):-%x}}
cacheScript="$(dirname $(dirname $(dirname $bashSource)))/dist/scripts/cache"
print-cachescript-path() {
echo $cacheScript
}
cache-restore() {
node $cacheScript restore $1
}
cache-save() {
node $cacheScript save $1
}
# install python packages
pip-install() {
cache-restore pip
echo "::group::Install Python pacakges"
pip install -r requirements.txt # install dependencies
pip install -e . # install current directory as editable python package
echo "::endgroup"
cache-save pip
}
# install npm packages
npm-install() {
cache-restore npm
echo "::group::Install npm pacakges"
echo "npm: $(npm --version)"
echo "node: $(node --version)"
npm ci
echo "::endgroup::"
cache-save npm
}
# install npm packages via yarn
yarn-install() {
cache-restore yarn
echo "::group::Install npm pacakges via yarn"
echo "npm: $(npm --version)"
echo "node: $(node --version)"
echo "yarn: $(yarn --version)"
yarn
echo "::endgroup::"
cache-save yarn
}
# default setup will install both pip and npm pacakges at the same time
default-setup-command() {
echo 'Please provide `run` commands or configure `default-setup-command`.'
exit 1
}

View File

@@ -0,0 +1,18 @@
/**
* Runner script to store/save caches by predefined configs.
* Used in `scripts/bashlib.sh`.
*/
import { EnvVariable } from '../constants';
// To import `@actions/cache` modules safely, we must set GitHub event name to
// a invalid value, so actual runner code doesn't execute.
const originalEvent = process.env[EnvVariable.GitHubEventName];
process.env[EnvVariable.GitHubEventName] = 'CACHE_HACK';
import { run } from '../cache';
// then we restore the event name before the job actually runs
process.env[EnvVariable.GitHubEventName] = originalEvent;
// @ts-ignore
run(...process.argv.slice(2));

View File

@@ -0,0 +1,66 @@
/**
* Load inputs and execute.
*/
import * as core from '@actions/core';
import { exec } from '@actions/exec';
import path from 'path';
import fs from 'fs';
import { DefaultInputs, InputName } from './constants';
import { getInput } from './utils/inputs';
const SHARED_BASHLIB = path.resolve(__dirname, '../src/scripts/bashlib.sh');
/**
* Run bash commands with predefined lib functions.
*
* @param {string} cmd - The bash commands to execute.
*/
export async function runCommand(
cmd: string,
extraBashlib: string,
): Promise<void> {
const bashlibCommands = [`source ${SHARED_BASHLIB}`];
if (extraBashlib) {
bashlibCommands.push(`source ${extraBashlib}`);
}
try {
await exec('bash', ['-c', [...bashlibCommands, cmd].join('\n ')]);
} catch (error) {
core.setFailed(error.message);
process.exit(1);
}
}
export async function run(): Promise<void> {
let bashlib = getInput(InputName.Bashlib);
const rawCommands = getInput(InputName.Run);
const runInParallel = getInput(InputName.Parallel);
if (!fs.existsSync(bashlib)) {
if (bashlib !== DefaultInputs[InputName.Bashlib]) {
core.error(`Custom bashlib "${bashlib}" does not exist.`);
}
// don't add bashlib to runCommand
bashlib = '';
}
if (runInParallel) {
// Attempt to split by two or more new lines first, if there is still only
// one command, attempt to split by one new line. This is because users
// asked for parallelization, so we make our best efforts to get multiple
// commands.
let commands = rawCommands.split(/\n{2,}/);
if (commands.length === 1) {
commands = rawCommands.split('\n');
}
core.debug(`>> Run ${commands.length} commands in parallel...`);
await Promise.all(
commands
.map(x => x.trim())
.filter(x => !!x)
.map(cmd => exports.runCommand(cmd, bashlib)),
);
} else if (rawCommands) {
await exports.runCommand(rawCommands, bashlib);
}
}

View File

@@ -0,0 +1,2 @@
declare module '@actions/cache/dist/restore';
declare module '@actions/cache/dist/save';

View File

@@ -0,0 +1,61 @@
/**
* Manage inputs and env variables.
*/
import * as core from '@actions/core';
import {
Inputs,
EnvVariableNames,
InputName,
DefaultInputs,
} from '../constants';
export function getInput(name: keyof Inputs): string {
const value = core.getInput(name);
if (name === InputName.Parallel) {
return value.toUpperCase() === 'TRUE' ? value : '';
}
return value || DefaultInputs[name] || '';
}
/**
* Update env variables associated with some inputs.
* See: https://github.com/actions/toolkit/blob/5b940ebda7e7b86545fe9741903c930bc1191eb0/packages/core/src/core.ts#L69-L77 .
*
* @param {Inputs} inputs - The new inputs to apply to the env variables.
*/
export function setInputs(inputs: Inputs): void {
for (const [name, value] of Object.entries(inputs)) {
const envName = EnvVariableNames.has(name)
? name
: `INPUT_${name.replace(/ /g, '_').toUpperCase()}`;
process.env[envName] = value;
}
}
/**
* Apply new inputs and execute a runner function, restore them when done.
*
* @param {Inputs} inputs - The new inputs to apply to the env variables before
* excuting the runner.
* @param {runner} runner - The runner function that returns a promise.
* @returns {Promise<any>} - The result from the runner function.
*/
export async function applyInputs(
inputs: Inputs,
runner: () => Promise<void>,
): Promise<any> {
const originalInputs: Inputs = Object.fromEntries(
Object.keys(inputs).map(name => [
name,
EnvVariableNames.has(name) ? process.env[name] : core.getInput(name),
]),
);
exports.setInputs(inputs);
const result = await runner();
exports.setInputs(originalInputs);
return result;
}
export function maybeArrayToString(input: string[] | string) {
return Array.isArray(input) ? input.join('\n') : input;
}

View File

@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"lib": ["esnext"],
"moduleResolution": "node",
"outDir": "./lib",
"rootDir": ".",
"strict": true,
"noImplicitAny": true,
"esModuleInterop": true,
"preserveSymlinks": true
},
"include": [
"./src",
"./node_modules/@actions"
],
"exclude": ["**/*.test.ts", "__tests__"]
}

View File

@@ -1,31 +0,0 @@
name: 'Change Detector'
description: 'Detects file changes for pull request and push events'
inputs:
token:
description: 'GitHub token for authentication'
required: true
outputs:
python:
description: 'Whether Python-related files were changed'
value: ${{ steps.change-detector.outputs.python }}
frontend:
description: 'Whether frontend-related files were changed'
value: ${{ steps.change-detector.outputs.frontend }}
docker:
description: 'Whether docker-related files were changed'
value: ${{ steps.change-detector.outputs.docker }}
docs:
description: 'Whether docs-related files were changed'
value: ${{ steps.change-detector.outputs.docs }}
runs:
using: 'composite'
steps:
- name: Detect file changes
id: change-detector
run: |
python --version
python scripts/change_detector.py
shell: bash
env:
GITHUB_TOKEN: ${{ inputs.token }}
GITHUB_OUTPUT: ${{ github.output }}

View File

@@ -0,0 +1,13 @@
FROM ruby:2.6.0
LABEL "com.github.actions.name"="Comment on PR"
LABEL "com.github.actions.description"="Leaves a comment on an open PR matching a push event."
LABEL "com.github.actions.repository"="https://github.com/unsplash/comment-on-pr"
LABEL "com.github.actions.maintainer"="Aaron Klaassen <aaron@unsplash.com>"
LABEL "com.github.actions.icon"="message-square"
LABEL "com.github.actions.color"="blue"
RUN gem install octokit
ADD entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

7
.github/actions/comment-on-pr/LICENSE vendored Normal file
View File

@@ -0,0 +1,7 @@
Copyright 2019 Unsplash Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

27
.github/actions/comment-on-pr/README.md vendored Normal file
View File

@@ -0,0 +1,27 @@
# Comment on PR via GitHub Action
A GitHub action to comment on the relevant open PR when a commit is pushed.
## Usage
- Requires the `GITHUB_TOKEN` secret.
- Requires the comment's message in the `msg` parameter.
- Supports `push` and `pull_request` event types.
### Sample workflow
```
name: comment-on-pr example
on: pull_request
jobs:
example:
name: sample comment
runs-on: ubuntu-latest
steps:
- name: comment PR
uses: unsplash/comment-on-pr@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
msg: "Check out this message!"
```

View File

@@ -0,0 +1,15 @@
name: Comment on PR
author: Aaron Klaassen <aaron@unsplash.com>
description: Leaves a comment on an open PR matching a push event.
branding:
icon: 'message-square'
color: 'blue'
inputs:
msg:
description: Comment's message
required: true
runs:
using: 'docker'
image: 'Dockerfile'
args:
- ${{ inputs.msg }}

47
.github/actions/comment-on-pr/entrypoint.sh vendored Executable file
View File

@@ -0,0 +1,47 @@
#!/usr/bin/env ruby
require "json"
require "octokit"
json = File.read(ENV.fetch("GITHUB_EVENT_PATH"))
event = JSON.parse(json)
github = Octokit::Client.new(access_token: ENV["GITHUB_TOKEN"])
if !ENV["GITHUB_TOKEN"]
puts "Missing GITHUB_TOKEN"
exit(1)
end
if ARGV.empty?
puts "Missing message argument."
exit(1)
end
repo = event["repository"]["full_name"]
if ENV.fetch("GITHUB_EVENT_NAME") == "pull_request"
pr_number = event["number"]
else
pulls = github.pull_requests(repo, state: "open")
push_head = event["after"]
pr = pulls.find { |pr| pr["head"]["sha"] == push_head }
if !pr
puts "Couldn't find an open pull request for branch with head at #{push_head}."
exit(1)
end
pr_number = pr["number"]
end
message = ARGV.join(' ')
coms = github.issue_comments(repo, pr_number)
duplicate = coms.find { |c| c["user"]["login"] == "github-actions[bot]" && c["body"] == message }
if duplicate
puts "The PR already contains a database change notification"
exit(0)
end
github.add_comment(repo, pr_number, message)

View File

@@ -0,0 +1,55 @@
codecov:
notify:
require_ci_to_pass: yes
coverage:
notify:
slack:
default:
threshold: 1%
message: "Coverage {{changed}} for {{owner}}/{{repo}}" # customize the message
attachments: "sunburst, diff"
only_pulls: false
status:
src:
target: auto
threshold: 7%
base: auto
if_ci_failed: success
paths:
- src/
- '!src/tests/'
flags:
- src
test:
target: 60%
threshold: 10%
if_ci_failed: error
base: auto
paths:
- src/tests/
flags:
- test
precision: 2
round: down
range: "70...100"
flags:
src:
paths:
- src
- '!src/tests/'
test:
paths:
- src/tests/
parsers:
gcov:
branch_detection:
conditional: yes
loop: yes
method: no
macro: no
comment:
layout: "reach,diff,flags,tree"
behavior: default
require_changes: no

View File

@@ -0,0 +1,73 @@
plugins:
- '@typescript-eslint'
- eslint-comments
- promise
- unicorn
extends:
- airbnb-typescript
- plugin:@typescript-eslint/recommended
- plugin:eslint-comments/recommended
- plugin:promise/recommended
- plugin:unicorn/recommended
- prettier
- prettier/@typescript-eslint
settings:
import/parsers:
'@typescript-eslint/parser':
- .ts
- .tsx
- .js
import/resolver:
typescript: {}
rules:
unicorn/filename-case: off
react/static-property-placement: 0
no-prototype-builtins: 0
import/prefer-default-export: 0
'@typescript-eslint/no-explicit-any': 0
import/no-default-export: error
no-use-before-define:
- error
-
functions: false
classes: true
variables: true
'@typescript-eslint/explicit-function-return-type':
- error
-
allowExpressions: true
allowTypedFunctionExpressions: true
'@typescript-eslint/no-use-before-define':
- error
-
functions: false
classes: true
variables: true
typedefs: true
'@typescript-eslint/indent':
- 2
- 2
unicorn/prevent-abbreviations: 0
import/no-extraneous-dependencies: [error, {devDependencies: ['**/*.ts']}]
parser: "@typescript-eslint/parser"
parserOptions:
project: ./tsconfig.json
ecmaVersion: 2019
sourceType: module
env:
node: true
browser: true
ignorePatterns:
- '*.js'
overrides:
- files: ['src/tests/**/*']
plugins:
- jest
extends:
- plugin:jest/recommended
rules:
global-require: 0
'@typescript-eslint/no-var-requires': 0
no-console: 0
'@typescript-eslint/no-unused-vars': 0
'@typescript-eslint/no-throw-literal': 0

View File

@@ -0,0 +1,3 @@
# Contributing
The repository is released under the MIT license, and follows a standard Github development process, using Github tracker for issues and merging pull requests into master.

View File

@@ -0,0 +1,17 @@
---
name: Bug report
about: Create a report to help us improve
---
**Describe the bug**
A clear and concise description of what the bug is.
**Workflow**
If applicable, provide a workflow file to help explain your problem.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Additional context**
Add any other context about the problem here.

View File

@@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -0,0 +1,14 @@
### Type of Change
<!-- What type of change does your code introduce? -->
- [ ] New feature
- [ ] Bug fix
- [ ] Documentation
- [ ] Refactor
- [ ] Chore
### Resolves
- Fixes #[Add issue number here.]
### Describe Changes
<!-- Describe your changes in detail, if applicable. -->
_Describe what this Pull Request does_

View File

@@ -0,0 +1 @@
.codecov.yml,.eslintignore,.eslintrc.json,.eslintrc.yml,.github/workflows/integration.yml,.github/workflows/pr.yml,.github/workflows/push.yml,.github/workflows/readme.md,.gitignore,.prettierignore,.prettierrc.json,.prettierrc.yml,.releaserc.yml,Makefile,README.md,__tests__/main.test.ts,action.yml,dist/index.js,jest.config.js,package.json,src/ChangedFiles.ts,src/File.ts,src/FilesHelper.ts,src/GithubHelper.ts,src/InputHelper.ts,src/UtilsHelper.ts,src/main.ts,src/tests/FilesHelper.test.ts,src/tests/GithubHelper.test.ts,src/tests/InputHelper.test.ts,src/tests/UtilsHelper.test.ts,src/tests/main.test.ts,src/tests/mocks/core/index.test.ts,src/tests/mocks/core/index.ts,src/tests/mocks/env/events/issue_comment_created.json,src/tests/mocks/env/events/issue_comment_edited.json,src/tests/mocks/env/events/pull_request_opened.json,src/tests/mocks/env/events/pull_request_reopened.json,src/tests/mocks/env/events/pull_request_synchronize.json,src/tests/mocks/env/events/push.json,src/tests/mocks/env/events/push_merge.json,src/tests/mocks/env/events/schedule.json,src/tests/mocks/env/index.test.ts,src/tests/mocks/env/index.ts,src/tests/mocks/fs/index.test.ts,src/tests/mocks/fs/index.ts,src/tests/mocks/github/index.test.ts,src/tests/mocks/github/index.ts,src/tests/mocks/octokit/endpoint/merge.test.ts,src/tests/mocks/octokit/endpoint/merge.ts,src/tests/mocks/octokit/index.test.ts,src/tests/mocks/octokit/index.ts,src/tests/mocks/octokit/paginate.test.ts,src/tests/mocks/octokit/paginate.ts,src/tests/mocks/octokit/payloads.ts,src/tests/mocks/octokit/pulls/listFiles.test.ts,src/tests/mocks/octokit/pulls/listFiles.ts,src/tests/mocks/octokit/repos/compareCommits.test.ts,src/tests/mocks/octokit/repos/compareCommits.ts,src/tests/payloads.ts,src/typings/ActionError/index.d.ts,src/typings/ChangedFiles/index.d.ts,src/typings/CoreMock/index.d.ts,src/typings/FsMock/index.d.ts,src/typings/GitHubFile/index.d.ts,src/typings/GitHubMock/index.d.ts,src/typings/Inferred/index.d.ts,src/typings/Inputs/index.d.ts,src/typings/OctokitMock/index.d.ts,src/typings/TestInput/index.d.ts,tsconfig.build.json,tsconfig.json,yarn.lock
1 .codecov.yml .eslintignore .eslintrc.json .eslintrc.yml .github/workflows/integration.yml .github/workflows/pr.yml .github/workflows/push.yml .github/workflows/readme.md .gitignore .prettierignore .prettierrc.json .prettierrc.yml .releaserc.yml Makefile README.md __tests__/main.test.ts action.yml dist/index.js jest.config.js package.json src/ChangedFiles.ts src/File.ts src/FilesHelper.ts src/GithubHelper.ts src/InputHelper.ts src/UtilsHelper.ts src/main.ts src/tests/FilesHelper.test.ts src/tests/GithubHelper.test.ts src/tests/InputHelper.test.ts src/tests/UtilsHelper.test.ts src/tests/main.test.ts src/tests/mocks/core/index.test.ts src/tests/mocks/core/index.ts src/tests/mocks/env/events/issue_comment_created.json src/tests/mocks/env/events/issue_comment_edited.json src/tests/mocks/env/events/pull_request_opened.json src/tests/mocks/env/events/pull_request_reopened.json src/tests/mocks/env/events/pull_request_synchronize.json src/tests/mocks/env/events/push.json src/tests/mocks/env/events/push_merge.json src/tests/mocks/env/events/schedule.json src/tests/mocks/env/index.test.ts src/tests/mocks/env/index.ts src/tests/mocks/fs/index.test.ts src/tests/mocks/fs/index.ts src/tests/mocks/github/index.test.ts src/tests/mocks/github/index.ts src/tests/mocks/octokit/endpoint/merge.test.ts src/tests/mocks/octokit/endpoint/merge.ts src/tests/mocks/octokit/index.test.ts src/tests/mocks/octokit/index.ts src/tests/mocks/octokit/paginate.test.ts src/tests/mocks/octokit/paginate.ts src/tests/mocks/octokit/payloads.ts src/tests/mocks/octokit/pulls/listFiles.test.ts src/tests/mocks/octokit/pulls/listFiles.ts src/tests/mocks/octokit/repos/compareCommits.test.ts src/tests/mocks/octokit/repos/compareCommits.ts src/tests/payloads.ts src/typings/ActionError/index.d.ts src/typings/ChangedFiles/index.d.ts src/typings/CoreMock/index.d.ts src/typings/FsMock/index.d.ts src/typings/GitHubFile/index.d.ts src/typings/GitHubMock/index.d.ts src/typings/Inferred/index.d.ts src/typings/Inputs/index.d.ts src/typings/OctokitMock/index.d.ts src/typings/TestInput/index.d.ts tsconfig.build.json tsconfig.json yarn.lock

View File

@@ -0,0 +1,75 @@
[
".codecov.yml",
".eslintignore",
".eslintrc.json",
".eslintrc.yml",
".github/workflows/integration.yml",
".github/workflows/pr.yml",
".github/workflows/push.yml",
".github/workflows/readme.md",
".gitignore",
".prettierignore",
".prettierrc.json",
".prettierrc.yml",
".releaserc.yml",
"Makefile",
"README.md",
"__tests__/main.test.ts",
"action.yml",
"dist/index.js",
"jest.config.js",
"package.json",
"src/ChangedFiles.ts",
"src/File.ts",
"src/FilesHelper.ts",
"src/GithubHelper.ts",
"src/InputHelper.ts",
"src/UtilsHelper.ts",
"src/main.ts",
"src/tests/FilesHelper.test.ts",
"src/tests/GithubHelper.test.ts",
"src/tests/InputHelper.test.ts",
"src/tests/UtilsHelper.test.ts",
"src/tests/main.test.ts",
"src/tests/mocks/core/index.test.ts",
"src/tests/mocks/core/index.ts",
"src/tests/mocks/env/events/issue_comment_created.json",
"src/tests/mocks/env/events/issue_comment_edited.json",
"src/tests/mocks/env/events/pull_request_opened.json",
"src/tests/mocks/env/events/pull_request_reopened.json",
"src/tests/mocks/env/events/pull_request_synchronize.json",
"src/tests/mocks/env/events/push.json",
"src/tests/mocks/env/events/push_merge.json",
"src/tests/mocks/env/events/schedule.json",
"src/tests/mocks/env/index.test.ts",
"src/tests/mocks/env/index.ts",
"src/tests/mocks/fs/index.test.ts",
"src/tests/mocks/fs/index.ts",
"src/tests/mocks/github/index.test.ts",
"src/tests/mocks/github/index.ts",
"src/tests/mocks/octokit/endpoint/merge.test.ts",
"src/tests/mocks/octokit/endpoint/merge.ts",
"src/tests/mocks/octokit/index.test.ts",
"src/tests/mocks/octokit/index.ts",
"src/tests/mocks/octokit/paginate.test.ts",
"src/tests/mocks/octokit/paginate.ts",
"src/tests/mocks/octokit/payloads.ts",
"src/tests/mocks/octokit/pulls/listFiles.test.ts",
"src/tests/mocks/octokit/pulls/listFiles.ts",
"src/tests/mocks/octokit/repos/compareCommits.test.ts",
"src/tests/mocks/octokit/repos/compareCommits.ts",
"src/tests/payloads.ts",
"src/typings/ActionError/index.d.ts",
"src/typings/ChangedFiles/index.d.ts",
"src/typings/CoreMock/index.d.ts",
"src/typings/FsMock/index.d.ts",
"src/typings/GitHubFile/index.d.ts",
"src/typings/GitHubMock/index.d.ts",
"src/typings/Inferred/index.d.ts",
"src/typings/Inputs/index.d.ts",
"src/typings/OctokitMock/index.d.ts",
"src/typings/TestInput/index.d.ts",
"tsconfig.build.json",
"tsconfig.json",
"yarn.lock"
]

View File

@@ -0,0 +1 @@
.codecov.yml .eslintignore .eslintrc.json .eslintrc.yml .github/workflows/integration.yml .github/workflows/pr.yml .github/workflows/push.yml .github/workflows/readme.md .gitignore .prettierignore .prettierrc.json .prettierrc.yml .releaserc.yml Makefile README.md __tests__/main.test.ts action.yml dist/index.js jest.config.js package.json src/ChangedFiles.ts src/File.ts src/FilesHelper.ts src/GithubHelper.ts src/InputHelper.ts src/UtilsHelper.ts src/main.ts src/tests/FilesHelper.test.ts src/tests/GithubHelper.test.ts src/tests/InputHelper.test.ts src/tests/UtilsHelper.test.ts src/tests/main.test.ts src/tests/mocks/core/index.test.ts src/tests/mocks/core/index.ts src/tests/mocks/env/events/issue_comment_created.json src/tests/mocks/env/events/issue_comment_edited.json src/tests/mocks/env/events/pull_request_opened.json src/tests/mocks/env/events/pull_request_reopened.json src/tests/mocks/env/events/pull_request_synchronize.json src/tests/mocks/env/events/push.json src/tests/mocks/env/events/push_merge.json src/tests/mocks/env/events/schedule.json src/tests/mocks/env/index.test.ts src/tests/mocks/env/index.ts src/tests/mocks/fs/index.test.ts src/tests/mocks/fs/index.ts src/tests/mocks/github/index.test.ts src/tests/mocks/github/index.ts src/tests/mocks/octokit/endpoint/merge.test.ts src/tests/mocks/octokit/endpoint/merge.ts src/tests/mocks/octokit/index.test.ts src/tests/mocks/octokit/index.ts src/tests/mocks/octokit/paginate.test.ts src/tests/mocks/octokit/paginate.ts src/tests/mocks/octokit/payloads.ts src/tests/mocks/octokit/pulls/listFiles.test.ts src/tests/mocks/octokit/pulls/listFiles.ts src/tests/mocks/octokit/repos/compareCommits.test.ts src/tests/mocks/octokit/repos/compareCommits.ts src/tests/payloads.ts src/typings/ActionError/index.d.ts src/typings/ChangedFiles/index.d.ts src/typings/CoreMock/index.d.ts src/typings/FsMock/index.d.ts src/typings/GitHubFile/index.d.ts src/typings/GitHubMock/index.d.ts src/typings/Inferred/index.d.ts src/typings/Inputs/index.d.ts src/typings/OctokitMock/index.d.ts src/typings/TestInput/index.d.ts tsconfig.build.json tsconfig.json yarn.lock

View File

@@ -0,0 +1 @@
.codecov.yml,.eslintrc.yml,.prettierrc.yml,.releaserc.yml,src/FilesHelper.ts,src/GithubHelper.ts,src/InputHelper.ts,src/UtilsHelper.ts,src/tests/FilesHelper.test.ts,src/tests/GithubHelper.test.ts,src/tests/InputHelper.test.ts,src/tests/UtilsHelper.test.ts,src/tests/main.test.ts,src/tests/mocks/core/index.test.ts,src/tests/mocks/core/index.ts,src/tests/mocks/env/events/issue_comment_created.json,src/tests/mocks/env/events/issue_comment_edited.json,src/tests/mocks/env/events/pull_request_opened.json,src/tests/mocks/env/events/pull_request_reopened.json,src/tests/mocks/env/events/pull_request_synchronize.json,src/tests/mocks/env/events/push.json,src/tests/mocks/env/events/push_merge.json,src/tests/mocks/env/events/schedule.json,src/tests/mocks/env/index.test.ts,src/tests/mocks/env/index.ts,src/tests/mocks/fs/index.test.ts,src/tests/mocks/fs/index.ts,src/tests/mocks/github/index.test.ts,src/tests/mocks/github/index.ts,src/tests/mocks/octokit/endpoint/merge.test.ts,src/tests/mocks/octokit/endpoint/merge.ts,src/tests/mocks/octokit/index.test.ts,src/tests/mocks/octokit/index.ts,src/tests/mocks/octokit/paginate.test.ts,src/tests/mocks/octokit/paginate.ts,src/tests/mocks/octokit/payloads.ts,src/tests/mocks/octokit/pulls/listFiles.test.ts,src/tests/mocks/octokit/pulls/listFiles.ts,src/tests/mocks/octokit/repos/compareCommits.test.ts,src/tests/mocks/octokit/repos/compareCommits.ts,src/tests/payloads.ts,src/typings/ActionError/index.d.ts,src/typings/ChangedFiles/index.d.ts,src/typings/CoreMock/index.d.ts,src/typings/FsMock/index.d.ts,src/typings/GitHubFile/index.d.ts,src/typings/GitHubMock/index.d.ts,src/typings/Inferred/index.d.ts,src/typings/Inputs/index.d.ts,src/typings/OctokitMock/index.d.ts,src/typings/TestInput/index.d.ts,tsconfig.build.json
1 .codecov.yml .eslintrc.yml .prettierrc.yml .releaserc.yml src/FilesHelper.ts src/GithubHelper.ts src/InputHelper.ts src/UtilsHelper.ts src/tests/FilesHelper.test.ts src/tests/GithubHelper.test.ts src/tests/InputHelper.test.ts src/tests/UtilsHelper.test.ts src/tests/main.test.ts src/tests/mocks/core/index.test.ts src/tests/mocks/core/index.ts src/tests/mocks/env/events/issue_comment_created.json src/tests/mocks/env/events/issue_comment_edited.json src/tests/mocks/env/events/pull_request_opened.json src/tests/mocks/env/events/pull_request_reopened.json src/tests/mocks/env/events/pull_request_synchronize.json src/tests/mocks/env/events/push.json src/tests/mocks/env/events/push_merge.json src/tests/mocks/env/events/schedule.json src/tests/mocks/env/index.test.ts src/tests/mocks/env/index.ts src/tests/mocks/fs/index.test.ts src/tests/mocks/fs/index.ts src/tests/mocks/github/index.test.ts src/tests/mocks/github/index.ts src/tests/mocks/octokit/endpoint/merge.test.ts src/tests/mocks/octokit/endpoint/merge.ts src/tests/mocks/octokit/index.test.ts src/tests/mocks/octokit/index.ts src/tests/mocks/octokit/paginate.test.ts src/tests/mocks/octokit/paginate.ts src/tests/mocks/octokit/payloads.ts src/tests/mocks/octokit/pulls/listFiles.test.ts src/tests/mocks/octokit/pulls/listFiles.ts src/tests/mocks/octokit/repos/compareCommits.test.ts src/tests/mocks/octokit/repos/compareCommits.ts src/tests/payloads.ts src/typings/ActionError/index.d.ts src/typings/ChangedFiles/index.d.ts src/typings/CoreMock/index.d.ts src/typings/FsMock/index.d.ts src/typings/GitHubFile/index.d.ts src/typings/GitHubMock/index.d.ts src/typings/Inferred/index.d.ts src/typings/Inputs/index.d.ts src/typings/OctokitMock/index.d.ts src/typings/TestInput/index.d.ts tsconfig.build.json

View File

@@ -0,0 +1,54 @@
[
".codecov.yml",
".eslintrc.yml",
".prettierrc.yml",
".releaserc.yml",
"src/FilesHelper.ts",
"src/GithubHelper.ts",
"src/InputHelper.ts",
"src/UtilsHelper.ts",
"src/tests/FilesHelper.test.ts",
"src/tests/GithubHelper.test.ts",
"src/tests/InputHelper.test.ts",
"src/tests/UtilsHelper.test.ts",
"src/tests/main.test.ts",
"src/tests/mocks/core/index.test.ts",
"src/tests/mocks/core/index.ts",
"src/tests/mocks/env/events/issue_comment_created.json",
"src/tests/mocks/env/events/issue_comment_edited.json",
"src/tests/mocks/env/events/pull_request_opened.json",
"src/tests/mocks/env/events/pull_request_reopened.json",
"src/tests/mocks/env/events/pull_request_synchronize.json",
"src/tests/mocks/env/events/push.json",
"src/tests/mocks/env/events/push_merge.json",
"src/tests/mocks/env/events/schedule.json",
"src/tests/mocks/env/index.test.ts",
"src/tests/mocks/env/index.ts",
"src/tests/mocks/fs/index.test.ts",
"src/tests/mocks/fs/index.ts",
"src/tests/mocks/github/index.test.ts",
"src/tests/mocks/github/index.ts",
"src/tests/mocks/octokit/endpoint/merge.test.ts",
"src/tests/mocks/octokit/endpoint/merge.ts",
"src/tests/mocks/octokit/index.test.ts",
"src/tests/mocks/octokit/index.ts",
"src/tests/mocks/octokit/paginate.test.ts",
"src/tests/mocks/octokit/paginate.ts",
"src/tests/mocks/octokit/payloads.ts",
"src/tests/mocks/octokit/pulls/listFiles.test.ts",
"src/tests/mocks/octokit/pulls/listFiles.ts",
"src/tests/mocks/octokit/repos/compareCommits.test.ts",
"src/tests/mocks/octokit/repos/compareCommits.ts",
"src/tests/payloads.ts",
"src/typings/ActionError/index.d.ts",
"src/typings/ChangedFiles/index.d.ts",
"src/typings/CoreMock/index.d.ts",
"src/typings/FsMock/index.d.ts",
"src/typings/GitHubFile/index.d.ts",
"src/typings/GitHubMock/index.d.ts",
"src/typings/Inferred/index.d.ts",
"src/typings/Inputs/index.d.ts",
"src/typings/OctokitMock/index.d.ts",
"src/typings/TestInput/index.d.ts",
"tsconfig.build.json"
]

View File

@@ -0,0 +1 @@
.codecov.yml .eslintrc.yml .prettierrc.yml .releaserc.yml src/FilesHelper.ts src/GithubHelper.ts src/InputHelper.ts src/UtilsHelper.ts src/tests/FilesHelper.test.ts src/tests/GithubHelper.test.ts src/tests/InputHelper.test.ts src/tests/UtilsHelper.test.ts src/tests/main.test.ts src/tests/mocks/core/index.test.ts src/tests/mocks/core/index.ts src/tests/mocks/env/events/issue_comment_created.json src/tests/mocks/env/events/issue_comment_edited.json src/tests/mocks/env/events/pull_request_opened.json src/tests/mocks/env/events/pull_request_reopened.json src/tests/mocks/env/events/pull_request_synchronize.json src/tests/mocks/env/events/push.json src/tests/mocks/env/events/push_merge.json src/tests/mocks/env/events/schedule.json src/tests/mocks/env/index.test.ts src/tests/mocks/env/index.ts src/tests/mocks/fs/index.test.ts src/tests/mocks/fs/index.ts src/tests/mocks/github/index.test.ts src/tests/mocks/github/index.ts src/tests/mocks/octokit/endpoint/merge.test.ts src/tests/mocks/octokit/endpoint/merge.ts src/tests/mocks/octokit/index.test.ts src/tests/mocks/octokit/index.ts src/tests/mocks/octokit/paginate.test.ts src/tests/mocks/octokit/paginate.ts src/tests/mocks/octokit/payloads.ts src/tests/mocks/octokit/pulls/listFiles.test.ts src/tests/mocks/octokit/pulls/listFiles.ts src/tests/mocks/octokit/repos/compareCommits.test.ts src/tests/mocks/octokit/repos/compareCommits.ts src/tests/payloads.ts src/typings/ActionError/index.d.ts src/typings/ChangedFiles/index.d.ts src/typings/CoreMock/index.d.ts src/typings/FsMock/index.d.ts src/typings/GitHubFile/index.d.ts src/typings/GitHubMock/index.d.ts src/typings/Inferred/index.d.ts src/typings/Inputs/index.d.ts src/typings/OctokitMock/index.d.ts src/typings/TestInput/index.d.ts tsconfig.build.json

View File

@@ -0,0 +1 @@
.github/workflows/integration.yml,.github/workflows/pr.yml,.github/workflows/push.yml,.github/workflows/readme.md,.gitignore,.prettierignore,README.md,action.yml,jest.config.js,package.json,src/main.ts,tsconfig.json,yarn.lock
1 .github/workflows/integration.yml .github/workflows/pr.yml .github/workflows/push.yml .github/workflows/readme.md .gitignore .prettierignore README.md action.yml jest.config.js package.json src/main.ts tsconfig.json yarn.lock

View File

@@ -0,0 +1,15 @@
[
".github/workflows/integration.yml",
".github/workflows/pr.yml",
".github/workflows/push.yml",
".github/workflows/readme.md",
".gitignore",
".prettierignore",
"README.md",
"action.yml",
"jest.config.js",
"package.json",
"src/main.ts",
"tsconfig.json",
"yarn.lock"
]

View File

@@ -0,0 +1 @@
.github/workflows/integration.yml .github/workflows/pr.yml .github/workflows/push.yml .github/workflows/readme.md .gitignore .prettierignore README.md action.yml jest.config.js package.json src/main.ts tsconfig.json yarn.lock

View File

@@ -0,0 +1 @@
.eslintignore,.eslintrc.json,.prettierrc.json,Makefile,__tests__/main.test.ts,dist/index.js,src/ChangedFiles.ts,src/File.ts
1 .eslintignore .eslintrc.json .prettierrc.json Makefile __tests__/main.test.ts dist/index.js src/ChangedFiles.ts src/File.ts

View File

@@ -0,0 +1,10 @@
[
".eslintignore",
".eslintrc.json",
".prettierrc.json",
"Makefile",
"__tests__/main.test.ts",
"dist/index.js",
"src/ChangedFiles.ts",
"src/File.ts"
]

View File

@@ -0,0 +1 @@
.eslintignore .eslintrc.json .prettierrc.json Makefile __tests__/main.test.ts dist/index.js src/ChangedFiles.ts src/File.ts

View File

@@ -0,0 +1,157 @@
json_output='["functions/twitch-sadako/webhookSubscribeLambda/test/webhookSubscribeLambda.json", "functions/twitch-sadako/webhookSubscribeLambda/test/webhookSubscribeLambda_post.json", "functions/twitch-sadako/webhookSubscribeLambda/test/webhookSubscribeLambda_post.json", "functions/twitch-sadako/webhookSubscribeLambda/test/webhookSubscribeLambda_post.json"]'
csv_output="functions/twitch-sadako/webhookSubscribeLambda/test/webhookSubscribeLambda.json,functions/twitch-sadako/webhookSubscribeLambda/test/webhookSubscribeLambda_post.json,functions/twitch-sadako/webhookSubscribeLambda/test/webhookSubscribeLambda_post.json,functions/twitch-sadako/webhookSubscribeLambda/test/webhookSubscribeLambda_post.json"
txt_hard_output='functions/twitch-sadako/webhookSubscribeLambda/test/webhookSubscribeLambda.json_<br />&nbsp;&nbsp;_functions/twitch-sadako/webhookSubscribeLambda/test/webhookSubscribeLambda_post.json_<br />&nbsp;&nbsp;_functions/twitch-sadako/webhookSubscribeLambda/test/webhookSubscribeLambda_post.json_<br />&nbsp;&nbsp;_functions/twitch-sadako/webhookSubscribeLambda/test/webhookSubscribeLambda_post.json'
txt_output='functions/twitch-sadako/webhookSubscribeLambda/test/webhookSubscribeLambda.json functions/twitch-sadako/webhookSubscribeLambda/test/webhookSubscribeLambda_post.json functions/twitch-sadako/webhookSubscribeLambda/test/webhookSubscribeLambda_post.json functions/twitch-sadako/webhookSubscribeLambda/test/webhookSubscribeLambda_post.json'
testOutput () {
# read from var
if [ "${2}" == "json" ]; then
local output_length=$(echo "${1}" | jq '. | length')
elif [ "${2}" == "," ]; then
local output_length=$(awk -F"${2}" '{print NF-1}' <<< $(echo "${1}"))
else
local output_length=$(awk -F"${2}" '{print NF-1}' <<< $(echo "${1}"))
fi
echo "$output_length"
}
testFile () {
# read from file
if [ "${2}" == "json" ]; then
local file_length=$(jq -r '. | length' ${file}.json)
elif [ "${2}" == "," ]; then
local file_length=$(cat ${file}.csv | awk -F"${2}" '{print NF-1}')
else
local file_length=$(cat ${file}.txt | awk -F"${2}" '{print NF-1}')
fi
echo "$file_length"
}
cleanTest () {
rm -rf $1.json $1.csv $1.txt
}
prepareTest () {
# if prefix is simple setup test var and file
if [ "$1" == "simple_" ]; then
# declare a var named simple_FILE
if [ "$dev" == "dev" ]; then
local file_prefix="events/"
else
local file_prefix=""
fi
declare -n file=${1}${2}
if [ "$3" == "json" ]; then
echo ${json_output} > "${file_prefix}${!file}.json"
elif [ "$3" == "," ]; then
echo ${csv_output} > "${file_prefix}${!file}.csv"
elif [ "$3" == "_<br />&nbsp;&nbsp;_" ]; then
echo ${txt_hard_output} > "${file_prefix}${!file}.txt"
else
echo ${txt_output} > "${file_prefix}${!file}.txt"
fi
if [ "$4" == "json" ]; then
file=$json_output
elif [ "$4" == "," ]; then
file=$csv_output
elif [ "$4" == "_<br />&nbsp;&nbsp;_" ]; then
file=$txt_hard_output
else
file=$txt_output
fi
else
declare -n file=${2}
if [ "$dev" == "dev" ]; then
if [ "$4" == "json" ]; then
file="$(cat events/${!file}.json)"
elif [ "$4" == "," ]; then
file="$(cat events/${!file}.csv)"
else
file="$(cat events/${!file}.txt)"
fi
fi
fi
echo "${file}"
}
testResults () {
if [ "$1" == 'simple_' ]; then
expected=3
if [ "$2" == 'json' ]; then
expected=$(($expected+1))
fi
# echo $result
if [ "$3" != "$expected" ]; then
echo -e "\t\033[1;91mTest failure $5/($1)$4:'$2' { EXPECTED:$expected RECEIVED:$3 } \033[0m"
exit 1;
fi
else
if [ "$4" == 'files' ]; then
expected=72
elif [ "$4" == 'files_added' ]; then
expected=51
elif [ "$4" == 'files_modified' ]; then
expected=12
elif [ "$4" == 'files_removed' ]; then
expected=7
fi
if [ "$2" == 'json' ]; then
expected=$(($expected+1))
fi
if [ "$3" != "$expected" ]; then
echo -e "\t\033[1;91mTest failure $5/($1)$4:'$2' { EXPECTED:$expected RECEIVED:$3 } \033[0m"
exit 1;
fi
fi
echo -e "\t\033[1;92mTest success $5/($1)$4:'$2' { $expected == $3 } \033[0m"
}
runTest () {
for prefix in "simple_" "real"; do \
file=${1}
if [ "$prefix" == 'simple_' ]; then
if [ "$dev" == "dev" ]; then
file=events/${prefix}${1}
else
file=${prefix}${1}
fi
elif [ "$prefix" != 'simple_' ] && [ "$dev" == "dev" ]; then
file=events/${1}
fi
input="$(prepareTest $prefix $1 "$2" "$3")"
local file_length=$(testFile $file "${2}")
local output_length=$(testOutput "${input}" "${3}")
testResults $prefix "${2}" "$file_length" "$1" "fileOutput"
testResults $prefix "${3}" "$output_length" "$1" "output"
if [ "$prefix" == 'simple_' ]; then
cleanTest $file
fi
done
}
test () {
if [ "$dev" == "dev" ]; then
echo -e "\t\033[1;91mDEV MODE\033[0m"
fi
if [ "$output" == "" ] || [ "$fileOutput" == "" ]; then
for fileOutput in "json" "," " "; do \
echo -e "\033[1;92mFILEOUTPUT:'$fileOutput'\033[0m"
for output in "json" "," " "; do \
echo -e "\033[1;92mOUTPUT:'$output'\033[0m"
for file in "files" "files_modified" "files_added" "files_removed"; do \
echo -e "\033[1;92mFILE:'$file'\033[0m"
runTest $file "$fileOutput" "$output"
done
done
done
else
for file in "files" "files_modified" "files_added" "files_removed"; do \
echo -e "\033[1;92mFILE:'$file' with FILEOUTPUT:'$fileOutput' OUTPUT:'$output'\033[0m"
runTest $file "$fileOutput" "$output"
done
fi
}
dev=$1
test

View File

@@ -0,0 +1,26 @@
# Set to true to add reviewers to pull requests
addReviewers: true
# Set to true to add assignees to pull requests
addAssignees: author
# A list of reviewers to be added to pull requests (GitHub user name)
reviewers:
- trilom
# A number of reviewers added to the pull request
# Set 0 to add all the reviewers (default: 0)
numberOfReviewers: 0
# A list of assignees, overrides reviewers if set
# assignees:
# - assigneeA
# A number of assignees to add to the pull request
# Set to 0 to add all of the assignees.
# Uses numberOfReviewers if unset.
# numberOfAssignees: 2
# A list of keywords to be skipped the process that add reviewers if pull requests include it
# skipKeywords:
# - wip

View File

@@ -0,0 +1,42 @@
- name: pretty
description: Code that has been linted with eslint and prettier
color: 76edd1
- name: builds
description: Code that builds with yarn and tsc
color: 39bc44
- name: tested-unit
description: Code that has passed unit tests with jest
color: 9520bc
- name: tested-integration
description: Code that has passed integration tests with jest
color: fc5aee
- name: "doesnt read directions"
description: "Doesn't know how to read directions, please PR to develop"
color: d876e3
- name: automated pr
description: This was created by create-pull-request action
color: b9ff9b
- name: released
description: This has been released to NPM, Github Packages, and Actions Marketplace
color: ededed
- name: bug
description: Something isn't working
color: d73a4a
- name: duplicate
description: This issue or pull request already exists
color: cfd3d7
- name: enhancement
description: New feature or request
color: a2eeef
- name: "automated merge"
description: This was merged automatically
color: c2e0c6
- name: "hold merge"
description: This merge will be blocked from automerging until this label is removed
color: b60205
- name: lintdogged
description: Code that has been looked at by reviewdog
color: 5F422D
- name: failure
description: Something bad happened...
color: d93f0b

View File

@@ -0,0 +1,97 @@
# this will tag PRs that are ready for release and automerge them
name: Automerge Pull Requests
on:
# issue_comment:
# types: [created]
pull_request:
branches: [master, next, alpha, beta]
types: [labeled, closed]
jobs:
automerge:
name: automerge pr
runs-on: ubuntu-latest
env:
GITHUB_TOKEN: ${{ secrets.TRILOM_BOT_TOKEN }}
pr_number: ${{ format('{0}{1}', github.event.pull_request.number, github.event.issue.number) }}
# if event type is non fork PR or comment on PR from trilom with '/release'
if: >-
(
github.event_name == 'pull_request'
&& github.event.pull_request.head.repo.full_name == github.repository
&& contains(github.event.pull_request.labels.*.name, 'pretty')
&& contains(github.event.pull_request.labels.*.name, 'builds')
&& contains(github.event.pull_request.labels.*.name, 'tested-unit')
&& contains(github.event.pull_request.labels.*.name, 'tested-integration')
&& contains(github.event.pull_request.labels.*.name, 'lintdogged')
&& ! contains(github.event.pull_request.labels.*.name, 'automated merge')
&& ! contains(github.event.pull_request.labels.*.name, 'hold merge')
) || (
github.event_name == 'issue_comment'
&& github.event.issue.pull_request != ''
&& contains(github.event.comment.body, '/release')
&& github.actor == 'trilom'
&& contains(github.event.issue.labels.*.name, 'pretty')
&& contains(github.event.issue.labels.*.name, 'builds')
&& contains(github.event.issue.labels.*.name, 'tested-unit')
&& contains(github.event.issue.labels.*.name, 'tested-integration')
&& contains(github.event.issue.labels.*.name, 'lintdogged')
&& ! contains(github.event.issue.labels.*.name, 'automated merge')
&& ! contains(github.event.issue.labels.*.name, 'hold merge'))
steps:
- name: if pretty, builds, tested merge automerge pr
# if pretty, builds, and tested labels then merge
uses: pascalgn/automerge-action@v0.7.5
env:
GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }}
MERGE_METHOD: merge
# this breaks the /release on issue_comment portion unless I get the head.ref from github-script
MERGE_COMMIT_MESSAGE: 'Auto merge from ${{ github.event.pull_request.head.ref }} PR#{pullRequest.number}: {pullRequest.title}'
UPDATE_METHOD: merge
MERGE_LABELS: 'pretty,builds,tested-unit,tested-integration,lintdogged'
UPDATE_LABELS: ''
# if failure, get payload of PR and notify
- name: if failure, get pr payload
uses: actions/github-script@0.8.0
id: pr_json
if: failure()
with:
github-token: ${{env.GITHUB_TOKEN}}
script: |
const result = await github.pulls.get({
owner: '${{ github.repository }}'.split('/')[0],
repo: '${{ github.repository }}'.split('/')[1],
pull_number: ${{ env.pr_number }}
})
return result.data;
- name: if failure, set pr payload outputs
if: failure()
id: pr
run: |
echo '${{ steps.pr_json.outputs.result }}' > pr.json
echo "::set-output name=user::$( jq -r '.user.login' pr.json )"
echo "::set-output name=head::$( jq -r '.head.repo.full_name' pr.json )"
echo "::set-output name=head_url::$( jq -r '.head.repo.html_url' pr.json )"
echo "::set-output name=base::$( jq -r '.base.repo.full_name' pr.json )"
echo "::set-output name=base_url::$( jq -r '.base.repo.html_url' pr.json )"
- name: if failure, notify
uses: peter-evans/create-or-update-comment@v1
if: failure()
with:
token: ${{ env.GITHUB_TOKEN }}
issue-number: ${{ env.pr_number }}
body: |
@${{ steps.pr.outputs.user }}, @trilom - it appears that there was an issue with the merge.
Head Repo/Branch: **[${{ steps.pr.outputs.head }}]**(${{ steps.pr.outputs.head_url }}) merge into **[${{ steps.pr.outputs.base }}]**(${{ steps.pr.outputs.base_url }})
## Event JSON
```json
${{ toJSON(steps.pr_json.outputs.result)}}
```
- uses: actions/github-script@0.6.0
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
github.issues.addLabels({owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number,
labels: ['automated merge']
})

View File

@@ -0,0 +1,19 @@
name: Close Pull Request
on:
pull_request:
branches-ignore: [master]
types: [opened, reopened]
jobs:
# close any fork PRs not opened by trilom to anything but master
close_pr:
name: close non master PRs from fork
runs-on: ubuntu-latest
if: (github.actor != 'trilom' || github.actor != 'trilom-bot') && github.event.pull_request.head.repo.full_name != github.repository
steps:
- uses: superbrothers/close-pull-request@v2
with:
comment: Please merge your code into master, this will trigger the desired merge workflow.
- uses: actions/github@v1.0.0
if: success()
with:
args: label "doesnt read directions"

View File

@@ -0,0 +1,106 @@
name: Integration Tests
on:
issue_comment:
types:
- created
schedule:
- cron: '0 0 * * *'
pull_request:
branches: [master]
push:
branches: [master]
jobs:
# always_job:
# name: Always run job
# runs-on: ubuntu-latest
# steps:
# - name: dump env
# env:
# GITHUB_CONTEXT: ${{ toJson(github) }}
# JOB_CONTEXT: ${{ toJson(job) }}
# STEPS_CONTEXT: ${{ toJson(steps) }}
# RUNNER_CONTEXT: ${{ toJson(runner) }}
# STRATEGY_CONTEXT: ${{ toJson(strategy) }}
# MATRIX_CONTEXT: ${{ toJson(matrix) }}
# run: |
# echo "GITHUB_EVENT_PATH\n$GITHUB_EVENT_PATH"
# echo "GITHUB_CONTEXT\n$GITHUB_CONTEXT"
# echo "JOB_CONTEXT\n$JOB_CONTEXT"
# echo "STEPS_CONTEXT\n$STEPS_CONTEXT"
# echo "RUNNER_CONTEXT\n$RUNNER_CONTEXT"
# echo "STRATEGY_CONTEXT\n$STRATEGY_CONTEXT"
# echo "MATRIX_CONTEXT\n$MATRIX_CONTEXT"
integration:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
event_type: ['push', 'pull_request']
output: ['json', ',', ' ', '_<br />&nbsp;&nbsp;_']
fileOutput: ['json', ',', ' ', '_<br />&nbsp;&nbsp;_']
if: >-
( startsWith(github.head_ref, '1.')
|| startsWith(github.head_ref, '2.'))
||
contains(github.event.head_commit.message, 'Release merge from')
||
github.event_name == 'schedule'
|| (
github.event_name == 'issue_comment'
&& github.event.issue.number != ''
&& contains(github.event.comment.body, '/integration')
&& github.actor == 'trilom')
steps:
# get pr number if exists
- id: pr
if: github.event_name == 'issue_comment'
run: |
pr=$(echo "${{github.event.comment.body}}" | sed 's|.*/integration||') &&
echo "::set-output name=pr::${pr}"
env:
comment: ${{ toJson(github) }}
# use pr number from integration command
- uses: actions/checkout@v2
if: github.event_name == 'issue_comment' && steps.pr.outputs.pr != ''
with:
ref: ${{format('refs/pull/{0}/head', steps.pr.outputs.pr )}}
# use the issue number if pr is blank
- uses: actions/checkout@v2
if: github.event_name == 'issue_comment' && steps.pr.outputs.pr == '' && github.event.issue.pull_request != ''
with:
ref: ${{format('refs/pull/{0}/head', github.event.issue.number )}}
- name: fail if no PR number and issue comment
if: github.event_name == 'issue_comment' && steps.pr.outputs.pr == '' && github.event.issue.pull_request == ''
run: |
echo "Please provide a PR number to use like /integration13 for PR# 13."
exit 1
- uses: actions/checkout@v2
if: github.event_name != 'issue_comment'
- run: yarn build-package
- uses: ./
id: file_changes_build_pr
if: matrix.event_type == 'pull_request'
with:
prNumber: 83
output: ${{ matrix.output }}
fileOutput: ${{ matrix.fileOutput }}
- uses: ./
id: file_changes_build_push
if: matrix.event_type == 'push'
with:
pushBefore: 6ac7697cd1c4f23a08d4d4edbe7dab06b34c58a2
pushAfter: 4ee1a1a2515f4ac1b90a56aaeb060b97f20c8968
output: ${{ matrix.output }}
fileOutput: ${{ matrix.fileOutput }}
- run: |
mv $HOME/files* .
chmod +x test.sh && ./test.sh
working-directory: .github/actions/integration
if: success()
env:
fileOutput: ${{ matrix.fileOutput }}
output: ${{ matrix.output }}
files: ${{ format('{0}{1}', steps.file_changes_build_pr.outputs.files, steps.file_changes_build_push.outputs.files ) }}
files_modified: ${{ format('{0}{1}', steps.file_changes_build_pr.outputs.files_modified, steps.file_changes_build_push.outputs.files_modified ) }}
files_added: ${{ format('{0}{1}', steps.file_changes_build_pr.outputs.files_added, steps.file_changes_build_push.outputs.files_added ) }}
files_removed: ${{ format('{0}{1}', steps.file_changes_build_pr.outputs.files_removed, steps.file_changes_build_push.outputs.files_removed ) }}

View File

@@ -0,0 +1,13 @@
name: Sync labels
on:
push:
branches: [master]
paths: [.github/labels.yml]
jobs:
make-labels:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: micnncim/action-label-syncer@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -0,0 +1,192 @@
name: Contribution Workflow
env:
isFork: ${{ github.event.pull_request.head.repo.full_name != github.repository }}
on: [pull_request]
jobs:
add-reviews:
runs-on: ubuntu-latest
steps:
- uses: kentaro-m/auto-assign-action@v1.1.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
# make sure we can build
build:
name: yarn install && tsc
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: yarn build
- uses: actions/github-script@0.6.0
if: failure() && contains(env.isFork, 'false')
with:
github-token: ${{ secrets.TRILOM_BOT_TOKEN }}
script: |
if ('${{ contains(github.event.pull_request.labels.*.name, 'builds') }}' == 'true') {
github.issues.removeLabel({owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number,
name: 'builds'
})
}
- uses: actions/github-script@0.6.0
if: contains(env.isFork, 'false')
with:
github-token: ${{ secrets.TRILOM_BOT_TOKEN }}
script: |
github.issues.addLabels({owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number,
labels: ['builds']
})
# unit test with jest
test-unit:
name: jest unit tests
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v2
- run: yarn build
- run: yarn test-coverage
- run: bash <(curl -s https://codecov.io/bash)
if: contains(env.isFork, 'false')
- uses: actions/github-script@0.6.0
if: failure() && contains(env.isFork, 'false')
with:
github-token: ${{ secrets.TRILOM_BOT_TOKEN }}
script: |
if ('${{ contains(github.event.pull_request.labels.*.name, 'tested-unit') }}' == 'true') {
github.issues.removeLabel({owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number,
name: 'tested-unit'
})
}
- uses: actions/github-script@0.6.0
if: contains(env.isFork, 'false')
with:
github-token: ${{ secrets.TRILOM_BOT_TOKEN }}
script: |
github.issues.addLabels({owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number,
labels: ['tested-unit']
})
# integration test with jest
test-integration:
name: jest integration tests
runs-on: ubuntu-latest
needs: test-unit
steps:
- uses: actions/checkout@v2
- run: yarn build
- run: yarn test-integration
env:
GITHUB_TOKEN: ${{ secrets.TRILOM_BOT_TOKEN }}
- uses: actions/github-script@0.6.0
if: failure() && contains(env.isFork, 'false')
with:
github-token: ${{ secrets.TRILOM_BOT_TOKEN }}
script: |
if ('${{ contains(github.event.pull_request.labels.*.name, 'tested-integration') }}' == 'true') {
github.issues.removeLabel({owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number,
name: 'tested-integration'
})
}
- uses: actions/github-script@0.6.0
if: contains(env.isFork, 'false')
with:
github-token: ${{ secrets.TRILOM_BOT_TOKEN }}
script: |
github.issues.addLabels({owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number,
labels: ['tested-integration']
})
# lint code in github check
lintdog-fork:
name: eslintdog (reviewdog)
runs-on: ubuntu-latest
needs: build
if: github.event.pull_request.head.repo.full_name != github.repository
steps:
- uses: actions/checkout@v2
- run: yarn build
- name: Lint and report
uses: reviewdog/action-eslint@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
reporter: github-check
eslint_flags: '--ext .ts ./'
# lint code and comment back if possible
lintdog:
name: eslintdog (reviewdog)
runs-on: ubuntu-latest
needs: build
if: github.event.pull_request.head.repo.full_name == github.repository
steps:
- uses: actions/checkout@v2
- run: yarn build
- name: Lint and report
uses: reviewdog/action-eslint@v1
with:
github_token: ${{ secrets.TRILOM_BOT_TOKEN }}
reporter: github-pr-review
eslint_flags: '--ext .ts ./'
- uses: actions/github-script@0.6.0
if: failure()
with:
github-token: ${{ secrets.TRILOM_BOT_TOKEN }}
script: |
if ('${{ contains(github.event.pull_request.labels.*.name, 'lintdogged') }}' == 'true') {
github.issues.removeLabel({owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number,
name: 'lintdogged'
})
}
- uses: actions/github-script@0.6.0
with:
github-token: ${{ secrets.TRILOM_BOT_TOKEN }}
script: |
github.issues.addLabels({owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number,
labels: ['lintdogged']
})
# format and push code back if not forked branch
format_check_push:
name: prettier
runs-on: ubuntu-latest
needs: [lintdog, lintdog-fork]
if: always()
env:
GITHUB_TOKEN: ${{ secrets.TRILOM_BOT_TOKEN }}
steps:
- uses: actions/checkout@v2 # checkout for forks
if: contains(env.isFork, 'true')
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@v2 # checkout for PR
if: contains(env.isFork, 'false')
with:
token: ${{ secrets.TRILOM_BOT_TOKEN }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.event.pull_request.head.ref }}
- run: yarn build
- run: yarn format-check
- name: yarn format and push code if check failed
if: failure() && github.actor != 'trilom-bot' && contains(env.isFork, 'false')
env:
GITHUB_TOKEN: ${{ secrets.TRILOM_BOT_TOKEN }}
run: |
yarn format
sudo yarn clean
git config --local user.email "trilom-bot@trailmix.me"
git config --local user.name "trilom-bot"
git add -A
git diff-index --quiet HEAD || git commit -m "Adding format changes 🤖" -a
git push https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.git HEAD:refs/heads/${{ github.head_ref }} && exit 0
- uses: actions/github-script@0.6.0
if: failure() && contains(env.isFork, 'false')
with:
github-token: ${{ secrets.TRILOM_BOT_TOKEN }}
script: |
if ('${{ contains(github.event.pull_request.labels.*.name, 'pretty') }}' == 'true') {
github.issues.removeLabel({owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number,
name: 'pretty'
})
}
- uses: actions/github-script@0.6.0
if: contains(env.isFork, 'false')
with:
github-token: ${{ secrets.TRILOM_BOT_TOKEN }}
script: |
github.issues.addLabels({owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number,
labels: ['pretty']
})

View File

@@ -0,0 +1,259 @@
# if a push comes in then this will test it for a release and create a release PR if needed
name: Push to release branches
on:
push:
branches: [master, next, alpha, beta]
tags-ignore: ['**']
jobs:
# semantic release an auto-merged branch to github package repo, npm, github actions
release:
name: Release to NPM, Github, Github Actions Marketplace
runs-on: ubuntu-latest
needs: [build, test-unit, test-integration, lintdog]
if: >
github.actor != 'semantic-release-bot'
&& ( (contains(github.event.head_commit.message, 'trilom/1.')
|| contains(github.event.head_commit.message, 'trilom/2.'))
&& ! contains(github.event.head_commit.message, 'chore(release):'))
env:
GITHUB_TOKEN: ${{ secrets.TRILOM_BOT_TOKEN }}
SEMANTIC_RELEASE_PACKAGE: '@${{ github.repository }}'
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: semantic-release
uses: cycjimmy/semantic-release-action@v2
id: semantic
with:
semantic_version: 15.14.0
extra_plugins: |
@semantic-release/git@7.0.18
@semantic-release/changelog
semantic-release-slack-bot
dry_run: false
- name: echo release outputs
if: steps.semantic.outputs.new_release_published == 'true'
run: |
echo ${{ steps.semantic.outputs.new_release_version }}
echo ${{ steps.semantic.outputs.new_release_major_version }}
echo ${{ steps.semantic.outputs.new_release_minor_version }}
echo ${{ steps.semantic.outputs.new_release_patch_version }}
- name: Setup Node.js with GitHub Package Registry
if: steps.semantic.outputs.new_release_published == 'true'
uses: actions/setup-node@v1
with:
node-version: 12
registry-url: 'https://npm.pkg.github.com'
scope: trilom
- name: Publish To GitHub Package Registry
if: steps.semantic.outputs.new_release_published == 'true'
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ env.GITHUB_TOKEN }}
# create PR from release branch to master to prepare for release
check-release:
name: Check if we need to release
runs-on: ubuntu-latest
needs: [build, test-unit, test-integration, lintdog]
if: >
github.actor != 'semantic-release-bot'
&& ! contains(github.event.head_commit.message, 'trilom/1.')
&& ! contains(github.event.head_commit.message, 'trilom/2.')
&& ! contains(github.event.head_commit.message, 'chore(release):')
env:
GITHUB_TOKEN: ${{ secrets.TRILOM_BOT_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: commit format changes and create authors file
run: |
git config --local user.email "trilom-bot@trailmix.me"
git config --local user.name "trilom-bot"
yarn build
yarn format
git add -A
git diff-index --quiet HEAD || git commit -m "Adding format changes 🤖" -a
yarn build-release
git add -A
git diff-index --quiet HEAD || git commit -m "Adding release changes ⚙️" -a
git log --format='%aN <%aE>%n%cN <%cE>' | sort -u > AUTHORS
sed -i '/trilom-bot/d' AUTHORS
sed -i '/semantic-release-bot/d' AUTHORS
sed -i '/carnoco@gmail.com/d' AUTHORS
sed -i '/GitHub <noreply@github.com>/d' AUTHORS
sed -i '/dependabot/d' AUTHORS
echo -e "\r\n$(date)" >> AUTHORS
git add -A
git diff-index --quiet HEAD || git commit -m "Updating AUTHORS 📓" -a
# see if we need to release, if so create a automerge release PR and notify the original creator
- name: semantic-release
uses: cycjimmy/semantic-release-action@v2
id: semantic
env:
SEMANTIC_RELEASE_PACKAGE: '@${{ github.repository }}'
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
with:
semantic_version: 15.14.0
extra_plugins: |
@semantic-release/git@7.0.18
@semantic-release/changelog
semantic-release-slack-bot
dry_run: true
- name: echo release outputs
if: steps.semantic.outputs.new_release_published == 'true'
run: |
echo ${{ steps.semantic.outputs.new_release_version }}
echo ${{ steps.semantic.outputs.new_release_major_version }}
echo ${{ steps.semantic.outputs.new_release_minor_version }}
echo ${{ steps.semantic.outputs.new_release_patch_version }}
- name: push potential formatting changes since there is no release
if: steps.semantic.outputs.new_release_published == 'false'
run: |
git config --local user.email "trilom-bot@trailmix.me"
git config --local user.name "trilom-bot"
git push -f https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git HEAD:${{ github.ref }}
- name: get changed files and format for automerge PR body
id: file_changes
uses: trilom/file-changes-action@master
if: steps.semantic.outputs.new_release_published == 'true'
with:
githubToken: ${{ env.GITHUB_TOKEN }}
output: '_<br />&nbsp;&nbsp;_'
- name: get original PR number
uses: actions/github-script@0.6.0
id: pr
if: steps.semantic.outputs.new_release_published == 'true'
with:
github-token: ${{env.GITHUB_TOKEN}}
result-encoding: string
script: |
const result = await github.repos.listPullRequestsAssociatedWithCommit({
owner: context.payload.repository.owner.name,
repo: context.payload.repository.name,
commit_sha: context.payload.head_commit.id
})
if (result.data.length >= 1) {
return result.data[0].number
} else return 87
- name: get original PR user
uses: actions/github-script@0.6.0
id: login
if: steps.pr.outputs.result != 0 && steps.semantic.outputs.new_release_published == 'true'
with:
github-token: ${{env.GITHUB_TOKEN}}
result-encoding: string
script: |
const result = await github.pulls.get({
owner: context.payload.repository.owner.name,
repo: context.payload.repository.name,
pull_number: ${{ steps.pr.outputs.result }}
})
if (result.data.user === true && result.data.user.login === true) {
return result.data.user.login
} else return 'trilom';
- name: create release PR
id: create-pr
uses: peter-evans/create-pull-request@v2
if: steps.semantic.outputs.new_release_published == 'true'
with:
token: ${{ env.GITHUB_TOKEN }}
commit-message: '${{ github.event.head_commit.message }}'
committer: trilom-bot <trilom-bot@trailmix.me>
author: ${{ steps.login.outputs.result }} <${{ steps.login.outputs.result }}@users.noreply.github.com>
title: 'releases/v${{ steps.semantic.outputs.new_release_version }} [@${{ steps.login.outputs.result }}] - ${{ github.event.head_commit.message }}'
body: |
# @${{ steps.login.outputs.result }} would like to merge into file-changes-action
[**compare link**](${{ github.event.compare }})
## Commits
```json
${{ toJSON(github.event.commits)}}
```
## Files
&nbsp;&nbsp;_${{ steps.file_changes.outputs.files}}_
## Files modified
&nbsp;&nbsp;_${{ steps.file_changes.outputs.files_modified}}_
## Files added
&nbsp;&nbsp;_${{ steps.file_changes.outputs.files_added}}_
## Files removed
&nbsp;&nbsp;_${{ steps.file_changes.outputs.files_removed}}_
labels: 'automated pr'
assignees: '${{ steps.login.outputs.result }},trilom'
reviewers: trilom
branch: '${{ steps.semantic.outputs.new_release_version }}'
- name: notify initial commiter of change
uses: peter-evans/create-or-update-comment@v1
if: steps.login.outputs.result != '' && steps.semantic.outputs.new_release_published == 'true'
with:
token: ${{ env.GITHUB_TOKEN }}
issue-number: ${{ steps.pr.outputs.result }}
body: |
Hey @${{ steps.login.outputs.result }},
This merge has triggered a release, hurray!
[Here you can follow the release.](https://github.com/trilom/file-changes-action/pull/${{ steps.create-pr.outputs.pr_number }})
Please use this new **Pull Request** if there are any issues to communicate further.
Thanks!
# - uses: actions/github-script@0.6.0
# if: steps.create-pr.outputs.pr_number != '' && steps.semantic.outputs.new_release_published == 'true'
# with:
# github-token: ${{ secrets.TRILOM_BOT_TOKEN }}
# script: |
# github.issues.addLabels({owner: context.repo.owner, repo: context.repo.repo, issue_number: ${{ steps.create-pr.outputs.pr_number }},
# labels: ['${{ steps.semantic.outputs.new_release_version }}']
# })
# make sure we can build
build:
name: yarn install && tsc
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: yarn build
# unit test with jest
test-unit:
name: jest unit tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: yarn build
- run: yarn test-coverage
- run: bash <(curl -s https://codecov.io/bash)
# integration test with jest
test-integration:
name: jest integration tests
needs: test-unit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: yarn build
- run: yarn test-integration
env:
GITHUB_TOKEN: ${{ secrets.TRILOM_BOT_TOKEN }}
# lint code and comment back if possible
lintdog:
name: eslintdog (reviewdog)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Lint and report push
uses: reviewdog/action-eslint@v1
with:
github_token: ${{ secrets.TRILOM_BOT_TOKEN }}
reporter: github-check
eslint_flags: 'src/**/*.ts'

View File

@@ -0,0 +1,86 @@
# Workflow Information
- [Workflow Information](#workflow-information)
- [Overview](#overview)
- [Schedule](#schedule)
- [Issue Comment](#issue-comment)
- [Pull Request](#pull-request)
- [Push](#push)
# Overview
1. Make a **Pull Request** from your forked branch (forked from _master_) with changes to _trilom/file-changes-action/master_ branch.
2. Once merged into master this will lint the code and provide output in the checks, update the AUTHORS file, and package _dist/_. If there is a release then this will create a **Pull Request** from the _v\*\*_ branch to _master_ and a comment will be made on the original **Pull Request** notifying contributors. If there is not a release the changes will be **push**ed to _master_.
3. In the **Pull Request** linting and testing will be performed again. If _linted_, _tested-unit_, _tested-integration_, _builds_, and _lintdogged_ label exist and _hold merge_ does not the release will be merged into _master_.
4. Once merged this time [semantic-release](https://github.com/semantic-release/semantic-release) will run to create the Github Release, release notes, changelog, notify Slack, package and deploy to NPM and Github Package Repo, label the release, and notify any issues of it's deployment.
5. After user semantic-release-bot commits the release commit, this code will be pushed to the release branch.
## Schedule
- Everyday at 5:00 AM GMT:
- Run integration tests via Github Actions.
## Issue Comment
- When any `created` **Issue Comment** type runs on a **Pull Request** from trilom with the body of `/integrationNUMBER`(**integration.yml**):
- Run integration tests via Github Actions with PR.
- **NOT IMPLEMENTED** When any `created` **Issue Comment** type runs on a **Pull Request** from trilom with the body of `/release`(**automerge.yml**):
- If _linted_, _tested-unit_, _tested-integration_, _builds_, _lintdogged_, and _hold merge_ or _automated merge_ **does not** labels exist:
- Merge the PR and add the _automated merge_ label
- If failure, put some output on the original PR.
## Pull Request
- When any `opened`, `reopened`, or `synchronize` **Pull Request** type runs to the _master_ branch from a _v\*\*_ branch:
- Run integration tests via Github Actions.
- When any `opened` or `reopened` **Pull Request** type runs on any branch other than _master_ from anyone other than trilom or trilom-bot from a forked branch(**close_pr.yml**):
- Close the **Pull Request** and put the dunce cap on.
- When any `labeled`, or `closed` **Pull Request** type runs on _master_, _next_, _alpha_, or _beta_(**automerge.yml**):
- If _linted_, _tested-unit_, _tested-integration_, _builds_, _lintdogged_, and _hold merge_ or _automated merge_ **does not** labels exist:
- Merge the PR and add the _automated merge_ label
- If failure, put some output on the original PR.
- When any `opened`, `reopened`, or `synchronize` **Pull Request** type runs(**pr.yml**):
- Assign it to trilom (**add-reviews**)
- Build code with `yarn build` which runs `yarn` and `tsc` (**build**)
- Label with builds if passing and on inner workspace
- Test code with `yarn test-coverage` which runs `jest --coverage` (**test-unit**)
- Label with tested-unit if passing and on inner workspace
- Test code with `yarn test-integration` which runs `jest -c jest.config.integration.js` (**test-integration**)
- Label with tested-integration if passing and on inner workspace
- Test code with eslint reviewdog and report back if inner workspace (**lintdog**)
- Label with pretty if passing and on inner workspace
- Check format of code with `yarn format-check` which runs `prettier --check` (**format_check_push**)
- If:
- Fork then pull **Pull Request** github.ref with GITHUB_TOKEN
- Inner **Pull Request** then pull HEAD repo ref
- Build code with `yarn build` which runs `yarn` and `tsc`
- If format-check succeeds and on inner workspace
- Label with pretty
- If format-check fails and on inner workspace and actor is not trilom-bot
- Run `yarn format` which runs `prettier --write`
- Clean build files with `yarn clean`
- Commit the format changes as trilom-bot to **Pull Request** head
## Push
- When any **Push** type runs to _master_:
- Run integration tests via Github Actions.
- When any **Push** type runs to _master_, _next_, _alpha_, or _beta_(**push.yml**):
- Build code with `yarn build` which runs `yarn` and `tsc` (**build**)
- Test code with `yarn test-coverage` which runs `jest` (**test**)
- Test code with eslint reviewdog and report back with github checks(**lintdog**)
- When any **Push** type runs to _master_, _next_, _alpha_, or _beta_ with a head_commit message **NOT** containing 'trilom/v1.' or 'trilom/v2.':
- Build with `yarn build-release` which runs `yarn && tsc --build tsconfig.build.json && ncc build --minify` to build the **dist/\*\*.js** files, update **AUTHORS**, format **src/\*\*.ts** files and commit.
- Test [semantic-release](https://github.com/semantic-release/semantic-release) if a release is ready then create a **Pull Request**
- Echo release outputs
- Get changed files with [file-changes-action](https://github.com/trilom/file-changes-action) and build a message to post to new **Pull Request**
- Comment on the original **Pull Request** with the new details of the release.
- If no release, then **Push** changes directly back to master.
- When any **Push** type runs to _master_, _next_, _alpha_, or _beta_ with a head_commit message containing 'trilom/v1.' or 'trilom/v2.':
- Run [semantic-release](https://github.com/semantic-release/semantic-release) to prepare Github Release, release notes, changelog, notify Slack, package and deploy to NPM and Github Package Repo, label the release, and notify any issues of it's deployment.
- When any **Push** type runs to _master_, _next_, _alpha_, or _beta_ from semantic-release-bot with a head_commit message containing 'chore(release):':
- Get the **Pull Request** number from the **Push** and push the semantic-release changes to the tagged release branch.

View File

@@ -0,0 +1,100 @@
lib
**/outputs/**
# Dependency directory
node_modules
# Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
jspm_packages/
# # TypeScript v1 declaration files
# typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# OS metadata
.DS_Store
Thumbs.db
# Ignore built ts files
__tests__/runner/*

View File

@@ -0,0 +1,2 @@
/dist
/node_modules

View File

@@ -0,0 +1,9 @@
printWidth: 80
tabWidth: 2
useTabs: false
semi: false
singleQuote: true
trailingComma: none
bracketSpacing: false
arrowParens: avoid
parser: typescript

View File

@@ -0,0 +1,62 @@
branches:
- "+([1-9])?(.{+([1-9]),x}).x"
- master
- next
- name: alpha
prerelease: true
- name: beta
prerelease: true
dryRun: false
plugins:
- "@semantic-release/commit-analyzer"
- "@semantic-release/release-notes-generator"
-
- semantic-release-slack-bot
- notifyOnSuccess: true
notifyOnFail: true
markdownReleaseNotes: true
onSuccessTemplate:
text: "$package_name version v$npm_package_version!\n\n$release_notes"
-
- "@semantic-release/changelog"
- changelogFile: CHANGELOG.md
- "@semantic-release/npm"
-
- "@semantic-release/github"
- assets:
- path: "dist/**/*.js"
label: Packaged JS Code
successComment: >
# 🎉🦍🎉 This <% issue.pull_request ? 'pull request' : 'issue' %>
has been resolved in version *<%= nextRelease.version %>* at
*trilom/file-changes-action@<%= nextRelease.gitTag %>*
` - name: File Changes Action
uses: trilom/file-changes-action@<%= nextRelease.gitTag %>`
## Release<%= _.size(releases) > 1 ? 's' : '' %>
<% _.forEach(releases, function(release) { %>
\n\t\t**Release Name:** [<%= release.name %>](<%= release.url %>)<% }); %>
\n\n ## Commits<% _.forEach(commits, function(commit) { %>
\n\t\t@<%= commit.author %> - [_<%= commit.message %>_](https://github.com/trilom/file-changes-action/commit/<%= commit.hash %>)<% }); %>"
**Release Name:** [<%= release.name %>](<%= release.url %>)<% }); %>
## Commits
<% _.forEach(commits, function(commit) { %>
@<%= commit.author.name %> - [_<%= commit.message.toString().replace(/[()\\\/_\*]/g, '') %>_](https://github.com/trilom/file-changes-action/commit/<%= commit.hash %>)<% }); %>
labels: [failure]
releasedLabels: ["releases/${nextRelease.gitTag}"]
assignees: trilom
-
- "@semantic-release/git"
- assets: [CHANGELOG.md, package.json, yarn.lock]
message: >
chore(release): 🎉🦍🎉 Release <%= nextRelease.version %> -
<%= new Date().toLocaleDateString('en-US', {year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric' }) %> [skip ci]
`- name: File Changes Action
uses: trilom/file-changes-action@<%= nextRelease.gitTag %>`
<%= nextRelease.notes %>

View File

@@ -0,0 +1,5 @@
Bryan Killian <bryan.v.killian@gmail.com>
Daniel Orner <daniel.orner@wishabi.com>
Sergey Kluchkovsky <kaineer@gmail.com>
Thu May 21 14:42:36 UTC 2020

View File

@@ -0,0 +1,45 @@
## [1.2.4](https://github.com/trilom/file-changes-action/compare/v1.2.3...v1.2.4) (2020-05-21)
### Bug Fixes
* **change in api:** github api had a change, this should trigger release 1.2.4. this change here quiets a quacker during the intergration test ([99f8f91](https://github.com/trilom/file-changes-action/commit/99f8f91f3ed1430713973d8f1e2848b5acc58163))
## [1.2.3](https://github.com/trilom/file-changes-action/compare/v1.2.2...v1.2.3) (2020-03-25)
### Bug Fixes
* **test release:** testing a release ([dfca448](https://github.com/trilom/file-changes-action/commit/dfca448d9d1f04825a549ba0bc7d6b097df295a2))
## [1.2.2](https://github.com/trilom/file-changes-action/compare/v1.2.1...v1.2.2) (2020-03-25)
### Bug Fixes
* **issue_comment:** this needs to return PR info not commit info if before and after explicitly set, else PR ([eee976b](https://github.com/trilom/file-changes-action/commit/eee976b2219f243f83583baab84fa89376006acc))
* **naming:** renamed "deleted" to "removed". sorry if this is breaking for you. ([800537f](https://github.com/trilom/file-changes-action/commit/800537f435a66454c64fc2b42cfd82ca33cc093d))
* **pull_request_synchronize events:** issue with PR Synchronize events, it would return commit files instead of PR files, this is adjusted to return ALL PR files with PR synchronize event ([fb7bcc7](https://github.com/trilom/file-changes-action/commit/fb7bcc76581402f20aa64da82cd1174e313ec02c))
* **space issue:** this should resolve the issue with using a blank space. the assumption here is that 'json' is default, if you use ' ' it will be '' which is the app default, not the action default of 'json' ([0e4184f](https://github.com/trilom/file-changes-action/commit/0e4184fe04f87323c60b71c1ccf2af95f9f35b8c)), closes [#81](https://github.com/trilom/file-changes-action/issues/81)
## [1.2.1](https://github.com/trilom/file-changes-action/compare/v1.2.0...v1.2.1) (2020-03-19)
### Bug Fixes
* **everything:** very proud to say this is 100% coverage according to default jest of all src code (including test) ([dd31d02](https://github.com/trilom/file-changes-action/commit/dd31d0220fdc9e6eb3469b3443239359d7da33d4))
* **redesign:** a lot of things changed here in the project ([32903fd](https://github.com/trilom/file-changes-action/commit/32903fd341ce6a5471e3df73393784cb43adb397))
# [1.2.0](https://github.com/trilom/file-changes-action/compare/v1.1.0...v1.2.0) (2020-03-02)
### Features
* **action:** githubToken is optional (uses action token), added githubRepo, prNumber, and pushBefore & After ([b24e2c3](https://github.com/trilom/file-changes-action/commit/b24e2c30c72710da8704a02f9d05141a19f27f83))
# [1.2.0](https://github.com/trilom/file-changes-action/compare/v1.1.0...v1.2.0) (2020-03-02)
### Features
* **action:** githubToken is optional (uses action token), added githubRepo, prNumber, and pushBefore & After ([b24e2c3](https://github.com/trilom/file-changes-action/commit/b24e2c30c72710da8704a02f9d05141a19f27f83))

View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2018 GitHub, Inc. and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,201 @@
# file-changes-action
[![codecov](https://codecov.io/gh/trilom/file-changes-action/branch/master/graph/badge.svg)](https://codecov.io/gh/trilom/file-changes-action)
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)
![Integration Tests](https://github.com/trilom/file-changes-action/workflows/Integration%20Tests/badge.svg)
# Like my work? Hire me!
> Please reach out if you need something built!
This action will take the information from the Push/Pull Request and output some variables and write files that will let you know what was changed, removed, or added.
## Inputs
### githubRepo
_Optional_ - `string` - the github repository you want to compare changes from, defaults to the github.repository.
### githubToken
_Optional_ - `string` - specific github token, github.token is used by default (Github Action Runner)
### output
_Optional_ - `string` - type of output for output variables, default is json. Use ',' for comma separated values, or ' ' for space delimited values. You can also create your own delimiter for example ' |FILE:' will output 'file1.yml |FILE:file2.yml |FILE:file3.yml'.
### fileOutput
_Optional_ - `string` - type of output for file output, default is json. Use ',' for comma separated values, or ' ' for space delimited values. You can also create your own delimiter for example `\ |FILE:` will output:
> file1.yml |FILE:file2.yml |FILE:file3.yml
If you select json then the file format will be .json, if you select ',' then the file format will be .csv, anything else will output the files as .txt
### pushBefore
_Optional_ - `string` - pass in a specific sha to compare to as a before, required if using pushAfter. (push payload after github.payload.before)
### pushAfter
_Optional_ - `string` - pass in a specific sha to compare to as an after, required if using pushBefore. (push payload after github.payload.after)
### prNumber
_Optional_ - `string` - pass in a specific PR number to get file changes from.
## Outputs
### files
steps.file_changes.outputs.files - `string` - The names all new, updated, and removed files. The output is dependant on the output input, default is a json string.
### files_added
steps.file_changes.outputs.files_added - `string` - The names of the newly created files. The output is dependant on the output input, default is a json string.
### files_modified
steps.file_changes.outputs.files_modified - `string` - The names of the updated files. The output is dependant on the output input, default is a json string.
### files_removed
steps.file_changes.outputs.files_removed - `string` - The names of the removed files. The output is dependant on the output input, default is a json string.
## Example usage
```yaml
# bare minimal
name: changes
on: push
jobs:
changes:
runs-on: ubuntu-latest
steps:
- id: file_changes
uses: trilom/file-changes-action@v1.2.3
### full
name: changes
on: [push, pull_request] # push or pull, or any event with custom pr number or before/after commit sha
jobs:
changes:
runs-on: ubuntu-latest
steps:
- id: file_changes
uses: trilom/file-changes-action@v1.2.3
with:
# optional target repo
githubRepo: trilom/file-changes-action
# optional token
githubToken: ${{ secrets.BOT_TOKEN }}
# optional output format
output: 'json'
# optional fileoutput format
fileOutput: 'csv'
# optional push before SHA (need both before and after)
pushBefore: 79eeec74aebc3deb0a2f6234c5ac13142e9224e5
# optional push after SHA (need both before and after)
pushAfter: 1c5a2bfde79e2c9cffb75b9a455391350fe69a40
# optional PR number to compare
prNumber: 36
```
## How to Use
In order to make those decisions we need to know what files have changed and that is where this action comes in. In the example below we are checking out our repository code, and then running the `trilom/file-changes-action@v1` action. The only thing you need to provide is a GITHUB_TOKEN so that Octokit can make it's API calls.
If a PR is made then it will look at all of the files included in the PR.
If a push is made then it will compare commits from the SHA `github.payload.before` to the SHA `github.payload.after` of the push.
After gathering this information it will output the files in 2 ways.
- As an output variable, you can use this variable by using `steps.file_changes_outputs_files`, `steps.file_changes.outputs.files_modified`, `steps.file_changes.outputs.files_added`, `steps.file_changes.outputs.files_removed`.
- As a file on the container stored at `$HOME/files.json`, `$HOME/files_modified.json`, `$HOME/files_added.json`, `$HOME/files_removed.json`.
- _NOTE:_ If you set a custom delimiter in output or fileOutput inputs then you will receive different files. For example a delimiter of ',' will output at `$HOME/files.csv` instead of `$HOME/files.json`. Likewise, anything other than 'json' or ',' delmiters will output `$HOME/files.txt` files instead of `$HOME/files.json` by default.
## Use Cases
I have a process where I have AWS Cloudformation templates stored in one directory that might be named PRODUCT-ROLE, and mappings for these templates that span the PRODUCT. For example **mappings/wordpress.mappings.yml, templates/wordpress-database.yml, templates/wordpress-webserver.yml**, and some of the templates might use different Lambda functions defined in for example **functions/wordpress-webserver/**.
In the example below we have a workflow that on *push* to the develop branch we can perform some actions based on the files. In my use case I look for changes on the develop branch of this repository for every push that happens. When a push happens and a change is made to any of the paths below the workflow will trigger. With this action you are able to know exactly which files changed so that you can make decisions later in your CI/CD.
In this case, if a **templates/*.yml** file is changed, then we want to update the Cloudformation stack. We can also write specifics for related templates. For example, if **templates/wordpress-database.yml** changes then we want to deploy **templates/wordpress-webserver.yml** as well after.
Another case is if the **mappings/wordpress.mappings.yml** changes, we want to deploy all **template/wordpress-*.yml** files.
## More examples
```yaml
name: push-develop
on: [push]
jobs:
changes:
runs-on: ubuntu-latest
steps:
- id: file_changes
uses: trilom/file-changes-action@v1.2.3
- name: test
run: |
cat $HOME/files.json
cat $HOME/files_modified.json
cat $HOME/files_added.json
cat $HOME/files_removed.json
echo '${{ steps.file_changes.outputs.files}}'
echo '${{ steps.file_changes.outputs.files_modified}}'
echo '${{ steps.file_changes.outputs.files_added}}'
echo '${{ steps.file_changes.outputs.files_removed}}'
```
You can set the output and fileOutput to ',' for csv output.
```yaml
name: push-develop
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- id: file_changes
uses: trilom/file-changes-action@v1.2.3
with:
output: ','
fileOutput: ','
- name: test
run: |
cat $HOME/files.csv
```
You can set the output and fileOutput to ' ' for txt output. We also used a specific token, and got info for the PR that this push came from.
```yaml
name: push-develop
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@0.6.0
id: pr
with:
github-token: ${{env.BOT_USER_TOKEN}}
result-encoding: string
script: |
const result = await github.repos.listPullRequestsAssociatedWithCommit({
owner: context.payload.repository.owner.name,
repo: context.payload.repository.name,
commit_sha: context.payload.head_commit.id
})
return result.data[0].number;
- id: file_changes
uses: trilom/file-changes-action@v1.2.3
with:
githubToken: ${{ env.BOT_USER_TOKEN }}
prNumber: ${{ steps.pr.outputs.results }}
output: ' '
fileOutput: ' '
- name: test
run: |
cat $HOME/files.txt
```

View File

@@ -0,0 +1,43 @@
name: 'File Changes Action'
description: 'Creates outputs variables of files modified, added, or removed by a PR or Push.'
author: 'Bryan Killian <me@trilom.org>'
inputs:
githubRepo:
description: 'The github repository you want to compare changes from, defaults to the github.repository.'
required: false
githubToken:
description: 'The github action token will be used by default, if you want to use something different than you can pass it in here.'
default: ${{ github.token }}
required: true
pushBefore:
description: 'Pass in a specific sha to compare to as a before, required if using pushAfter. (push BASE payload after github.payload.before)'
required: false
pushAfter:
description: 'Pass in a specific sha to compare to as an after, required if using pushBefore. (push HEAD payload after github.payload.after)'
required: false
prNumber:
description: 'Pass in a specific PR number to get file changes from.'
required: false
output:
description: 'Choose between json (default), or custom delimiter by passing a string, for example '','' for csv variable output'
required: true
default: json
fileOutput:
description: 'Choose between json (default), or custom delimiter by passing a string, for example '','' for csv file output. If you set as json the file output will be suffixed with .json, if you select '','' then the output will be .csv, else .txt will be the output.'
required: true
default: json
outputs:
files:
description: 'The names all new, updated, and removed files'
files_added:
description: 'The names of the newly created files'
files_modified:
description: 'The names of the updated files'
files_removed:
description: 'The names of the removed files'
runs:
using: 'node12'
main: 'dist/index.js'
branding:
icon: 'file-text'
color: 'red'

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,5 @@
var config = require('./jest.config')
config.testPathIgnorePatterns = ['!/src/tests/integration.test.ts']
config.testMatch = ['**/integration.test.ts']
console.log('RUNNING INTEGRATION TESTS')
module.exports = config

View File

@@ -0,0 +1,29 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: "node",
testRunner: 'jest-circus/runner',
testMatch: ['**/*.test.ts'],
testPathIgnorePatterns: ['/src/tests/integration.test.ts'],
clearMocks: true,
collectCoverage: false,
coverageThreshold: {
global: {
branches: 50,
functions: 70,
lines: 75,
statements: 75
},
'./src/*.ts': {
branches: 70,
functions: 85,
lines: 85,
statements: 85
},
'./src/tests/**/*.ts': {
branches: 50,
functions: 60,
lines: 65,
statements: 65
}
}
}

7238
.github/actions/file-changes-action/package-lock.json generated vendored Normal file

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More