Skip to content

Add script to run CI workflows (tests and linting) locally#11

Merged
gensyn merged 7 commits intomainfrom
copilot/run-github-actions-locally
Mar 25, 2026
Merged

Add script to run CI workflows (tests and linting) locally#11
gensyn merged 7 commits intomainfrom
copilot/run-github-actions-locally

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 23, 2026

No existing way to run the repository's CI workflows locally before pushing.

Changes

  • run_workflows_locally.sh – new executable script at the repo root that:
    • Auto-installs Docker (via get.docker.com) and act (via the official install script) if not already present (Linux only)
    • All Docker daemon interactions and act invocations use sudo
    • Starts the Docker daemon if it isn't running
    • Runs test.yml, pylint.yml, and integration-tests.yml with the push event trigger against the catthehacker/ubuntu:act-latest image
    • Workflows that depend on GitHub infrastructure (hassfest.yaml, validate.yaml, release.yaml) are silently omitted as they cannot run meaningfully offline
    • Prints a colour-coded pass/fail summary
    • Takes no arguments

Usage

./run_workflows_locally.sh

📍 Connect Copilot coding agent with Jira, Azure Boards or Linear to delegate work to Copilot in one click without leaving your project management tool.

Copilot AI changed the title [WIP] Add Bash script to run GitHub workflows locally Add script to run all GitHub Actions workflows locally Mar 23, 2026
Copilot AI requested a review from gensyn March 23, 2026 11:06
@gensyn
Copy link
Copy Markdown
Owner

gensyn commented Mar 25, 2026

@copilot Please remove the support for MacOS - there is no plan to use it.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 25, 2026

@copilot Please remove the support for MacOS - there is no plan to use it.

Done. Removed all macOS-specific code (os_type() helper, Homebrew/Docker Desktop branches, and the Docker daemon wait loop). The script is now Linux-only. Commit: c24c1e1

@gensyn
Copy link
Copy Markdown
Owner

gensyn commented Mar 25, 2026

@copilot The installation of docker requires sudo docker to be used, so currently commands like docker info fail, even though docker is running.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 25, 2026

@copilot The installation of docker requires sudo docker to be used, so currently commands like docker info fail, even though docker is running.

Fixed in 7f49ae7. All calls that communicate with the Docker daemon (docker --version, docker info) and the act invocation are now prefixed with sudo.

@gensyn
Copy link
Copy Markdown
Owner

gensyn commented Mar 25, 2026

@copilot Two actions fail locally while they succeed on GitHub:

[INFO]  Running [hassfest.yaml] with event 'push'…
INFO[0000] Using docker host 'unix:///var/run/docker.sock', and daemon socket 'unix:///var/run/docker.sock' 
[Validate with hassfest/validate] ⭐ Run Set up job
[Validate with hassfest/validate] 🚀  Start image=catthehacker/ubuntu:act-latest
[Validate with hassfest/validate]   🐳  docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true
[Validate with hassfest/validate]   🐳  docker create image=catthehacker/ubuntu:act-latest platform= entrypoint=["tail" "-f" "/dev/null"] cmd=[] network="host"
[Validate with hassfest/validate]   🐳  docker run image=catthehacker/ubuntu:act-latest platform= entrypoint=["tail" "-f" "/dev/null"] cmd=[] network="host"
[Validate with hassfest/validate]   🐳  docker exec cmd=[node --no-warnings -e console.log(process.execPath)] user= workdir=
[Validate with hassfest/validate]   ✅  Success - Set up job
[Validate with hassfest/validate]   ☁  git clone 'https://github.com/home-assistant/actions' # ref=master
[Validate with hassfest/validate] ⭐ Run Pre Run hassfest
[Validate with hassfest/validate]   ✅  Success - Pre Run hassfest [67.029747ms]
[Validate with hassfest/validate] ⭐ Run Main Check out repository
[Validate with hassfest/validate]   🐳  docker cp src=/media/christoph/Projekte/PyCharm/core/config/custom_components/ssh_command/. dst=/media/christoph/Projekte/PyCharm/core/config/custom_components/ssh_command
[Validate with hassfest/validate]   ✅  Success - Main Check out repository [621.296888ms]
[Validate with hassfest/validate] ⭐ Run Main Move files to where hassfest expects them
[Validate with hassfest/validate]   🐳  docker exec cmd=[bash -e /var/run/act/workflow/1] user= workdir=
[Validate with hassfest/validate]   ✅  Success - Main Move files to where hassfest expects them [135.541823ms]
[Validate with hassfest/validate] ⭐ Run Main Run hassfest
[Validate with hassfest/validate]   🐳  docker cp src=/root/.cache/act/home-assistant-actions-hassfest@master/ dst=/var/run/act/actions/home-assistant-actions-hassfest@master/
[Validate with hassfest/validate] ⭐ Run Main echo "::add-matcher::/var/run/act/actions/home-assistant-actions-hassfest@master/hassfest/problem-matcher.json"
[Validate with hassfest/validate]   🐳  docker exec cmd=[bash --noprofile --norc -e -o pipefail /var/run/act/workflow/2-composite-0.sh] user= workdir=
[Validate with hassfest/validate]   ❓ add-matcher /var/run/act/actions/home-assistant-actions-hassfest@master/hassfest/problem-matcher.json
[Validate with hassfest/validate]   ✅  Success - Main echo "::add-matcher::/var/run/act/actions/home-assistant-actions-hassfest@master/hassfest/problem-matcher.json" [110.572404ms]
[Validate with hassfest/validate] ⭐ Run Main docker run --rm -v /media/christoph/Projekte/PyCharm/core/config/custom_components/ssh_command://github/workspace ghcr.io/home-assistant/hassfest
[Validate with hassfest/validate]   🐳  docker exec cmd=[bash --noprofile --norc -e -o pipefail /var/run/act/workflow/2-composite-1.sh] user= workdir=
| Unable to find image 'ghcr.io/home-assistant/hassfest:latest' locally
| latest: Pulling from home-assistant/hassfest
0e816cd12c97: Pull complete 
3566efde290b: Pull complete 
589002ba0eae: Pull complete 
0805a1082be0: Pull complete 
184fc4e8734c: Pull complete 
2800a7aef8b1: Pull complete 
e60cee1a699f: Pull complete 
Digest: sha256:aae8ce15d3986d6bd89c5ce51344f96dc2676f2c3004886a759ae1f1101374d7
| Status: Downloaded newer image for ghcr.io/home-assistant/hassfest:latest
| Validating application_credentials... done in 0.00s
| Validating bluetooth... done in 0.00s
| Validating codeowners... done in 0.00s
| Validating conditions... done in 0.71s
| Validating config_schema... done in 0.00s
| Validating dependencies... done in 1.38s
| Validating dhcp... done in 0.00s
| Validating icons... done in 0.00s
| Validating integration_info... done in 0.00s
| Validating json... done in 0.45s
| Validating labs... done in 0.00s
| Validating manifest... done in 0.00s
| Validating mqtt... done in 0.00s
| Validating quality_scale... done in 0.00s
| Validating requirements... done in 0.00s
| Validating services... done in 0.00s
| Validating ssdp... done in 0.00s
| Validating translations... done in 0.01s
| Validating triggers... done in 0.30s
| Validating usb... done in 0.00s
| Validating zeroconf... done in 0.00s
| Validating config_flow... done in 0.00s
| 
| Integrations: 1
| Invalid integrations: 1
| 
| Integration workspace - /github/workspace:
| * [ERROR] [MANIFEST] Domain does not match dir name
| 
[Validate with hassfest/validate]   ❌  Failure - Main docker run --rm -v /media/christoph/Projekte/PyCharm/core/config/custom_components/ssh_command://github/workspace ghcr.io/home-assistant/hassfest
 [24.302217002s]
[Validate with hassfest/validate] exitcode '1': failure
[Validate with hassfest/validate]   ❌  Failure - Main Run hassfest [24.774977926s]
[Validate with hassfest/validate] exitcode '1': failure
[Validate with hassfest/validate] ⭐ Run Post Run hassfest
[Validate with hassfest/validate]   🐳  docker cp src=/root/.cache/act/home-assistant-actions-hassfest@master/ dst=/var/run/act/actions/home-assistant-actions-hassfest@master/
[Validate with hassfest/validate]   ✅  Success - Post Run hassfest [29.462615ms]
[Validate with hassfest/validate] ⭐ Run Complete job
[Validate with hassfest/validate] Cleaning up container for job validate
[Validate with hassfest/validate]   ✅  Success - Complete job
[Validate with hassfest/validate] 🏁  Job failed
Error: Job 'validate' failed
[FAIL]  hassfest.yaml failed
[INFO]  Running [validate.yaml] with event 'workflow_dispatch'…
INFO[0000] Using docker host 'unix:///var/run/docker.sock', and daemon socket 'unix:///var/run/docker.sock' 
[Validate/validate-hacs] ⭐ Run Set up job
[Validate/validate-hacs] 🚀  Start image=catthehacker/ubuntu:act-latest
[Validate/validate-hacs]   🐳  docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true
[Validate/validate-hacs]   🐳  docker create image=catthehacker/ubuntu:act-latest platform= entrypoint=["tail" "-f" "/dev/null"] cmd=[] network="host"
[Validate/validate-hacs]   🐳  docker run image=catthehacker/ubuntu:act-latest platform= entrypoint=["tail" "-f" "/dev/null"] cmd=[] network="host"
[Validate/validate-hacs]   🐳  docker exec cmd=[node --no-warnings -e console.log(process.execPath)] user= workdir=
[Validate/validate-hacs]   ✅  Success - Set up job
[Validate/validate-hacs]   ☁  git clone 'https://github.com/hacs/action' # ref=main
[Validate/validate-hacs] ⭐ Run Main HACS validation
[Validate/validate-hacs]   🐳  docker pull image=ghcr.io/hacs/action:main platform= username= forcePull=true
[Validate/validate-hacs]   🐳  docker create image=ghcr.io/hacs/action:main platform= entrypoint=[] cmd=[] network="container:act-Validate-validate-hacs-e1ee04cfa255468b6bfebe0bf9c5389327db1aa442f655a9dfccffba1996c584"
[Validate/validate-hacs]   🐳  docker run image=ghcr.io/hacs/action:main platform= entrypoint=[] cmd=[] network="container:act-Validate-validate-hacs-e1ee04cfa255468b6bfebe0bf9c5389327db1aa442f655a9dfccffba1996c584"
[Validate/validate-hacs]   ❓  ::DEBUG:: Using selector: EpollSelector
[Validate/validate-hacs]   ❓  ::INFO:: Category: integration
[Validate/validate-hacs]   ❓  ::INFO:: Repository: gensyn/ssh_command@main
[Validate/validate-hacs]   ❓  ::DEBUG:: <Integration gensyn/ssh_command> Checking repository.
[Validate/validate-hacs]   ❓  ::ERROR:: 401
[Validate/validate-hacs]   ❓  ::ERROR:: Repository gensyn/ssh_command not loaded properly in HACS.
[Validate/validate-hacs]   ❌  Failure - Main HACS validation [38.238535684s]
[Validate/validate-hacs] exit with `FAILURE`: 1
[Validate/validate-hacs] ⭐ Run Complete job
[Validate/validate-hacs] Cleaning up container for job validate-hacs
[Validate/validate-hacs]   ✅  Success - Complete job
[Validate/validate-hacs] 🏁  Job failed
Error: Job 'validate-hacs' failed
[FAIL]  validate.yaml failed

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 25, 2026

@copilot Two actions fail locally while they succeed on GitHub:

...

Fixed in 0211332. Both workflows are now skipped by default with a clear explanation:

  • hassfest.yamlact sets GITHUB_WORKSPACE to the host filesystem path, which causes hassfest's directory-name check to fail locally (works fine on GitHub). Opt in with --include-hassfest.
  • validate.yaml – HACS validation fetches live data from the GitHub repository and may not behave identically locally. Opt in with --include-validate.

The default run (./run_workflows_locally.sh) now only executes test.yml, pylint.yml, and integration-tests.yml.

@gensyn
Copy link
Copy Markdown
Owner

gensyn commented Mar 25, 2026

@copilot Please silently skip all actions that depend on GitHub or don't make sense to run locally. The important part is that tests and linting are run.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 25, 2026

@copilot Please silently skip all actions that depend on GitHub or don't make sense to run locally. The important part is that tests and linting are run.

Done in 9fc522c. hassfest.yaml, validate.yaml, and release.yaml are now silently omitted — no messages, no flags. The script takes no arguments and only runs test.yml, pylint.yml, and integration-tests.yml.

Copilot AI changed the title Add script to run all GitHub Actions workflows locally Add script to run CI workflows (tests and linting) locally Mar 25, 2026
@gensyn gensyn marked this pull request as ready for review March 25, 2026 09:23
@gensyn gensyn merged commit eab11a0 into main Mar 25, 2026
5 checks passed
@gensyn gensyn deleted the copilot/run-github-actions-locally branch March 25, 2026 09:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants