├── .dockerignore ├── .editorconfig ├── .env ├── .github ├── FUNDING.yml ├── dependabot.yml ├── linters │ ├── .checkov.yml │ ├── .commit-lint.yml │ ├── .grype.yaml │ ├── .lychee.toml │ ├── .markdown-lint.yml │ ├── .mega-linter.yml │ └── .yamllint.yml └── workflows │ ├── pull_request_target.yml │ └── push.yml ├── .gitignore ├── .pandoc.yml ├── .release.json ├── .semantic.json ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── action.yml ├── colophon.yml ├── docker-compose.yml ├── docs ├── README.md └── README.template ├── package-lock.json ├── package.json ├── src ├── index.js └── lib │ ├── index.js │ └── runs.js └── test └── fixtures └── payload.json /.dockerignore: -------------------------------------------------------------------------------- 1 | action/node_modules 2 | action/test 3 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-template # 3 | # ----------------------------------------------- # 4 | 5 | root = true 6 | 7 | [*] 8 | charset = utf-8 9 | end_of_line = lf 10 | indent_size = 2 11 | indent_style = space 12 | insert_final_newline = true 13 | trim_trailing_whitespace = true 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | 18 | [Makefile] 19 | indent_style = tab 20 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | GITHUB_EVENT_NAME=push 2 | GITHUB_EVENT_PATH=test/fixtures/payload.json 3 | GITHUB_REPOSITORY=ahmadnassri/action-workflow-queue 4 | GITHUB_WORKSPACE=/github/workspace 5 | 6 | INPUT_GITHUB-TOKEN=$GITHUB_TOKEN 7 | INPUT_DELAY=1000 8 | INPUT_TIMEOUT=1000 9 | INPUT_TOKEN=$GITHUB_TOKEN 10 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-template # 3 | # ----------------------------------------------- # 4 | 5 | github: [ahmadnassri] 6 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # ---------------------------------------------------- # 2 | # Note: this file originates in template-action-docker # 3 | # ---------------------------------------------------- # 4 | 5 | version: 2 6 | updates: 7 | - package-ecosystem: npm 8 | open-pull-requests-limit: 10 9 | directory: /action 10 | commit-message: 11 | prefix: build 12 | prefix-development: chore 13 | include: scope 14 | schedule: 15 | interval: daily 16 | time: "10:00" 17 | timezone: America/Toronto 18 | 19 | - package-ecosystem: docker 20 | open-pull-requests-limit: 10 21 | directory: / 22 | commit-message: 23 | prefix: build 24 | prefix-development: chore 25 | include: scope 26 | schedule: 27 | interval: daily 28 | time: "10:00" 29 | timezone: America/Toronto 30 | -------------------------------------------------------------------------------- /.github/linters/.checkov.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-template # 3 | # ----------------------------------------------- # 4 | 5 | quiet: true 6 | skip-check: 7 | - CKV_DOCKER_2 8 | - CKV_DOCKER_8 9 | - CKV_GHA_3 10 | - BC_DKR_3 11 | - CKV_GIT_1 12 | - CKV_GIT_5 13 | - CKV_GIT_6 14 | - CKV_TF_1 15 | -------------------------------------------------------------------------------- /.github/linters/.commit-lint.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-template # 3 | # ----------------------------------------------- # 4 | 5 | extends: 6 | - "@commitlint/config-conventional" 7 | 8 | rules: 9 | body-max-line-length: [2, "always", 200] 10 | -------------------------------------------------------------------------------- /.github/linters/.grype.yaml: -------------------------------------------------------------------------------- 1 | check-for-app-update: false 2 | exclude: 3 | - '**/package-lock.json' 4 | -------------------------------------------------------------------------------- /.github/linters/.lychee.toml: -------------------------------------------------------------------------------- 1 | exclude_path = [".github"] 2 | -------------------------------------------------------------------------------- /.github/linters/.markdown-lint.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-template # 3 | # ----------------------------------------------- # 4 | 5 | # Heading levels should only increment by one level at a time 6 | MD001: false 7 | 8 | # Heading style 9 | MD003: 10 | style: atx 11 | 12 | # Unordered list style 13 | MD004: 14 | style: dash 15 | 16 | # Inconsistent indentation for list items at the same level 17 | MD005: true 18 | 19 | # Unordered list indentation 20 | MD007: 21 | indent: 2 22 | start_indented: false 23 | 24 | # Trailing spaces 25 | MD009: 26 | br_spaces: 2 27 | list_item_empty_lines: false 28 | strict: false 29 | 30 | # Hard tabs 31 | MD010: 32 | code_blocks: false 33 | 34 | # Reversed link syntax 35 | MD011: true 36 | 37 | # Multiple consecutive blank lines 38 | MD012: 39 | maximum: 1 40 | 41 | # Line length 42 | MD013: 43 | line_length: 360 44 | strict: true 45 | stern: true 46 | 47 | # Dollar signs used before commands without showing output 48 | MD014: false 49 | 50 | # No space after hash on atx style heading 51 | MD018: true 52 | 53 | # Multiple spaces after hash on atx style heading 54 | MD019: true 55 | 56 | # No space inside hashes on closed atx style heading 57 | MD020: true 58 | 59 | # Multiple spaces inside hashes on closed atx style heading 60 | MD021: true 61 | 62 | # Headings should be surrounded by blank lines 63 | MD022: 64 | lines_above: 1 65 | lines_below: 1 66 | 67 | # Headings must start at the beginning of the line 68 | MD023: true 69 | 70 | # Multiple headings with the same content 71 | MD024: 72 | allow_different_nesting: true 73 | 74 | # Multiple top level headings in the same document 75 | MD025: true 76 | 77 | # Trailing punctuation in heading 78 | MD026: 79 | punctuation: ".,;:!?。,;:!?" 80 | 81 | # Multiple spaces after blockquote symbol 82 | MD027: true 83 | 84 | # Blank line inside blockquote 85 | MD028: true 86 | 87 | # Ordered list item prefix 88 | MD029: 89 | style: one_or_ordered 90 | 91 | # Spaces after list markers 92 | MD030: 93 | ul_single: 1 94 | ol_single: 1 95 | ul_multi: 1 96 | ol_multi: 1 97 | 98 | # Fenced code blocks should be surrounded by blank lines 99 | MD031: 100 | list_items: true 101 | 102 | # Lists should be surrounded by blank lines 103 | MD032: true 104 | 105 | # inline HTML 106 | MD033: 107 | allowed_elements: [details, summary] 108 | 109 | # Bare URL used 110 | MD034: true 111 | 112 | # Horizontal rule style 113 | MD035: 114 | style: "----" 115 | 116 | # Emphasis used instead of a heading 117 | MD036: 118 | punctuation: ".,;:!?。,;:!?" 119 | 120 | # Spaces inside emphasis markers 121 | MD037: true 122 | 123 | # Spaces inside code span elements 124 | MD038: true 125 | 126 | # Spaces inside link text 127 | MD039: true 128 | 129 | # Fenced code blocks should have a language specified 130 | MD040: true 131 | 132 | # First line in file should be a top level heading 133 | MD041: false 134 | 135 | # No empty links 136 | MD042: true 137 | 138 | # Required heading structure 139 | MD043: false 140 | 141 | # Proper names should have the correct capitalization 142 | MD044: false 143 | 144 | # Images should have alternate text (alt text) 145 | MD045: false 146 | 147 | # Code block style 148 | MD046: 149 | style: fenced 150 | 151 | # Files should end with a single newline character 152 | MD047: true 153 | 154 | # Code fence style 155 | MD048: 156 | style: backtick 157 | -------------------------------------------------------------------------------- /.github/linters/.mega-linter.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-template # 3 | # ----------------------------------------------- # 4 | 5 | DISABLE: 6 | - COPYPASTE 7 | 8 | DISABLE_LINTERS: 9 | - REPOSITORY_TRIVY 10 | - SPELL_CSPELL 11 | - JSON_PRETTIER 12 | - YAML_PRETTIER 13 | - JAVASCRIPT_PRETTIER 14 | - HTML_DJLINT 15 | - REPOSITORY_KICS 16 | - REPOSITORY_TRUFFLEHOG 17 | - REPOSITORY_DEVSKIM # temporarily disabled 18 | - TERRAFORM_TERRASCAN # temporarily disabled 19 | 20 | LOG_LEVEL: INFO 21 | PRINT_ALPACA: false 22 | CONFIG_REPORTER: false 23 | SHOW_ELAPSED_TIME: true 24 | FLAVOR_SUGGESTIONS: false 25 | VALIDATE_ALL_CODEBASE: false 26 | IGNORE_GENERATED_FILES: true 27 | FILTER_REGEX_EXCLUDE: (dist/*|README.md|vendor/*|/schemas/*|test/fixtures/*) 28 | 29 | MARKDOWN_MARKDOWNLINT_CONFIG_FILE: .markdown-lint.yml 30 | REPOSITORY_CHECKOV_ARGUMENTS: [--skip-path, schemas, --skip-path, test/fixtures] 31 | -------------------------------------------------------------------------------- /.github/linters/.yamllint.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-template # 3 | # ----------------------------------------------- # 4 | 5 | extends: default 6 | 7 | rules: 8 | brackets: 9 | max-spaces-inside: 1 10 | document-start: 11 | present: false 12 | truthy: 13 | check-keys: false 14 | line-length: 15 | max: 500 16 | comments: 17 | min-spaces-from-content: 1 18 | -------------------------------------------------------------------------------- /.github/workflows/pull_request_target.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-template # 3 | # ----------------------------------------------- # 4 | 5 | name: pull_request_target 6 | 7 | on: pull_request_target 8 | 9 | permissions: read-all 10 | 11 | jobs: 12 | main: 13 | uses: ahmadnassri/actions/.github/workflows/pull-request-target.yml@master 14 | secrets: inherit 15 | -------------------------------------------------------------------------------- /.github/workflows/push.yml: -------------------------------------------------------------------------------- 1 | # ---------------------------------------------------- # 2 | # Note: this file originates in template-action-docker # 3 | # ---------------------------------------------------- # 4 | 5 | name: push 6 | 7 | on: 8 | - push 9 | - workflow_dispatch 10 | 11 | permissions: read-all 12 | 13 | jobs: 14 | main: 15 | uses: ahmadnassri/actions/.github/workflows/push-action-docker.yml@master 16 | secrets: inherit 17 | permissions: 18 | contents: write 19 | statuses: write 20 | packages: write 21 | pull-requests: write 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ---------------------------------------------------- # 2 | # Note: this file originates in template-action-docker # 3 | # ---------------------------------------------------- # 4 | 5 | *.log 6 | .nyc_output 7 | coverage 8 | node_modules 9 | -------------------------------------------------------------------------------- /.pandoc.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-template # 3 | # ----------------------------------------------- # 4 | 5 | input-file: docs/README.md 6 | output-file: README.md 7 | metadata-file: colophon.yml 8 | template: docs/README.template 9 | 10 | from: gfm 11 | to: gfm 12 | 13 | wrap: preserve 14 | reference-links: true 15 | fail-if-warnings: false 16 | -------------------------------------------------------------------------------- /.release.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["@semantic-release/commit-analyzer", { 4 | "preset": "conventionalcommits", 5 | "releaseRules": [ 6 | { "breaking": true, "release": "major" }, 7 | { "revert": true, "release": "patch" }, 8 | { "type": "build", "release": "patch" }, 9 | { "type": "docs", "release": "patch" }, 10 | { "type": "feat", "release": "minor" }, 11 | { "type": "fix", "release": "patch" }, 12 | { "type": "perf", "release": "patch" }, 13 | { "type": "refactor", "release": "patch" } 14 | ] 15 | }], 16 | ["@semantic-release/release-notes-generator", { 17 | "preset": "conventionalcommits", 18 | "presetConfig": { 19 | "types": [ 20 | { "type": "chore", "section": "Chores", "hidden": true }, 21 | { "type": "build", "section": "Build", "hidden": false }, 22 | { "type": "ci", "section": "CI/CD", "hidden": false }, 23 | { "type": "docs", "section": "Docs", "hidden": false }, 24 | { "type": "feat", "section": "Features", "hidden": false }, 25 | { "type": "fix", "section": "Bug Fixes", "hidden": false }, 26 | { "type": "perf", "section": "Performance", "hidden": false }, 27 | { "type": "refactor", "section": "Refactor", "hidden": false }, 28 | { "type": "style", "section": "Code Style", "hidden": false }, 29 | { "type": "test", "section": "Tests", "hidden": false } 30 | ] 31 | } 32 | }], 33 | ["@semantic-release/exec", { 34 | "prepareCmd": "sed -Ei 's/:[0-9,\\.]+/:${nextRelease.version}/g' action.yml" 35 | }], 36 | ["@semantic-release/git", { 37 | "assets": ["action.yml"], 38 | "message": "chore(release): bump to ${nextRelease.version} [skip ci]" 39 | }], 40 | ["@semantic-release/github", { 41 | "successComment": false, 42 | "failComment": false 43 | }] 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /.semantic.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["@semantic-release/commit-analyzer", { 4 | "preset": "conventionalcommits", 5 | "releaseRules": [ 6 | { "breaking": true, "release": "major" }, 7 | { "revert": true, "release": "patch" }, 8 | { "type": "build", "release": "patch" }, 9 | { "type": "docs", "release": "patch" }, 10 | { "type": "feat", "release": "minor" }, 11 | { "type": "fix", "release": "patch" }, 12 | { "type": "perf", "release": "patch" }, 13 | { "type": "refactor", "release": "patch" } 14 | ] 15 | }], 16 | ["@semantic-release/release-notes-generator", { 17 | "preset": "conventionalcommits", 18 | "presetConfig": { 19 | "types": [ 20 | { "type": "chore", "section": "Chores", "hidden": true }, 21 | { "type": "build", "section": "Build", "hidden": false }, 22 | { "type": "ci", "section": "CI/CD", "hidden": false }, 23 | { "type": "docs", "section": "Docs", "hidden": false }, 24 | { "type": "feat", "section": "Features", "hidden": false }, 25 | { "type": "fix", "section": "Bug Fixes", "hidden": false }, 26 | { "type": "perf", "section": "Performance", "hidden": false }, 27 | { "type": "refactor", "section": "Refactor", "hidden": false }, 28 | { "type": "style", "section": "Code Style", "hidden": false }, 29 | { "type": "test", "section": "Tests", "hidden": false } 30 | ] 31 | } 32 | }], 33 | ["@semantic-release/exec", { 34 | "prepareCmd": "sed -Ei 's/:[0-9,\\.]+/:${nextRelease.version}/g' action.yml" 35 | }], 36 | ["@semantic-release/git", { 37 | "assets": ["action.yml"], 38 | "message": "chore(release): bump to ${nextRelease.version} [skip ci]" 39 | }], 40 | ["@semantic-release/github", { 41 | "successComment": false, 42 | "failComment": false 43 | }] 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # --- base stage --- # 2 | 3 | FROM alpine:3.19 AS base 4 | 5 | # hadolint ignore=DL3018 6 | RUN apk add --no-cache --update \ 7 | nodejs=18.18.2-r0 \ 8 | git=2.40.1-r0 \ 9 | openssh=9.3_p2-r0 \ 10 | ca-certificates=20230506-r0 \ 11 | ruby-bundler=2.4.15-r0 \ 12 | bash=5.2.15-r5 13 | 14 | WORKDIR /action 15 | 16 | # --- build stage --- # 17 | 18 | FROM base AS build 19 | 20 | # hadolint ignore=DL3018 21 | RUN apk add --no-cache npm=9.6.6-r0 22 | 23 | # slience npm 24 | # hadolint ignore=DL3059 25 | RUN npm config set update-notifier=false audit=false fund=false 26 | 27 | # install packages 28 | COPY package* ./ 29 | RUN npm ci --omit=dev --no-fund --no-audit 30 | 31 | # --- app stage --- # 32 | 33 | FROM base AS app 34 | 35 | # copy from build image 36 | COPY --from=build /action/node_modules ./node_modules 37 | 38 | # copy files 39 | COPY package.json src ./ 40 | 41 | WORKDIR /github/workspace/ 42 | 43 | # hadolint ignore=DL3002 44 | USER root 45 | 46 | HEALTHCHECK NONE 47 | 48 | ENTRYPOINT ["node", "/action/index.js"] 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Ahmad Nassri 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make 2 | 3 | # ---------------------------------------------------- # 4 | # Note: this file originates in template-action-docker # 5 | # ---------------------------------------------------- # 6 | 7 | pull: ## pull latest containers 8 | @docker compose pull 9 | 10 | lint: clean ## run mega-linter 11 | @docker compose run --rm lint 12 | 13 | readme: clean ## run readme action 14 | @docker compose run --rm readme 15 | 16 | build: clean ## start the project in background 17 | @docker compose build --no-cache app 18 | 19 | shell: ## start the container shell 20 | @docker compose run --rm --entrypoint /bin/sh app 21 | 22 | install: ## install all dependencies 23 | @docker compose run --rm app install 24 | 25 | start: ## start the project in foreground 26 | @docker compose run --rm app 27 | 28 | test: ## run all npm tests 29 | @docker compose run --rm app-test 30 | 31 | build-action: clean ## start the project in background 32 | @docker compose build --no-cache action 33 | 34 | shell-action: ## start the container shell 35 | @docker compose run --rm --entrypoint /bin/sh action 36 | 37 | start-action: ## start the project in foreground 38 | @docker compose run --rm action 39 | 40 | test-action: ## start the project in foreground 41 | @docker compose run --rm action-test 42 | 43 | stop: ## stop all running containers 44 | @docker compose down --remove-orphans --rmi local 45 | 46 | clean: stop ## remove running containers, volumes, node_modules & anything else 47 | @docker compose rm --stop --volumes --force 48 | 49 | # Utility methods 50 | ## Help: https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html 51 | 52 | help: ## display this help 53 | @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) 54 | 55 | .DEFAULT_GOAL := help 56 | .PHONY: help all clean test 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GitHub Action: Workflow Run Queue 2 | 3 | If the same workflow is already running from a previous commit, wait for it to finish 4 | 5 | [![license][license-img]][license-url] 6 | [![release][release-img]][release-url] 7 | 8 |
9 | Why? 10 | 11 | Workflows run on every commit asynchronously, this is fine for most cases, however, you might want to wait for a previous commit workflow to finish before running another one, some example use-cases: 12 | 13 | - Deployment workflows 14 | - Terraform workflows 15 | - Database Migrations 16 | 17 |
18 | 19 | ## Usage 20 | 21 | ###### `.github/workflows/my-workflow.yml` 22 | 23 | ``` yaml 24 | jobs: 25 | xyz: 26 | runs-on: ubuntu-latest 27 | 28 | steps: 29 | - uses: actions/checkout@v2 30 | - uses: ahmadnassri/action-workflow-queue@v1 31 | 32 | # only runs additional steps if there is no other instance of `my-workflow.yml` currently running 33 | ``` 34 | 35 | ### Inputs 36 | 37 | | input | required | default | description | 38 | |----------------|----------|----------------|-------------------------------------------------| 39 | | `github-token` | ❌ | `github.token` | The GitHub token used to call the GitHub API | 40 | | `timeout` | ❌ | `600000` | timeout before we stop trying (in milliseconds) | 41 | | `delay` | ❌ | `10000` | delay between status checks (in milliseconds) | 42 | 43 | ---- 44 | > Author: [Ahmad Nassri](https://www.ahmadnassri.com/) • 45 | > Twitter: [@AhmadNassri](https://twitter.com/AhmadNassri) 46 | 47 | [license-url]: LICENSE 48 | [license-img]: https://badgen.net/github/license/ahmadnassri/action-workflow-queue 49 | 50 | [release-url]: https://github.com/ahmadnassri/action-workflow-queue/releases 51 | [release-img]: https://badgen.net/github/release/ahmadnassri/action-workflow-queue 52 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: Workflow Queue 2 | description: If the same workflow is already running from a previous commit, wait for it to finish 3 | 4 | branding: 5 | color: yellow 6 | icon: clock 7 | 8 | inputs: 9 | github-token: 10 | description: The GitHub token used to post comments on pull requests 11 | default: ${{ github.token }} 12 | 13 | timeout: 14 | description: timeout before we stop trying (in milliseconds) 15 | default: "600000" 16 | 17 | delay: 18 | description: delay between status checks (in milliseconds) 19 | default: "10000" 20 | 21 | runs: 22 | using: docker 23 | image: docker://ghcr.io/ahmadnassri/action-workflow-queue:1.2.0 24 | -------------------------------------------------------------------------------- /colophon.yml: -------------------------------------------------------------------------------- 1 | version: 2.0 2 | 3 | id: action-workflow-queue 4 | 5 | about: 6 | title: "GitHub Action: Workflow Run Queue" 7 | description: If the same workflow is already running from a previous commit, wait for it to finish 8 | repository: ahmadnassri/action-workflow-queue 9 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | # ---------------------------------------------------- # 2 | # Note: this file originates in template-action-docker # 3 | # ---------------------------------------------------- # 4 | 5 | services: 6 | # ---- mega-linter ---- # 7 | lint: 8 | profiles: ["dev"] 9 | image: oxsecurity/megalinter-javascript:v7.3.0 10 | volumes: 11 | - ./:/tmp/lint 12 | environment: 13 | MEGALINTER_CONFIG: .github/linters/.mega-linter.yml 14 | REPORT_OUTPUT_FOLDER: none 15 | VALIDATE_ALL_CODEBASE: true 16 | 17 | # ---- readme generator ---- # 18 | readme: 19 | profiles: ["dev"] 20 | image: pandoc/minimal:2.19 21 | volumes: 22 | - ./:/data 23 | command: --defaults=.pandoc.yml 24 | 25 | # ---- action container ---- # 26 | action: 27 | profiles: ["action"] 28 | build: . 29 | 30 | action-test: 31 | extends: action 32 | profiles: ["action"] 33 | volumes: 34 | - ./test:/github/workspace/test 35 | - .git:/github/workspace/.git 36 | env_file: 37 | - .env 38 | 39 | # ---- main container ---- # 40 | app: 41 | profiles: ["app"] 42 | image: node:20-alpine 43 | working_dir: /app 44 | entrypoint: npm --no-update-notifier --no-fund --no-audit 45 | command: start 46 | tty: true 47 | volumes: 48 | - ./:/app 49 | env_file: 50 | - .env 51 | 52 | app-test: 53 | extends: app 54 | profiles: ["test"] 55 | command: run test:ci -- --reporter=classic 56 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | 2 |
3 | Why? 4 | 5 | Workflows run on every commit asynchronously, this is fine for most cases, however, you might want to wait for a previous commit workflow to finish before running another one, some example use-cases: 6 | 7 | - Deployment workflows 8 | - Terraform workflows 9 | - Database Migrations 10 |
11 | 12 | ## Usage 13 | 14 | ###### `.github/workflows/my-workflow.yml` 15 | 16 | ```yaml 17 | jobs: 18 | xyz: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - uses: actions/checkout@v2 23 | - uses: ahmadnassri/action-workflow-queue@v1 24 | 25 | # only runs additional steps if there is no other instance of `my-workflow.yml` currently running 26 | ``` 27 | 28 | ### Inputs 29 | 30 | | input | required | default | description | 31 | | -------------- | -------- | -------------- | ----------------------------------------------- | 32 | | `github-token` | ❌ | `github.token` | The GitHub token used to call the GitHub API | 33 | | `timeout` | ❌ | `600000` | timeout before we stop trying (in milliseconds) | 34 | | `delay` | ❌ | `10000` | delay between status checks (in milliseconds) | 35 | -------------------------------------------------------------------------------- /docs/README.template: -------------------------------------------------------------------------------- 1 | # $about.title$ 2 | 3 | $about.description$ 4 | 5 | [![license][license-img]][license-url] 6 | [![release][release-img]][release-url] 7 | 8 | $body$ 9 | 10 | --- 11 | 12 | > Author: [Ahmad Nassri](https://www.ahmadnassri.com/) 13 | 14 | [license-url]: LICENSE 15 | [license-img]: https://badgen.net/github/license/$about.repository$ 16 | [release-url]: https://github.com/$about.repository$/releases 17 | [release-img]: https://badgen.net/github/release/$about.repository$ 18 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "actions-workflow-queue", 3 | "version": "0.0.0-semantically-released", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "actions-workflow-queue", 9 | "version": "0.0.0-semantically-released", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@actions/core": "^1.10.0", 13 | "@actions/github": "^5.1.1" 14 | } 15 | }, 16 | "node_modules/@actions/core": { 17 | "version": "1.10.0", 18 | "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", 19 | "integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", 20 | "dependencies": { 21 | "@actions/http-client": "^2.0.1", 22 | "uuid": "^8.3.2" 23 | } 24 | }, 25 | "node_modules/@actions/github": { 26 | "version": "5.1.1", 27 | "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.1.tgz", 28 | "integrity": "sha512-Nk59rMDoJaV+mHCOJPXuvB1zIbomlKS0dmSIqPGxd0enAXBnOfn4VWF+CGtRCwXZG9Epa54tZA7VIRlJDS8A6g==", 29 | "dependencies": { 30 | "@actions/http-client": "^2.0.1", 31 | "@octokit/core": "^3.6.0", 32 | "@octokit/plugin-paginate-rest": "^2.17.0", 33 | "@octokit/plugin-rest-endpoint-methods": "^5.13.0" 34 | } 35 | }, 36 | "node_modules/@actions/http-client": { 37 | "version": "2.1.0", 38 | "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.1.0.tgz", 39 | "integrity": "sha512-BonhODnXr3amchh4qkmjPMUO8mFi/zLaaCeCAJZqch8iQqyDnVIkySjB38VHAC8IJ+bnlgfOqlhpyCUZHlQsqw==", 40 | "dependencies": { 41 | "tunnel": "^0.0.6" 42 | } 43 | }, 44 | "node_modules/@octokit/auth-token": { 45 | "version": "2.5.0", 46 | "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", 47 | "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", 48 | "dependencies": { 49 | "@octokit/types": "^6.0.3" 50 | } 51 | }, 52 | "node_modules/@octokit/core": { 53 | "version": "3.6.0", 54 | "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", 55 | "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", 56 | "dependencies": { 57 | "@octokit/auth-token": "^2.4.4", 58 | "@octokit/graphql": "^4.5.8", 59 | "@octokit/request": "^5.6.3", 60 | "@octokit/request-error": "^2.0.5", 61 | "@octokit/types": "^6.0.3", 62 | "before-after-hook": "^2.2.0", 63 | "universal-user-agent": "^6.0.0" 64 | } 65 | }, 66 | "node_modules/@octokit/endpoint": { 67 | "version": "6.0.12", 68 | "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", 69 | "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", 70 | "dependencies": { 71 | "@octokit/types": "^6.0.3", 72 | "is-plain-object": "^5.0.0", 73 | "universal-user-agent": "^6.0.0" 74 | } 75 | }, 76 | "node_modules/@octokit/graphql": { 77 | "version": "4.8.0", 78 | "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", 79 | "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", 80 | "dependencies": { 81 | "@octokit/request": "^5.6.0", 82 | "@octokit/types": "^6.0.3", 83 | "universal-user-agent": "^6.0.0" 84 | } 85 | }, 86 | "node_modules/@octokit/openapi-types": { 87 | "version": "12.11.0", 88 | "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz", 89 | "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==" 90 | }, 91 | "node_modules/@octokit/plugin-paginate-rest": { 92 | "version": "2.21.3", 93 | "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz", 94 | "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==", 95 | "dependencies": { 96 | "@octokit/types": "^6.40.0" 97 | }, 98 | "peerDependencies": { 99 | "@octokit/core": ">=2" 100 | } 101 | }, 102 | "node_modules/@octokit/plugin-rest-endpoint-methods": { 103 | "version": "5.16.2", 104 | "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz", 105 | "integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==", 106 | "dependencies": { 107 | "@octokit/types": "^6.39.0", 108 | "deprecation": "^2.3.1" 109 | }, 110 | "peerDependencies": { 111 | "@octokit/core": ">=3" 112 | } 113 | }, 114 | "node_modules/@octokit/request": { 115 | "version": "5.6.3", 116 | "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", 117 | "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", 118 | "dependencies": { 119 | "@octokit/endpoint": "^6.0.1", 120 | "@octokit/request-error": "^2.1.0", 121 | "@octokit/types": "^6.16.1", 122 | "is-plain-object": "^5.0.0", 123 | "node-fetch": "^2.6.7", 124 | "universal-user-agent": "^6.0.0" 125 | } 126 | }, 127 | "node_modules/@octokit/request-error": { 128 | "version": "2.1.0", 129 | "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", 130 | "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", 131 | "dependencies": { 132 | "@octokit/types": "^6.0.3", 133 | "deprecation": "^2.0.0", 134 | "once": "^1.4.0" 135 | } 136 | }, 137 | "node_modules/@octokit/types": { 138 | "version": "6.41.0", 139 | "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz", 140 | "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==", 141 | "dependencies": { 142 | "@octokit/openapi-types": "^12.11.0" 143 | } 144 | }, 145 | "node_modules/before-after-hook": { 146 | "version": "2.2.3", 147 | "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", 148 | "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" 149 | }, 150 | "node_modules/deprecation": { 151 | "version": "2.3.1", 152 | "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", 153 | "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" 154 | }, 155 | "node_modules/is-plain-object": { 156 | "version": "5.0.0", 157 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", 158 | "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", 159 | "engines": { 160 | "node": ">=0.10.0" 161 | } 162 | }, 163 | "node_modules/node-fetch": { 164 | "version": "2.6.11", 165 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", 166 | "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", 167 | "dependencies": { 168 | "whatwg-url": "^5.0.0" 169 | }, 170 | "engines": { 171 | "node": "4.x || >=6.0.0" 172 | }, 173 | "peerDependencies": { 174 | "encoding": "^0.1.0" 175 | }, 176 | "peerDependenciesMeta": { 177 | "encoding": { 178 | "optional": true 179 | } 180 | } 181 | }, 182 | "node_modules/once": { 183 | "version": "1.4.0", 184 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 185 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 186 | "dependencies": { 187 | "wrappy": "1" 188 | } 189 | }, 190 | "node_modules/tr46": { 191 | "version": "0.0.3", 192 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 193 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" 194 | }, 195 | "node_modules/tunnel": { 196 | "version": "0.0.6", 197 | "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", 198 | "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", 199 | "engines": { 200 | "node": ">=0.6.11 <=0.7.0 || >=0.7.3" 201 | } 202 | }, 203 | "node_modules/universal-user-agent": { 204 | "version": "6.0.0", 205 | "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", 206 | "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" 207 | }, 208 | "node_modules/uuid": { 209 | "version": "8.3.2", 210 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", 211 | "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", 212 | "bin": { 213 | "uuid": "dist/bin/uuid" 214 | } 215 | }, 216 | "node_modules/webidl-conversions": { 217 | "version": "3.0.1", 218 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 219 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" 220 | }, 221 | "node_modules/whatwg-url": { 222 | "version": "5.0.0", 223 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 224 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 225 | "dependencies": { 226 | "tr46": "~0.0.3", 227 | "webidl-conversions": "^3.0.0" 228 | } 229 | }, 230 | "node_modules/wrappy": { 231 | "version": "1.0.2", 232 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 233 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" 234 | } 235 | }, 236 | "dependencies": { 237 | "@actions/core": { 238 | "version": "1.10.0", 239 | "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", 240 | "integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", 241 | "requires": { 242 | "@actions/http-client": "^2.0.1", 243 | "uuid": "^8.3.2" 244 | } 245 | }, 246 | "@actions/github": { 247 | "version": "5.1.1", 248 | "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.1.tgz", 249 | "integrity": "sha512-Nk59rMDoJaV+mHCOJPXuvB1zIbomlKS0dmSIqPGxd0enAXBnOfn4VWF+CGtRCwXZG9Epa54tZA7VIRlJDS8A6g==", 250 | "requires": { 251 | "@actions/http-client": "^2.0.1", 252 | "@octokit/core": "^3.6.0", 253 | "@octokit/plugin-paginate-rest": "^2.17.0", 254 | "@octokit/plugin-rest-endpoint-methods": "^5.13.0" 255 | } 256 | }, 257 | "@actions/http-client": { 258 | "version": "2.1.0", 259 | "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.1.0.tgz", 260 | "integrity": "sha512-BonhODnXr3amchh4qkmjPMUO8mFi/zLaaCeCAJZqch8iQqyDnVIkySjB38VHAC8IJ+bnlgfOqlhpyCUZHlQsqw==", 261 | "requires": { 262 | "tunnel": "^0.0.6" 263 | } 264 | }, 265 | "@octokit/auth-token": { 266 | "version": "2.5.0", 267 | "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", 268 | "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", 269 | "requires": { 270 | "@octokit/types": "^6.0.3" 271 | } 272 | }, 273 | "@octokit/core": { 274 | "version": "3.6.0", 275 | "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", 276 | "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", 277 | "requires": { 278 | "@octokit/auth-token": "^2.4.4", 279 | "@octokit/graphql": "^4.5.8", 280 | "@octokit/request": "^5.6.3", 281 | "@octokit/request-error": "^2.0.5", 282 | "@octokit/types": "^6.0.3", 283 | "before-after-hook": "^2.2.0", 284 | "universal-user-agent": "^6.0.0" 285 | } 286 | }, 287 | "@octokit/endpoint": { 288 | "version": "6.0.12", 289 | "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", 290 | "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", 291 | "requires": { 292 | "@octokit/types": "^6.0.3", 293 | "is-plain-object": "^5.0.0", 294 | "universal-user-agent": "^6.0.0" 295 | } 296 | }, 297 | "@octokit/graphql": { 298 | "version": "4.8.0", 299 | "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", 300 | "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", 301 | "requires": { 302 | "@octokit/request": "^5.6.0", 303 | "@octokit/types": "^6.0.3", 304 | "universal-user-agent": "^6.0.0" 305 | } 306 | }, 307 | "@octokit/openapi-types": { 308 | "version": "12.11.0", 309 | "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz", 310 | "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==" 311 | }, 312 | "@octokit/plugin-paginate-rest": { 313 | "version": "2.21.3", 314 | "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz", 315 | "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==", 316 | "requires": { 317 | "@octokit/types": "^6.40.0" 318 | } 319 | }, 320 | "@octokit/plugin-rest-endpoint-methods": { 321 | "version": "5.16.2", 322 | "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz", 323 | "integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==", 324 | "requires": { 325 | "@octokit/types": "^6.39.0", 326 | "deprecation": "^2.3.1" 327 | } 328 | }, 329 | "@octokit/request": { 330 | "version": "5.6.3", 331 | "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", 332 | "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", 333 | "requires": { 334 | "@octokit/endpoint": "^6.0.1", 335 | "@octokit/request-error": "^2.1.0", 336 | "@octokit/types": "^6.16.1", 337 | "is-plain-object": "^5.0.0", 338 | "node-fetch": "^2.6.7", 339 | "universal-user-agent": "^6.0.0" 340 | } 341 | }, 342 | "@octokit/request-error": { 343 | "version": "2.1.0", 344 | "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", 345 | "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", 346 | "requires": { 347 | "@octokit/types": "^6.0.3", 348 | "deprecation": "^2.0.0", 349 | "once": "^1.4.0" 350 | } 351 | }, 352 | "@octokit/types": { 353 | "version": "6.41.0", 354 | "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz", 355 | "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==", 356 | "requires": { 357 | "@octokit/openapi-types": "^12.11.0" 358 | } 359 | }, 360 | "before-after-hook": { 361 | "version": "2.2.3", 362 | "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", 363 | "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" 364 | }, 365 | "deprecation": { 366 | "version": "2.3.1", 367 | "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", 368 | "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" 369 | }, 370 | "is-plain-object": { 371 | "version": "5.0.0", 372 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", 373 | "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" 374 | }, 375 | "node-fetch": { 376 | "version": "2.6.11", 377 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", 378 | "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", 379 | "requires": { 380 | "whatwg-url": "^5.0.0" 381 | } 382 | }, 383 | "once": { 384 | "version": "1.4.0", 385 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 386 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 387 | "requires": { 388 | "wrappy": "1" 389 | } 390 | }, 391 | "tr46": { 392 | "version": "0.0.3", 393 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 394 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" 395 | }, 396 | "tunnel": { 397 | "version": "0.0.6", 398 | "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", 399 | "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" 400 | }, 401 | "universal-user-agent": { 402 | "version": "6.0.0", 403 | "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", 404 | "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" 405 | }, 406 | "uuid": { 407 | "version": "8.3.2", 408 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", 409 | "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" 410 | }, 411 | "webidl-conversions": { 412 | "version": "3.0.1", 413 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 414 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" 415 | }, 416 | "whatwg-url": { 417 | "version": "5.0.0", 418 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 419 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 420 | "requires": { 421 | "tr46": "~0.0.3", 422 | "webidl-conversions": "^3.0.0" 423 | } 424 | }, 425 | "wrappy": { 426 | "version": "1.0.2", 427 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 428 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" 429 | } 430 | } 431 | } 432 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "actions-workflow-queue", 4 | "version": "0.0.0-semantically-released", 5 | "description": "wait for all `workflow_run` required workflows to be successful", 6 | "author": { 7 | "name": "Ahmad Nassri", 8 | "email": "ahmad@ahmadnassri.com", 9 | "url": "https://ahmadnassri.com" 10 | }, 11 | "scripts": { 12 | "test": "echo nothing to test && exit 0", 13 | "test:ci": "echo nothing to test && exit 0" 14 | }, 15 | "type": "module", 16 | "main": "index.js", 17 | "license": "MIT", 18 | "dependencies": { 19 | "@actions/core": "^1.10.0", 20 | "@actions/github": "^5.1.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | // node modules 2 | import { inspect } from 'util' 3 | 4 | // packages 5 | import core from '@actions/core' 6 | 7 | // modules 8 | import main from './lib/index.js' 9 | 10 | // parse inputs 11 | const inputs = { 12 | token: core.getInput('github-token', { required: true }), 13 | delay: Number(core.getInput('delay', { required: true })), 14 | timeout: Number(core.getInput('timeout', { required: true })) 15 | } 16 | 17 | // error handler 18 | function errorHandler ({ message, stack, request }) { 19 | core.error(`${message}\n${stack}`) 20 | 21 | // debugging for API calls 22 | if (request) { 23 | const { method, url, body, headers } = request 24 | core.debug(`${method} ${url}\n\n${inspect(headers)}\n\n${inspect(body)}`) 25 | } 26 | 27 | process.exit(1) 28 | } 29 | 30 | // catch errors and exit 31 | process.on('unhandledRejection', errorHandler) 32 | process.on('uncaughtException', errorHandler) 33 | 34 | await main(inputs) 35 | -------------------------------------------------------------------------------- /src/lib/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | 3 | // packages 4 | import core from '@actions/core' 5 | import github from '@actions/github' 6 | 7 | // modules 8 | import runs from './runs.js' 9 | 10 | // sleep function 11 | const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)) 12 | 13 | export default async function ({ token, delay, timeout }) { 14 | let timer = 0 15 | 16 | // init octokit 17 | const octokit = github.getOctokit(token) 18 | 19 | // extract runId 20 | const { runId: run_id } = github.context 21 | 22 | // get workflow id and created date from run id 23 | const { data: { workflow_id, run_started_at } } = await octokit.request('GET /repos/{owner}/{repo}/actions/runs/{run_id}', { 24 | ...github.context.repo, 25 | run_id 26 | }) 27 | 28 | // date to check against 29 | const before = new Date(run_started_at) 30 | 31 | core.info(`searching for workflow runs before ${before}`) 32 | 33 | // get previous runs 34 | let waiting_for = await runs({ octokit, run_id, workflow_id, before }) 35 | 36 | if (waiting_for.length === 0) { 37 | core.info('no active run of this workflow found') 38 | process.exit(0) 39 | } 40 | 41 | // if one of them is not completed 42 | while (waiting_for.find(run => run.status !== 'completed')) { 43 | timer += delay 44 | 45 | // time out! 46 | if (timer >= timeout) { 47 | core.setFailed('workflow-queue timed out') 48 | process.exit(1) 49 | } 50 | 51 | for (const run of waiting_for) { 52 | core.info(`waiting for run #${run.id}: current status: ${run.status}`) 53 | } 54 | 55 | // zzz 56 | core.info(`waiting for #${delay/1000} minutes before polling the status again`) 57 | await sleep(delay) 58 | 59 | // get the data again 60 | waiting_for = await runs({ octokit, run_id, workflow_id, before }) 61 | } 62 | 63 | core.info('all runs in the queue completed!') 64 | } 65 | -------------------------------------------------------------------------------- /src/lib/runs.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | 3 | // node modules 4 | import { inspect } from 'util' 5 | 6 | // packages 7 | import core from '@actions/core' 8 | import github from '@actions/github' 9 | 10 | export default async function ({ octokit, workflow_id, run_id, before }) { 11 | // get current run of this workflow 12 | const { data: { workflow_runs } } = await octokit.request('GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs', { 13 | ...github.context.repo, 14 | workflow_id 15 | }) 16 | 17 | // find any instances of the same workflow 18 | const waiting_for = workflow_runs 19 | // limit to currently running ones 20 | .filter(run => ['in_progress', 'queued', 'waiting', 'pending', 'action_required', 'requested'].includes(run.status)) 21 | // exclude this one 22 | .filter(run => run.id !== run_id) 23 | // get older runs 24 | .filter(run => new Date(run.run_started_at) < before) 25 | 26 | core.info(`found ${waiting_for.length} workflow runs`) 27 | core.debug(inspect(waiting_for.map(run => ({ id: run.id, name: run.name })))) 28 | 29 | return waiting_for 30 | } 31 | -------------------------------------------------------------------------------- /test/fixtures/payload.json: -------------------------------------------------------------------------------- 1 | { 2 | "action": "opened", 3 | "number": 2, 4 | "pull_request": { 5 | "url": "https://api.github.com/repos/Codertocat/Hello-World/pulls/2", 6 | "id": 279147437, 7 | "node_id": "MDExOlB1bGxSZXF1ZXN0Mjc5MTQ3NDM3", 8 | "html_url": "https://github.com/Codertocat/Hello-World/pull/2", 9 | "diff_url": "https://github.com/Codertocat/Hello-World/pull/2.diff", 10 | "patch_url": "https://github.com/Codertocat/Hello-World/pull/2.patch", 11 | "issue_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/2", 12 | "number": 2, 13 | "state": "open", 14 | "locked": false, 15 | "title": "Update the README with new information.", 16 | "user": { 17 | "login": "Codertocat", 18 | "id": 21031067, 19 | "node_id": "MDQ6VXNlcjIxMDMxMDY3", 20 | "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", 21 | "gravatar_id": "", 22 | "url": "https://api.github.com/users/Codertocat", 23 | "html_url": "https://github.com/Codertocat", 24 | "followers_url": "https://api.github.com/users/Codertocat/followers", 25 | "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", 26 | "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", 27 | "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", 28 | "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", 29 | "organizations_url": "https://api.github.com/users/Codertocat/orgs", 30 | "repos_url": "https://api.github.com/users/Codertocat/repos", 31 | "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", 32 | "received_events_url": "https://api.github.com/users/Codertocat/received_events", 33 | "type": "User", 34 | "site_admin": false 35 | }, 36 | "body": "This is a pretty simple change that we need to pull into master.", 37 | "created_at": "2019-05-15T15:20:33Z", 38 | "updated_at": "2019-05-15T15:20:33Z", 39 | "closed_at": null, 40 | "merged_at": null, 41 | "merge_commit_sha": null, 42 | "assignee": null, 43 | "assignees": [ 44 | { 45 | "login": "Codertocat", 46 | "id": 21031067, 47 | "node_id": "MDQ6VXNlcjIxMDMxMDY3", 48 | "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", 49 | "gravatar_id": "", 50 | "url": "https://api.github.com/users/Codertocat", 51 | "html_url": "https://github.com/Codertocat", 52 | "followers_url": "https://api.github.com/users/Codertocat/followers", 53 | "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", 54 | "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", 55 | "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", 56 | "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", 57 | "organizations_url": "https://api.github.com/users/Codertocat/orgs", 58 | "repos_url": "https://api.github.com/users/Codertocat/repos", 59 | "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", 60 | "received_events_url": "https://api.github.com/users/Codertocat/received_events", 61 | "type": "User", 62 | "site_admin": false 63 | } 64 | ], 65 | "requested_reviewers": [ 66 | { 67 | "login": "octocat", 68 | "id": 5346, 69 | "node_id": "MDQ6VXNlcjIxMDMxMDY3", 70 | "avatar_url": "http://alambic.github.com/avatars/u/5346?", 71 | "gravatar_id": "", 72 | "url": "https://api.github.com/users/octocat", 73 | "html_url": "http://github.com/octocat", 74 | "followers_url": "https://api.github.com/users/octocat/followers", 75 | "following_url": "https://api.github.com/users/octocat/following{/other_user}", 76 | "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", 77 | "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", 78 | "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", 79 | "organizations_url": "https://api.github.com/users/octocat/orgs", 80 | "repos_url": "https://api.github.com/users/octocat/repos", 81 | "events_url": "https://api.github.com/users/octocat/events{/privacy}", 82 | "received_events_url": "https://api.github.com/users/octocat/received_events", 83 | "type": "User", 84 | "site_admin": false 85 | } 86 | ], 87 | "requested_teams": [], 88 | "labels": [ 89 | { 90 | "id": 1362934389, 91 | "node_id": "MDU6TGFiZWwxMzYyOTM0Mzg5", 92 | "url": "https://api.github.com/repos/Codertocat/Hello-World/labels/bug", 93 | "name": "bug", 94 | "color": "d73a4a", 95 | "default": true, 96 | "description": "Something isn't working" 97 | } 98 | ], 99 | "milestone": null, 100 | "commits_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls/2/commits", 101 | "review_comments_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls/2/comments", 102 | "review_comment_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls/comments{/number}", 103 | "comments_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/2/comments", 104 | "statuses_url": "https://api.github.com/repos/Codertocat/Hello-World/statuses/ec26c3e57ca3a959ca5aad62de7213c562f8c821", 105 | "head": { 106 | "label": "Codertocat:changes", 107 | "ref": "changes", 108 | "sha": "ec26c3e57ca3a959ca5aad62de7213c562f8c821", 109 | "user": { 110 | "login": "Codertocat", 111 | "id": 21031067, 112 | "node_id": "MDQ6VXNlcjIxMDMxMDY3", 113 | "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", 114 | "gravatar_id": "", 115 | "url": "https://api.github.com/users/Codertocat", 116 | "html_url": "https://github.com/Codertocat", 117 | "followers_url": "https://api.github.com/users/Codertocat/followers", 118 | "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", 119 | "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", 120 | "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", 121 | "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", 122 | "organizations_url": "https://api.github.com/users/Codertocat/orgs", 123 | "repos_url": "https://api.github.com/users/Codertocat/repos", 124 | "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", 125 | "received_events_url": "https://api.github.com/users/Codertocat/received_events", 126 | "type": "User", 127 | "site_admin": false 128 | }, 129 | "repo": { 130 | "id": 186853002, 131 | "node_id": "MDEwOlJlcG9zaXRvcnkxODY4NTMwMDI=", 132 | "name": "Hello-World", 133 | "full_name": "Codertocat/Hello-World", 134 | "private": false, 135 | "owner": { 136 | "login": "Codertocat", 137 | "id": 21031067, 138 | "node_id": "MDQ6VXNlcjIxMDMxMDY3", 139 | "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", 140 | "gravatar_id": "", 141 | "url": "https://api.github.com/users/Codertocat", 142 | "html_url": "https://github.com/Codertocat", 143 | "followers_url": "https://api.github.com/users/Codertocat/followers", 144 | "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", 145 | "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", 146 | "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", 147 | "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", 148 | "organizations_url": "https://api.github.com/users/Codertocat/orgs", 149 | "repos_url": "https://api.github.com/users/Codertocat/repos", 150 | "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", 151 | "received_events_url": "https://api.github.com/users/Codertocat/received_events", 152 | "type": "User", 153 | "site_admin": false 154 | }, 155 | "html_url": "https://github.com/Codertocat/Hello-World", 156 | "description": null, 157 | "fork": false, 158 | "url": "https://api.github.com/repos/Codertocat/Hello-World", 159 | "forks_url": "https://api.github.com/repos/Codertocat/Hello-World/forks", 160 | "keys_url": "https://api.github.com/repos/Codertocat/Hello-World/keys{/key_id}", 161 | "collaborators_url": "https://api.github.com/repos/Codertocat/Hello-World/collaborators{/collaborator}", 162 | "teams_url": "https://api.github.com/repos/Codertocat/Hello-World/teams", 163 | "hooks_url": "https://api.github.com/repos/Codertocat/Hello-World/hooks", 164 | "issue_events_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/events{/number}", 165 | "events_url": "https://api.github.com/repos/Codertocat/Hello-World/events", 166 | "assignees_url": "https://api.github.com/repos/Codertocat/Hello-World/assignees{/user}", 167 | "branches_url": "https://api.github.com/repos/Codertocat/Hello-World/branches{/branch}", 168 | "tags_url": "https://api.github.com/repos/Codertocat/Hello-World/tags", 169 | "blobs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/blobs{/sha}", 170 | "git_tags_url": "https://api.github.com/repos/Codertocat/Hello-World/git/tags{/sha}", 171 | "git_refs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/refs{/sha}", 172 | "trees_url": "https://api.github.com/repos/Codertocat/Hello-World/git/trees{/sha}", 173 | "statuses_url": "https://api.github.com/repos/Codertocat/Hello-World/statuses/{sha}", 174 | "languages_url": "https://api.github.com/repos/Codertocat/Hello-World/languages", 175 | "stargazers_url": "https://api.github.com/repos/Codertocat/Hello-World/stargazers", 176 | "contributors_url": "https://api.github.com/repos/Codertocat/Hello-World/contributors", 177 | "subscribers_url": "https://api.github.com/repos/Codertocat/Hello-World/subscribers", 178 | "subscription_url": "https://api.github.com/repos/Codertocat/Hello-World/subscription", 179 | "commits_url": "https://api.github.com/repos/Codertocat/Hello-World/commits{/sha}", 180 | "git_commits_url": "https://api.github.com/repos/Codertocat/Hello-World/git/commits{/sha}", 181 | "comments_url": "https://api.github.com/repos/Codertocat/Hello-World/comments{/number}", 182 | "issue_comment_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/comments{/number}", 183 | "contents_url": "https://api.github.com/repos/Codertocat/Hello-World/contents/{+path}", 184 | "compare_url": "https://api.github.com/repos/Codertocat/Hello-World/compare/{base}...{head}", 185 | "merges_url": "https://api.github.com/repos/Codertocat/Hello-World/merges", 186 | "archive_url": "https://api.github.com/repos/Codertocat/Hello-World/{archive_format}{/ref}", 187 | "downloads_url": "https://api.github.com/repos/Codertocat/Hello-World/downloads", 188 | "issues_url": "https://api.github.com/repos/Codertocat/Hello-World/issues{/number}", 189 | "pulls_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls{/number}", 190 | "milestones_url": "https://api.github.com/repos/Codertocat/Hello-World/milestones{/number}", 191 | "notifications_url": "https://api.github.com/repos/Codertocat/Hello-World/notifications{?since,all,participating}", 192 | "labels_url": "https://api.github.com/repos/Codertocat/Hello-World/labels{/name}", 193 | "releases_url": "https://api.github.com/repos/Codertocat/Hello-World/releases{/id}", 194 | "deployments_url": "https://api.github.com/repos/Codertocat/Hello-World/deployments", 195 | "created_at": "2019-05-15T15:19:25Z", 196 | "updated_at": "2019-05-15T15:19:27Z", 197 | "pushed_at": "2019-05-15T15:20:32Z", 198 | "git_url": "git://github.com/Codertocat/Hello-World.git", 199 | "ssh_url": "git@github.com:Codertocat/Hello-World.git", 200 | "clone_url": "https://github.com/Codertocat/Hello-World.git", 201 | "svn_url": "https://github.com/Codertocat/Hello-World", 202 | "homepage": null, 203 | "size": 0, 204 | "stargazers_count": 0, 205 | "watchers_count": 0, 206 | "language": null, 207 | "has_issues": true, 208 | "has_projects": true, 209 | "has_downloads": true, 210 | "has_wiki": true, 211 | "has_pages": true, 212 | "forks_count": 0, 213 | "mirror_url": null, 214 | "archived": false, 215 | "disabled": false, 216 | "open_issues_count": 2, 217 | "license": null, 218 | "forks": 0, 219 | "open_issues": 2, 220 | "watchers": 0, 221 | "default_branch": "master", 222 | "is_template": false, 223 | "topics": [], 224 | "visibility": "public", 225 | "web_commit_signoff_required": false 226 | } 227 | }, 228 | "base": { 229 | "label": "Codertocat:master", 230 | "ref": "master", 231 | "sha": "f95f852bd8fca8fcc58a9a2d6c842781e32a215e", 232 | "user": { 233 | "login": "Codertocat", 234 | "id": 21031067, 235 | "node_id": "MDQ6VXNlcjIxMDMxMDY3", 236 | "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", 237 | "gravatar_id": "", 238 | "url": "https://api.github.com/users/Codertocat", 239 | "html_url": "https://github.com/Codertocat", 240 | "followers_url": "https://api.github.com/users/Codertocat/followers", 241 | "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", 242 | "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", 243 | "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", 244 | "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", 245 | "organizations_url": "https://api.github.com/users/Codertocat/orgs", 246 | "repos_url": "https://api.github.com/users/Codertocat/repos", 247 | "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", 248 | "received_events_url": "https://api.github.com/users/Codertocat/received_events", 249 | "type": "User", 250 | "site_admin": false 251 | }, 252 | "repo": { 253 | "id": 186853002, 254 | "node_id": "MDEwOlJlcG9zaXRvcnkxODY4NTMwMDI=", 255 | "name": "Hello-World", 256 | "full_name": "Codertocat/Hello-World", 257 | "private": false, 258 | "owner": { 259 | "login": "Codertocat", 260 | "id": 21031067, 261 | "node_id": "MDQ6VXNlcjIxMDMxMDY3", 262 | "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", 263 | "gravatar_id": "", 264 | "url": "https://api.github.com/users/Codertocat", 265 | "html_url": "https://github.com/Codertocat", 266 | "followers_url": "https://api.github.com/users/Codertocat/followers", 267 | "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", 268 | "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", 269 | "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", 270 | "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", 271 | "organizations_url": "https://api.github.com/users/Codertocat/orgs", 272 | "repos_url": "https://api.github.com/users/Codertocat/repos", 273 | "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", 274 | "received_events_url": "https://api.github.com/users/Codertocat/received_events", 275 | "type": "User", 276 | "site_admin": false 277 | }, 278 | "html_url": "https://github.com/Codertocat/Hello-World", 279 | "description": null, 280 | "fork": false, 281 | "url": "https://api.github.com/repos/Codertocat/Hello-World", 282 | "forks_url": "https://api.github.com/repos/Codertocat/Hello-World/forks", 283 | "keys_url": "https://api.github.com/repos/Codertocat/Hello-World/keys{/key_id}", 284 | "collaborators_url": "https://api.github.com/repos/Codertocat/Hello-World/collaborators{/collaborator}", 285 | "teams_url": "https://api.github.com/repos/Codertocat/Hello-World/teams", 286 | "hooks_url": "https://api.github.com/repos/Codertocat/Hello-World/hooks", 287 | "issue_events_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/events{/number}", 288 | "events_url": "https://api.github.com/repos/Codertocat/Hello-World/events", 289 | "assignees_url": "https://api.github.com/repos/Codertocat/Hello-World/assignees{/user}", 290 | "branches_url": "https://api.github.com/repos/Codertocat/Hello-World/branches{/branch}", 291 | "tags_url": "https://api.github.com/repos/Codertocat/Hello-World/tags", 292 | "blobs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/blobs{/sha}", 293 | "git_tags_url": "https://api.github.com/repos/Codertocat/Hello-World/git/tags{/sha}", 294 | "git_refs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/refs{/sha}", 295 | "trees_url": "https://api.github.com/repos/Codertocat/Hello-World/git/trees{/sha}", 296 | "statuses_url": "https://api.github.com/repos/Codertocat/Hello-World/statuses/{sha}", 297 | "languages_url": "https://api.github.com/repos/Codertocat/Hello-World/languages", 298 | "stargazers_url": "https://api.github.com/repos/Codertocat/Hello-World/stargazers", 299 | "contributors_url": "https://api.github.com/repos/Codertocat/Hello-World/contributors", 300 | "subscribers_url": "https://api.github.com/repos/Codertocat/Hello-World/subscribers", 301 | "subscription_url": "https://api.github.com/repos/Codertocat/Hello-World/subscription", 302 | "commits_url": "https://api.github.com/repos/Codertocat/Hello-World/commits{/sha}", 303 | "git_commits_url": "https://api.github.com/repos/Codertocat/Hello-World/git/commits{/sha}", 304 | "comments_url": "https://api.github.com/repos/Codertocat/Hello-World/comments{/number}", 305 | "issue_comment_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/comments{/number}", 306 | "contents_url": "https://api.github.com/repos/Codertocat/Hello-World/contents/{+path}", 307 | "compare_url": "https://api.github.com/repos/Codertocat/Hello-World/compare/{base}...{head}", 308 | "merges_url": "https://api.github.com/repos/Codertocat/Hello-World/merges", 309 | "archive_url": "https://api.github.com/repos/Codertocat/Hello-World/{archive_format}{/ref}", 310 | "downloads_url": "https://api.github.com/repos/Codertocat/Hello-World/downloads", 311 | "issues_url": "https://api.github.com/repos/Codertocat/Hello-World/issues{/number}", 312 | "pulls_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls{/number}", 313 | "milestones_url": "https://api.github.com/repos/Codertocat/Hello-World/milestones{/number}", 314 | "notifications_url": "https://api.github.com/repos/Codertocat/Hello-World/notifications{?since,all,participating}", 315 | "labels_url": "https://api.github.com/repos/Codertocat/Hello-World/labels{/name}", 316 | "releases_url": "https://api.github.com/repos/Codertocat/Hello-World/releases{/id}", 317 | "deployments_url": "https://api.github.com/repos/Codertocat/Hello-World/deployments", 318 | "created_at": "2019-05-15T15:19:25Z", 319 | "updated_at": "2019-05-15T15:19:27Z", 320 | "pushed_at": "2019-05-15T15:20:32Z", 321 | "git_url": "git://github.com/Codertocat/Hello-World.git", 322 | "ssh_url": "git@github.com:Codertocat/Hello-World.git", 323 | "clone_url": "https://github.com/Codertocat/Hello-World.git", 324 | "svn_url": "https://github.com/Codertocat/Hello-World", 325 | "homepage": null, 326 | "size": 0, 327 | "stargazers_count": 0, 328 | "watchers_count": 0, 329 | "language": null, 330 | "has_issues": true, 331 | "has_projects": true, 332 | "has_downloads": true, 333 | "has_wiki": true, 334 | "has_pages": true, 335 | "forks_count": 0, 336 | "mirror_url": null, 337 | "archived": false, 338 | "disabled": false, 339 | "open_issues_count": 2, 340 | "license": null, 341 | "forks": 0, 342 | "open_issues": 2, 343 | "watchers": 0, 344 | "default_branch": "master", 345 | "is_template": false, 346 | "topics": [], 347 | "visibility": "public", 348 | "web_commit_signoff_required": false 349 | } 350 | }, 351 | "_links": { 352 | "self": { 353 | "href": "https://api.github.com/repos/Codertocat/Hello-World/pulls/2" 354 | }, 355 | "html": { "href": "https://github.com/Codertocat/Hello-World/pull/2" }, 356 | "issue": { 357 | "href": "https://api.github.com/repos/Codertocat/Hello-World/issues/2" 358 | }, 359 | "comments": { 360 | "href": "https://api.github.com/repos/Codertocat/Hello-World/issues/2/comments" 361 | }, 362 | "review_comments": { 363 | "href": "https://api.github.com/repos/Codertocat/Hello-World/pulls/2/comments" 364 | }, 365 | "review_comment": { 366 | "href": "https://api.github.com/repos/Codertocat/Hello-World/pulls/comments{/number}" 367 | }, 368 | "commits": { 369 | "href": "https://api.github.com/repos/Codertocat/Hello-World/pulls/2/commits" 370 | }, 371 | "statuses": { 372 | "href": "https://api.github.com/repos/Codertocat/Hello-World/statuses/ec26c3e57ca3a959ca5aad62de7213c562f8c821" 373 | } 374 | }, 375 | "author_association": "OWNER", 376 | "auto_merge": null, 377 | "active_lock_reason": null, 378 | "draft": false, 379 | "merged": false, 380 | "mergeable": null, 381 | "rebaseable": null, 382 | "mergeable_state": "unknown", 383 | "merged_by": null, 384 | "comments": 0, 385 | "review_comments": 0, 386 | "maintainer_can_modify": false, 387 | "commits": 1, 388 | "additions": 1, 389 | "deletions": 1, 390 | "changed_files": 1 391 | }, 392 | "repository": { 393 | "id": 186853002, 394 | "node_id": "MDEwOlJlcG9zaXRvcnkxODY4NTMwMDI=", 395 | "name": "Hello-World", 396 | "full_name": "Codertocat/Hello-World", 397 | "private": false, 398 | "owner": { 399 | "login": "Codertocat", 400 | "id": 21031067, 401 | "node_id": "MDQ6VXNlcjIxMDMxMDY3", 402 | "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", 403 | "gravatar_id": "", 404 | "url": "https://api.github.com/users/Codertocat", 405 | "html_url": "https://github.com/Codertocat", 406 | "followers_url": "https://api.github.com/users/Codertocat/followers", 407 | "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", 408 | "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", 409 | "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", 410 | "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", 411 | "organizations_url": "https://api.github.com/users/Codertocat/orgs", 412 | "repos_url": "https://api.github.com/users/Codertocat/repos", 413 | "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", 414 | "received_events_url": "https://api.github.com/users/Codertocat/received_events", 415 | "type": "User", 416 | "site_admin": false 417 | }, 418 | "html_url": "https://github.com/Codertocat/Hello-World", 419 | "description": null, 420 | "fork": false, 421 | "url": "https://api.github.com/repos/Codertocat/Hello-World", 422 | "forks_url": "https://api.github.com/repos/Codertocat/Hello-World/forks", 423 | "keys_url": "https://api.github.com/repos/Codertocat/Hello-World/keys{/key_id}", 424 | "collaborators_url": "https://api.github.com/repos/Codertocat/Hello-World/collaborators{/collaborator}", 425 | "teams_url": "https://api.github.com/repos/Codertocat/Hello-World/teams", 426 | "hooks_url": "https://api.github.com/repos/Codertocat/Hello-World/hooks", 427 | "issue_events_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/events{/number}", 428 | "events_url": "https://api.github.com/repos/Codertocat/Hello-World/events", 429 | "assignees_url": "https://api.github.com/repos/Codertocat/Hello-World/assignees{/user}", 430 | "branches_url": "https://api.github.com/repos/Codertocat/Hello-World/branches{/branch}", 431 | "tags_url": "https://api.github.com/repos/Codertocat/Hello-World/tags", 432 | "blobs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/blobs{/sha}", 433 | "git_tags_url": "https://api.github.com/repos/Codertocat/Hello-World/git/tags{/sha}", 434 | "git_refs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/refs{/sha}", 435 | "trees_url": "https://api.github.com/repos/Codertocat/Hello-World/git/trees{/sha}", 436 | "statuses_url": "https://api.github.com/repos/Codertocat/Hello-World/statuses/{sha}", 437 | "languages_url": "https://api.github.com/repos/Codertocat/Hello-World/languages", 438 | "stargazers_url": "https://api.github.com/repos/Codertocat/Hello-World/stargazers", 439 | "contributors_url": "https://api.github.com/repos/Codertocat/Hello-World/contributors", 440 | "subscribers_url": "https://api.github.com/repos/Codertocat/Hello-World/subscribers", 441 | "subscription_url": "https://api.github.com/repos/Codertocat/Hello-World/subscription", 442 | "commits_url": "https://api.github.com/repos/Codertocat/Hello-World/commits{/sha}", 443 | "git_commits_url": "https://api.github.com/repos/Codertocat/Hello-World/git/commits{/sha}", 444 | "comments_url": "https://api.github.com/repos/Codertocat/Hello-World/comments{/number}", 445 | "issue_comment_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/comments{/number}", 446 | "contents_url": "https://api.github.com/repos/Codertocat/Hello-World/contents/{+path}", 447 | "compare_url": "https://api.github.com/repos/Codertocat/Hello-World/compare/{base}...{head}", 448 | "merges_url": "https://api.github.com/repos/Codertocat/Hello-World/merges", 449 | "archive_url": "https://api.github.com/repos/Codertocat/Hello-World/{archive_format}{/ref}", 450 | "downloads_url": "https://api.github.com/repos/Codertocat/Hello-World/downloads", 451 | "issues_url": "https://api.github.com/repos/Codertocat/Hello-World/issues{/number}", 452 | "pulls_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls{/number}", 453 | "milestones_url": "https://api.github.com/repos/Codertocat/Hello-World/milestones{/number}", 454 | "notifications_url": "https://api.github.com/repos/Codertocat/Hello-World/notifications{?since,all,participating}", 455 | "labels_url": "https://api.github.com/repos/Codertocat/Hello-World/labels{/name}", 456 | "releases_url": "https://api.github.com/repos/Codertocat/Hello-World/releases{/id}", 457 | "deployments_url": "https://api.github.com/repos/Codertocat/Hello-World/deployments", 458 | "created_at": "2019-05-15T15:19:25Z", 459 | "updated_at": "2019-05-15T15:19:27Z", 460 | "pushed_at": "2019-05-15T15:20:32Z", 461 | "git_url": "git://github.com/Codertocat/Hello-World.git", 462 | "ssh_url": "git@github.com:Codertocat/Hello-World.git", 463 | "clone_url": "https://github.com/Codertocat/Hello-World.git", 464 | "svn_url": "https://github.com/Codertocat/Hello-World", 465 | "homepage": null, 466 | "size": 0, 467 | "stargazers_count": 0, 468 | "watchers_count": 0, 469 | "language": null, 470 | "has_issues": true, 471 | "has_projects": true, 472 | "has_downloads": true, 473 | "has_wiki": true, 474 | "has_pages": true, 475 | "forks_count": 0, 476 | "mirror_url": null, 477 | "archived": false, 478 | "disabled": false, 479 | "open_issues_count": 2, 480 | "license": null, 481 | "forks": 0, 482 | "open_issues": 2, 483 | "watchers": 0, 484 | "default_branch": "master", 485 | "is_template": false, 486 | "topics": [], 487 | "visibility": "public", 488 | "web_commit_signoff_required": false 489 | }, 490 | "installation": { 491 | "id": 1, 492 | "node_id": "MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMQ==" 493 | }, 494 | "sender": { 495 | "login": "Codertocat", 496 | "id": 21031067, 497 | "node_id": "MDQ6VXNlcjIxMDMxMDY3", 498 | "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", 499 | "gravatar_id": "", 500 | "url": "https://api.github.com/users/Codertocat", 501 | "html_url": "https://github.com/Codertocat", 502 | "followers_url": "https://api.github.com/users/Codertocat/followers", 503 | "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", 504 | "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", 505 | "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", 506 | "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", 507 | "organizations_url": "https://api.github.com/users/Codertocat/orgs", 508 | "repos_url": "https://api.github.com/users/Codertocat/repos", 509 | "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", 510 | "received_events_url": "https://api.github.com/users/Codertocat/received_events", 511 | "type": "User", 512 | "site_admin": false 513 | } 514 | } 515 | --------------------------------------------------------------------------------