Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Issue reopener GitHub Action #119

Merged
merged 19 commits into from
Aug 19, 2023
56 changes: 56 additions & 0 deletions .github/workflows/pre-submit.units.yml
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,15 @@ jobs:
# Run golangci-lint
make golangci-lint

eslint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
with:
node-version: 16
- run: make eslint

yamllint:
runs-on: ubuntu-latest
steps:
Expand All @@ -164,3 +173,50 @@ jobs:

# Run yamllint
make yamllint

check-dist-matrix:
runs-on: ubuntu-latest
strategy:
matrix:
action:
- ./actions/issue-reopener
steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3

- uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
with:
node-version: 16

- name: Rebuild the dist/ directory
working-directory: ${{ matrix.action }}
run: make clean package

- name: Compare the expected and actual dist/ directories
working-directory: ${{ matrix.action }}
id: diff
run: |
set -euo pipefail
if [ "$(git diff --ignore-space-at-eol dist/ | wc -l)" -gt "0" ]; then
echo "Detected uncommitted changes after build. See status below:"
git diff
exit 1
fi

# If dist/ was different from expected, upload the expected version as an artifact
- uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
if: ${{ failure() && steps.diff.conclusion == 'failure' }}
with:
name: dist
path: ${{ matrix.action }}/dist/

# NOTE: needed for protected branch checks.
check-dist:
runs-on: ubuntu-latest
needs: check-dist-matrix
if: ${{ always() }}
env:
CHECK_DIST_RESULT: ${{ needs.check-dist-matrix.result }}
steps:
# exit 0 if checks were successful.
- run: |
[ "${CHECK_DIST_RESULT}" == "success" ]
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ autogen: ## Runs autogen on code files.
#####################################################################

.PHONY: lint
lint: markdownlint golangci-lint yamllint actionlint ## Run all linters.
lint: golangci-lint eslint yamllint actionlint markdownlint ## Run all linters.

.PHONY: actionlint
actionlint: ## Runs the actionlint linter.
Expand All @@ -118,6 +118,14 @@ actionlint: ## Runs the actionlint linter.
actionlint $${files}; \
fi

.PHONY: eslint
eslint: ## Runs the eslint linter.
@set -e;\
PATHS=$$(find actions/ -not -path '*/node_modules/*' -name package.json -type f | xargs dirname); \
for path in $$PATHS; do \
make -C $$path lint; \
done

.PHONY: markdownlint
markdownlint: node_modules/.installed ## Runs the markdownlint linter.
@set -e;\
Expand Down
1 change: 1 addition & 0 deletions actions/issue-reopener/.eslintignore
53 changes: 53 additions & 0 deletions actions/issue-reopener/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"plugins": ["@typescript-eslint"],
"extends": ["plugin:github/recommended"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 9,
"sourceType": "module",
"project": "./tsconfig.json"
},
"rules": {
"i18n-text/no-en": "off",
"eslint-comments/no-use": "off",
"import/no-namespace": "off",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
"@typescript-eslint/no-require-imports": "error",
"@typescript-eslint/array-type": "error",
"@typescript-eslint/await-thenable": "error",
"@typescript-eslint/ban-ts-comment": "error",
"camelcase": "off",
"@typescript-eslint/consistent-type-assertions": "error",
"@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}],
"@typescript-eslint/func-call-spacing": ["error", "never"],
"@typescript-eslint/no-array-constructor": "error",
"@typescript-eslint/no-empty-interface": "error",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-extraneous-class": "error",
"@typescript-eslint/no-for-in-array": "error",
"@typescript-eslint/no-inferrable-types": "error",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-non-null-assertion": "warn",
"@typescript-eslint/no-unnecessary-qualifier": "error",
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-useless-constructor": "error",
"@typescript-eslint/no-var-requires": "error",
"@typescript-eslint/prefer-for-of": "warn",
"@typescript-eslint/prefer-function-type": "warn",
"@typescript-eslint/prefer-includes": "error",
"@typescript-eslint/prefer-string-starts-ends-with": "error",
"@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/require-array-sort-compare": "error",
"@typescript-eslint/restrict-plus-operands": "error",
"semi": "off",
"@typescript-eslint/type-annotation-spacing": "error",
"@typescript-eslint/unbound-method": "error"
},
"env": {
"node": true,
"es6": true
}
}
99 changes: 99 additions & 0 deletions actions/issue-reopener/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# 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/*
lib/**/*
1 change: 1 addition & 0 deletions actions/issue-reopener/.prettierignore
91 changes: 91 additions & 0 deletions actions/issue-reopener/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

SHELL := /bin/bash
ACTION_NAME = $(shell basename "$$(pwd)")
OUTPUT_FORMAT ?= $(shell if [ "${GITHUB_ACTIONS}" == "true" ]; then echo "github"; else echo ""; fi)

REPO_ROOT := $(shell git rev-parse --show-toplevel)

.PHONY: help
help: ## Shows all targets and help from the Makefile (this message).
@echo "$(ACTION_NAME) Makefile"
@echo "Usage: make [COMMAND]"
@echo ""
@grep --no-filename -E '^([/a-z.A-Z0-9_%-]+:.*?|)##' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS = "(:.*?|)## ?"}; { \
if (length($$1) > 0) { \
printf " \033[36m%-20s\033[0m %s\n", $$1, $$2; \
} else { \
if (length($$2) > 0) { \
printf "%s\n", $$2; \
} \
} \
}'

node_modules/.installed: package.json package-lock.json
npm ci
touch node_modules/.installed

.PHONY: action
action: node_modules/.installed ## Builds the action.
npm run build

.PHONY: package
package: action ## Builds the distribution package.
npm run package

.PHONY: clean
clean:
rm -rf dist lib node_modules

ianlewis marked this conversation as resolved.
Show resolved Hide resolved
ianlewis marked this conversation as resolved.
Show resolved Hide resolved
## Tools
#####################################################################

.PHONY: format
format: node_modules/.installed ## Formats code.
npm run format

## Testing
#####################################################################

.PHONY: lint
lint: node_modules/.installed ## Runs eslint.
ianlewis marked this conversation as resolved.
Show resolved Hide resolved
@set -e;\
if [ "$(OUTPUT_FORMAT)" == "github" ]; then \
exit_code=0; \
while IFS="" read -r p && [ -n "$$p" ]; do \
file=$$(echo "$$p" | jq -c '.filePath // empty' | tr -d '"'); \
file=$$(realpath --relative-to "$(REPO_ROOT)" "$$file"); \
while IFS="" read -r m && [ -n "$$m" ]; do \
severity=$$(echo "$$m" | jq -c '.severity // empty' | tr -d '"'); \
line=$$(echo "$$m" | jq -c '.line // empty' | tr -d '"'); \
endline=$$(echo "$$m" | jq -c '.endLine // empty' | tr -d '"'); \
col=$$(echo "$$m" | jq -c '.column // empty' | tr -d '"'); \
endcol=$$(echo "$$m" | jq -c '.endColumn // empty' | tr -d '"'); \
message=$$(echo "$$m" | jq -c '.message // empty' | tr -d '"'); \
exit_code=1; \
case $$severity in \
"1") \
echo "::warning file=$${file},line=$${line},endLine=$${endline},col=$${col},endColumn=$${endcol}::$${message}"; \
;; \
"2") \
echo "::error file=$${file},line=$${line},endLine=$${endline},col=$${col},endColumn=$${endcol}::$${message}"; \
;; \
esac; \
done <<<$$(echo "$$p" | jq -c '.messages[]'); \
done <<<$$(./node_modules/.bin/eslint --max-warnings 0 -f json src/**/*.ts | jq -c '.[]'); \
else \
./node_modules/.bin/eslint --max-warnings 0 src/**/*.ts; \
fi
46 changes: 46 additions & 0 deletions actions/issue-reopener/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# issue-reopener

ianlewis marked this conversation as resolved.
Show resolved Hide resolved
The `ianlewis/todos/actions/issue-reopener` GitHub Action searches your checked
out code for TODO comments that reference issues and reopens issues that have
been closed prematurely. `issue-reopener` will also add a comment on the issue
with a link to the source code where the TODO can be found.

TODO comments can take the following forms:

```golang
// TODO(#123): Referencing the issue number with a pound sign.
// TODO(123): Referencing the issue number only.
// TODO(github.com/owner/repo/issues/123): Referencing the issue url without scheme.
// TODO(https://github.com/owner/repo/issues/123): Referencing the issue url with scheme.
```

## Getting Started

First use the `actions/checkout` action to check out your repository. After that
you can call `ianlewis/todos/actions/issue-reopener` to scan your codebase for
TODO comments.

Note that you must set the `issues: write` permission on the job.

```yaml
jobs:
issue-reopener:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- uses: actions/checkout@v3
- name: Issue Reopener
uses: ianlewis/todos/actions/[email protected]
```

## Inputs

| Name | Required | Default | Description |
| ----- | -------- | ------------------ | -------------------------------------------------------------------------- |
| path | No | `github.workspace` | The root path of the source code to search. |
| token | No | `github.token` | The GitHub token to use. This token must have `issues: write` permissions. |

## Outputs

There are currently no outputs.
Loading
Loading