{"id":22180731,"url":"https://github.com/jftuga/github_actions_notes","last_synced_at":"2026-03-19T22:03:05.785Z","repository":{"id":117699208,"uuid":"469106094","full_name":"jftuga/github_actions_notes","owner":"jftuga","description":"My personal notes about Github Actions","archived":false,"fork":false,"pushed_at":"2022-03-26T01:12:10.000Z","size":2529,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-01-29T23:29:58.935Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jftuga.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-12T14:29:18.000Z","updated_at":"2024-06-04T04:04:25.000Z","dependencies_parsed_at":null,"dependency_job_id":"353c20bc-7dd0-4322-93e3-d2312b6a8507","html_url":"https://github.com/jftuga/github_actions_notes","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jftuga%2Fgithub_actions_notes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jftuga%2Fgithub_actions_notes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jftuga%2Fgithub_actions_notes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jftuga%2Fgithub_actions_notes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jftuga","download_url":"https://codeload.github.com/jftuga/github_actions_notes/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245334899,"owners_count":20598386,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-02T09:19:27.958Z","updated_at":"2026-01-05T21:35:00.133Z","avatar_url":"https://github.com/jftuga.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Github Actions Notes\nMy personal notes about Github Actions\n\n## Run\n* Under Linux, the run command does not need to start with `#!/bin/bash` as this is implied.\n* By default, `run` beings with `/usr/bin/bash -e {0}`.\n* * The `-e` is similar to `set -e` - meaning the script will abort when any commands return a non-zero exit code.\n* * `{0}` refers to an auto-generated shell script such as:\n* * *  `/home/runner/work/_temp/a894e763-fea0-48ac-ba15-92e8eda24f4d.sh`\n* * * The contents of the `run` command have been saved to this file by Github Actions.\n\n## Action Shell\n* A [list of all Github Action shells](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsshell), including supported platforms\n\n* You can use a different shell for the `run` command:\n\n```yaml\n      - name: python command\n        run: |\n          import platform\n          print(platform.processor())\n        shell: python\n```\n\n* You can use both `powershell` and `bash` under Windows:\n\n```yaml\n  run-windows-commands:\n    runs-on: windows-latest\n    steps:\n      - name: Directory PowerShell\n        run: Get-Location\n      - name: Directory Bash\n        run: pwd\n        shell: bash\n```\n\n## Job Dependencies\n\n* Jobs will run in parallel by default.\n* By using `needs` in a step, you can make it depend on a previous step, thus making Github Actions run in serial instead of parallel\n\n![Github_Actions_Run_Needs_Depend](github_actions_run_needs_depend.png)\n\n## Uses\n`uses:` is used to run a third-party Github Action.\n\n**Examples:**\n\n* `actions/hello-world-javascript-action@v1`\n* `actions/hello-world-javascript-action@master`\n* `actions/hello-world-javascript-action@3ee2a0320c9193ab716b86a9dae253f5c16bae62`\n* * After the `@` symbol, a `branch name`, `tag` or `commit` must be referenced.\n\nThe `with:` keyword provides an input to a `uses` actions:\n\n![Uses Input](github_actions_uses_input.png)\n\n* Note that `uses:` references a Github project: https://github.com/actions/hello-world-javascript-action\n\n`Outputs` can also be obtained by giving your `with` input an `id:` and then referencing it with a GitHub Action generated macro:\n\n* `${{ steps.id_name.outputs.output_name }}`\n* * `id_name` is defined in the input step by using `id:`\n* * `output_name` is a predefined output from the included Github Action itself\n* * * This name will be found in the documentation of the imported action\n\n![Uses Input and Output with ID](github_actions_uses_input_output_with_id.png)\n\n## Checkout Action\n\nBy default, Github Actions does not clone your repository into the Github Actions virtual machine.\n\nGithub provides an action to do this: https://github.com/actions/checkout\n\n**Example:**\n\n```yaml\n    - name: Checkout\n      uses: actions/checkout@v1\n```\n\n**Alternative:** *Not recommended - just proof of concept!* Instead of using `actions/checkout`, you could run these commands instead.  However, this example demonstrates the use of the built-in `GITHUB_*` environment variables.\n\n```yaml\n    steps:\n      - name: List Files\n        run: |\n          pwd\n          echo $GITHUB_SHA\n          echo $GITHUB_REPOSITORY\n          echo $GITHUB_WORKSPACE\n          echo \"${{ github.token }}\"\n          git clone https://github.com/$GITHUB_REPOSITORY\n          cd *\n          pwd\n          git checkout $GITHUB_SHA\n          ls -la\n          md5sum *.md\n```\n\n## pull_request\n\nYou can run actions when a `PR` occurs by adding `pull_request` to `on:`\n\n```yaml\nname: Actions Workflow\non: [push, pull_request]\n```\n\n![Github Actions On Pull Request](github_actions_on_pull_request.png)\n\n* By default, including `pull_request` only runs on these *activity types*: `opened`, `reopened`, and `synchronize`, but **not not on** `closed`.\n* To trigger workflows by different activity types, use the `types` keyword:\n\n```yaml\non:\n  pull_request:\n    types: [review_requested]\njobs:\n  specific_review_requested:\n    runs-on: ubuntu-latest\n    if: ${{ github.event.requested_team.name == 'dev-team'}}\n    steps:\n      - run: echo 'A review from dev-team was requested'\n```\n\n* If you use `actions/checkout`, when code is pushed, the action will run on any branch because a branch name is not specified under `on:`\n* * `$GITHUB_REF` is the branch that triggered the action\n* OTOH, when a pull_request occurs, then:\n* * `$GITHUB_REF` is the PR merge branch: `refs/pull/:prNumber/merge`\n\n![Github Actions On Pull Request 2](github_actions_on_pull_request_2.png)\n\n* See also: [Events that trigger workflows](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows)\n\n## Schedule\n\nYou can use a *cron schedule expression* to schedule GitHub Actions.\n* See also: [Create a repository dispatch event](https://docs.github.com/en/rest/reference/repos#create-a-repository-dispatch-event)\n\n\n```yaml\non:\n  schedule:\n    # run at 12 PM each day\n    - cron: \"0 12 * * *\"\n    # at 04:30 on every 2nd day-of-month\n    - cron: \"30 4 */2 * *\"\n```\n\n* The **minimum time** is every 5 minutes.\n* See also: [Crontab Guru](https://crontab.guru/)\n\n___\n\n## repository_dispatch\n\nThis event can be manually triggered by sending a POST request.  A `GitHub Token` is required in order to authorize the POST request.\n\n* Settings -\u003e Developer Settings -\u003e Personal Access Tokens\n* Generate new token\n* Scope: `repo` checkbox for all 4 sub-repo permissions\n\n\nThe POST request URL is:\n* https://api.github.com/repos/USERNAME/YOUR-REPO/dispatches\n* Authorization:\n* * Basic Auth with newly generated token\n* Required Headers:\n* * Key: `Accept`\n* * Value: `application/vnd.github.v3+json`\n* * Key: `Content-Type`\n* * Value: `application/json`\n* Body:\n* * send raw JSON\n* Example:\n\n```json\n{\n  \"event_type\": \"whatever_you_like (such as 'build')\"\n  \"client_payload\": {\n    \"env\": \"production\",\n    \"example_unit\": false,\n    \"example_integration\": true\n  }\n}\n```\n\nactions.yml:\n```yml\nrepository_dispatch:\n  # this match \"event_type\" in the JSON listed above\n  types: [build]\n```\n\nIn The `actions.yml` the `client_payload` will be available in the `github` object:\n\n![Github Actions Repository Dispatch Client Payload](github_actions_repository_dispatch_client_payload.png)\n\n___\n\n## Filtering Workflows by Branches, Tags, and Paths\n\nOnly run workflow when pushing to main:\n\n```yml\non:\n  push:\n    branches:\n      - main\n```\n\nOnly run workflow if a PR is requesting to merge with main:\n\n```yml\non:\n  pull_request:\n    branches:\n      - main\n```\n\nBranches can also be pattern based:\n\n```yml\non:\n  push:\n    branches:\n      - main\n      - 'feature/*'\n```\n\nThe above would **not** match `feature/abc/xyz` as the `*` does not match a `/`. It has to be one word.  Otherwise, you will need to use: `- 'feature/**'` to match nested slashes.\n\nSee also: [Filter pattern cheat sheet](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet)\n\n**Negation / Exclusions**\n\nUse `branches-ignore` to run on **all** branches except for those listed:\n\n```yml\non:\n  push:\n    branches-ignore:\n      - main\n```\n\nYou can **not** use both `branches:` and `branches-ignore:` simultaneously. To overcome this limitation, use a `!` within `branches`.\n\nThis will ignore the `featC` branch but still work on all other `feature` branches.  The negation entry **must come last** in the list:\n\n```yml\non:\n  push:\n    branches-ignore:\n      - main\n      - 'feature/**'\n      - '!feature/featC'\n```\n\n**tags**\n\nThese work exactly like `branches`, including `tags-ignore`:\n\n```yml\non:\n  push:\n    branches:\n      - master\n      - 'feature/**'\n  tags:\n    - v1.*\n```\n\n**paths**\n\nFor example, only run the workflow when Javascript files have been pushed, except for `filename.js`:\n\n```yml\non:\n  push:\n    branches:\n      - master\n      - 'feature/**'\n  tags:\n    - v1.*\n  paths:\n    - '**.js'\n    - '!filename.js'\n```\n\nYou can also use `paths-ignore` but not at the same time that you use `paths`:\n\n```yml\n   paths-ignore:\n     - 'docs/**'\n```\n\n___\n\n## Default \u0026 Custom Environment Variables\n\nYou can define `global` environment variables using `env:`, *(see WF_ENV):*\n\n```yml\non: push\nenv:\n  WF_ENV: Available to all jobs\n\njobs:\n  log-env:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Log ENV Variables\n        run: |\n          echo \"WF_ENV: ${WF_ENV}\"\n```\n\nYou can also create environment variables that can only be accessed from a specific job by placing `env:` within a single job, *(see JOB_ENV)*:\n\n```yml\non: push\nenv:\n  WF_ENV: Available to all jobs\n\njobs:\n  log-env:\n    runs-on: ubuntu-latest\n    env:\n      JOB_ENV: Available only to all jobs in log-env job\n    steps:\n      - name: Log ENV Variables\n        run: |\n          echo \"WF_ENV: ${WF_ENV}\"\n          echo \"JOB_ENV: ${JOB_ENV}\"\n```\n\nYou can do the same for only one `step` by placing `env:` within a certain `step`:\n\n```yml\nsteps:\n  - name: Log ENV Variables\n    env:\n      STEP_ENV: Available to only this step\n    run: |\n      echo \"WF_ENV: ${WF_ENV}\"\n      echo \"JOB_ENV: ${JOB_ENV}\"\n      echo \"STEP_ENV: ${STEP_ENV}\"\n```\n\n**All Github Environment Variables**\n* See also: [Default environment variables](https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables)\n\n**Useful Default GitHub Environment Variables**:\n\n![Github Actions Default Environment Variables](github_actions_default_environment_variables.png)\n\n**Example Output**:\n\n![Github Actions Default Environment Variables Output](github_actions_default_environment_variables_output.png)\n\n___\n\n## Encrypting Environment Variables\n\nSecrets can only be accessed and decrypted on Github.\n\n* Settings -\u003e Secrets\n* Add a new secret\n* * Name: WF_ENV\n* * Value: *(add you secret here)*\n* Click `Add Secret`\n\n```yml\non: push\nenv:\n  WF_ENV: ${{ secrets.WF_ENV }}\n```\n\n## Using GITHUB_TOKEN Secret for Authentication\n\n`${{ secrets.GITHUB_TOKEN }}` is a built-in secret that can be used by the Github API.  For example, it can be used to push code to your repo.  It can also be used to call the GitHub REST API from within your workflow.\n\n**Example 1: passing GITHUB_TOKEN as an input**\n\n```yml\nname: Pull request labeler\non: [ pull_request_target ]\n\npermissions:\n  contents: read\n  pull-requests: write\n\njobs:\n  triage:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/labeler@v2\n        with:\n          repo-token: ${{ secrets.GITHUB_TOKEN }}\n```\n\n**Example 2: call the the REST API**\n\nPoints of interest:\n* use of: `github.repository`\n* use of: `secrets.GITHUB_TOKEN`\n* use of: `github.workflow`\n\n```yml\nname: Create issue on commit\n\non: [ push ]\n\njobs:\n  create_commit:\n    runs-on: ubuntu-latest\n    permissions:\n      issues: write\n    steps:\n      - name: Create issue using REST API\n        run: |\n          curl --request POST \\\n          --url https://api.github.com/repos/${{ github.repository }}/issues \\\n          --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' \\\n          --header 'content-type: application/json' \\\n          --data '{\n            \"title\": \"Automated issue for commit: ${{ github.sha }}\",\n            \"body\": \"This issue was automatically created by the GitHub Action workflow **${{ github.workflow }}**. \\n\\n The commit hash was: _${{ github.sha }}_.\"\n            }' \\\n          --fail\n```\n\nLive Demo: [random_number.yml](https://github.com/jftuga/github-actions-test/blob/master/.github/workflows/random_number.yml)\n\nReference: [Automatic token authentication](https://docs.github.com/en/actions/security-guides/automatic-token-authentication)\n\n___\n\n## Encrypting \u0026 Decrypting Files\n\nGithub secrets can have a max size of `64 KB`.\n\nWorkaround: You can push an encrypted file to your repo and then decrypt it in your workflow.\n\nReference: [Limits for secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets#limits-for-secrets)\n\nEncrypt a file on a local machine:\n\n```shell\ngpg --symmetric --cipher-algo AES256 my_secret.json\n```\n\n**TODO:** Complete this section\n\n___\n\n## Expressions \u0026 Contexts\n\nAnything in between `${{ }}` is an expressions that gets *evaluated*.\n\nExamples:\n* ${{ 42 }}\n* ${{ true }}\n* ${{ 'some string' }}\n* ${{ 3.1415926 }}\n* ${{ 'abc' == 'abcde' }}\n* ${{ 1 \u003e 5 }}\n* ${{ *function* }}\n\nObjects inside the braces is called a `Context`.  Contexts are a way to access information about workflow runs, runner environments, jobs, and steps. Each context is an object that contains properties, which can be strings or other objects.\n\nA few of the Github built-in `contexts` include:\n* github\n* * Ex: github.token\n* secrets\n* * Ex: secrets.PASSPHRASE\n\n* Reference: [All GitHub Contexts](https://docs.github.com/en/actions/learn-github-actions/contexts)\n* Reference [All Github Functions](https://docs.github.com/en/actions/learn-github-actions/expressions#functions)\n* * Partial list of available functions:\n* * * contains\n* * * startsWith\n* * * format\n* * * toJSON\n* * * fromJSON\n\n**Example:**\n\n![Github Actions Functions](github_actions_functions.png)\n\n![Github Actions Functions Output](github_actions_functions_output.png)\n___\n\n## The If key \u0026 Job Status Check Functions\n\n**if**\n\n* You can use the `if` conditional to prevent a job from running unless a condition is met.\n* You can use any supported context and expression to create a conditional.\n* Expressions inside an `if` conditional **do not** require the `${{ }}` syntax.\n* These can be used in both `jobs` and `steps`.\n\n**Example:**\n\n![Github Actions If Condition](github_actions_if_condition.png)\n\nYou can use `failure()` to continue the next `step` even if the previous one fails.\n\n**Example:**\n\n![Github Actions If Condition Failure](github_actions_if_condition_failure.png)\n\nOther functions than can be used with `if`:\n* success()\n* cancelled() *return true when workflow is cancelled*\n* always() - *always returns true*\n___\n\n## Continue on Error \u0026 Timeout Minutes\n\nYou can use `needs:` in jobs if you do not want them to run in parallel and run them in a certain sequence.\n`needs:` is an array so you can depend on multiple jobs.\n\nYou can set `continue-on-error:` to `true` in the first step to run all successive steps without having to add `if failure()` to each one of those steps.\n\n\n`timeout-minutes` *(default is 360 minutes)* - can be step to change the maximum time a job can take. This can also be used in a `step`.\n\n## Using Matrix for Running Job with Different Environments\n\n![Github Actions Strategy Matrix](github_actions_strategy_matrix.png)\n\n* create an array that will be used in the steps\n* * `node_version:` in the example above\n* `max-parallel:` can be used to limit number of parallel jobs\n* * GitHub maximizes this by default\n* Set `fail-fast:` to `false` to abort parallel jobs if one of them fails\n* Use the `matrix context` to reference the *node_version* object\n\n**Example:**\n\n![Github Actions Strategy Matrix 3x3](github_actions_strategy_matrix_3x3.png)\n\n\n___\n\n## Including \u0026 Excluding Matrix Configurations\n\nTo exclude individual matrix combinations, use `exclude:`\n\n**Example:**\n\n![Github Actions Strategy Matrix Exclude](github_actions_strategy_matrix_exclude.png)\n\n`include:` includes extra variables for a certain configuration that already exists in the matrix.\n\n**Example:**\n\n![Github Actions Strategy Matrix Include](github_actions_strategy_matrix_include.png)\n\n**Usage:**\n\n`IS_UBUNTU_8` is set to `true` only in one configuration; otherwise, it is set to an *empty string*:\n\n![Github Actions Strategy Matrix Include Usage](github_actions_strategy_matrix_include_usage.png)\n___\n\n## Using Docker Containers in Jobs\n\nTo use Docker, use `container`. This can be any image from DockerHub.\n\n**Example:**\n\n```yml\njobs:\n  node-docker:\n    runs-on: ubuntu-latest\n    container:\n      image: node:13.5.0-alpine3.10\n      env:\n        NAME: PROD\n      ports: [22, 443]\n      volumes:\n        - my_docker_volume:/volume_mount\n      options: --cpu 1\n```\n\nWhen you only specify a container image, you can omit the `image` keyword:\n\n```yml\njobs:\n  my_job:\n    container: node:14.16\n```\n\n**Complete Example:**\n\n```yml\nname: container\non: push\n\njobs:\n  node-docker:\n    runs-on: ubuntu-latest\n    container:\n      image: node:13.5.0-alpine3.10\n    steps:\n      - name: log node version\n        run: |\n          node -v\n          cat /etc/os-release\n```\n\n___\n\n## Marketplace\n\n[Github Actions Marketplace](https://github.com/marketplace?type=actions)\n\n___\n\n## Debug\n* [If the workflow logs do not provide enough detail to diagnose why a workflow, job, or step is not working as expected, you can enable additional debug logging.](https://docs.github.com/en/actions/monitoring-and-troubleshooting-workflows/enabling-debug-logging)\n\n![Github Actions Debug Howto](github_actions_debug_howto.png)\n\n![Github Actions Debug Output](github_actions_debug_output.png)\n\n* You can download the `log archive`:\n* * If `ACTIONS_RUNNER_DEBUG` and `ACTIONS_STEP_DEBUG` set to `true`, then your downloaded `logs.zip` file will contain an additional folder: `runner-diagnostic-logs`\n\n![Github Actions Debug Download Log Archive](github_actions_debug_download_log_archive.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjftuga%2Fgithub_actions_notes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjftuga%2Fgithub_actions_notes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjftuga%2Fgithub_actions_notes/lists"}