Skip to content

Commit 8e6eb4f

Browse files
authored
GitHub workflow improvements (#1306)
* lint and action updates * add custom image tag action * remove publish infra bloat * replace cancel action with native concurrency control * ignore all docs changes for release trigger * image action updates * update publish trigger paths * simplify semver checks * make it possible to call publish * add tests for custom action * rename publish workflows * call publish after successful package release * fix inputs and published package parsing * clarify image tag action errors * move test action * add test events * add changesets action mock * add docs checks * add github action test readme * fix docs check on push * update action versions in docs * cache npm for docs check * pretend to fix bad docs link * fix docs link * Revert "fix docs link" This reverts commit a7508f5. * Revert "Revert "fix docs link"" This reverts commit ec642af. * improve caching * disable automatic publishing after release * limit docs checks to pushes to main and PRs * fix broken links * prevent word splitting and globbing * use latest checkout action everywhere * correctly detect prereleases as valid semver * update to latest cache action
1 parent e813803 commit 8e6eb4f

38 files changed

+617
-243
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
name: "#️⃣ Get image tag (action)"
2+
3+
description: This action gets the image tag from the commit ref or input (if provided)
4+
5+
outputs:
6+
tag:
7+
description: The image tag
8+
value: ${{ steps.get_tag.outputs.tag }}
9+
is_semver:
10+
description: Whether the tag is a semantic version
11+
value: ${{ steps.check_semver.outputs.is_semver }}
12+
13+
inputs:
14+
tag:
15+
description: The image tag. If this is set it will return the tag as is.
16+
required: false
17+
default: ""
18+
19+
runs:
20+
using: "composite"
21+
steps:
22+
- name: "#️⃣ Get image tag (step)"
23+
id: get_tag
24+
shell: bash
25+
run: |
26+
if [[ -n "${{ inputs.tag }}" ]]; then
27+
tag="${{ inputs.tag }}"
28+
elif [[ "${{ github.ref_type }}" == "tag" ]]; then
29+
if [[ "${{ github.ref_name }}" == infra-*-* ]]; then
30+
env=$(echo ${{ github.ref_name }} | cut -d- -f2)
31+
sha=$(echo ${{ github.sha }} | head -c7)
32+
ts=$(date +%s)
33+
tag=${env}-${sha}-${ts}
34+
elif [[ "${{ github.ref_name }}" == v.docker.* ]]; then
35+
version="${GITHUB_REF_NAME#v.docker.}"
36+
tag="v${version}"
37+
elif [[ "${{ github.ref_name }}" == build-* ]]; then
38+
tag="${GITHUB_REF_NAME#build-}"
39+
else
40+
echo "Invalid git tag: ${{ github.ref_name }}"
41+
exit 1
42+
fi
43+
elif [[ "${{ github.ref_name }}" == "main" ]]; then
44+
tag="main"
45+
else
46+
echo "Invalid git ref: ${{ github.ref }}"
47+
exit 1
48+
fi
49+
echo "tag=${tag}" >> "$GITHUB_OUTPUT"
50+
51+
- name: 🔍 Check for validity
52+
id: check_validity
53+
shell: bash
54+
env:
55+
tag: ${{ steps.get_tag.outputs.tag }}
56+
run: |
57+
if [[ "${tag}" =~ ^[a-z0-9]+([._-][a-z0-9]+)*$ ]]; then
58+
echo "Tag is valid: ${tag}"
59+
else
60+
echo "Tag is not valid: ${tag}"
61+
exit 1
62+
fi
63+
64+
- name: 🆚 Check for semver
65+
id: check_semver
66+
shell: bash
67+
env:
68+
tag: ${{ steps.get_tag.outputs.tag }}
69+
# Will match most semver formats except build metadata, i.e. v1.2.3+build.1
70+
# Valid matches:
71+
# v1.2.3
72+
# v1.2.3-alpha
73+
# v1.2.3-alpha.1
74+
# v1.2.3-rc.1
75+
# v1.2.3-beta-1
76+
run: |
77+
if [[ "${tag}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$ ]]; then
78+
echo "Tag is a semantic version: ${tag}"
79+
is_semver=true
80+
else
81+
echo "Tag is not a semantic version: ${tag}"
82+
is_semver=false
83+
fi
84+
echo "is_semver=${is_semver}" >> "$GITHUB_OUTPUT"

.github/test/README.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# GitHub Action Tests
2+
3+
This directory contains necessary files to allow local testing of GitHub Actions workflows, composite actions, etc. You will need to install [act](https://github.com/nektos/act) to perform tests.
4+
5+
## Workflow tests
6+
7+
Trigger specific workflow files by specifying their full path:
8+
9+
```
10+
act -W .github/workflow/release.yml
11+
```
12+
13+
You will likely need to override any custom runners we use, e.g. buildjet. For example:
14+
15+
```
16+
override=catthehacker/ubuntu:act-latest
17+
18+
act -W .github/workflow/release.yml \
19+
-P buildjet-8vcpu-ubuntu-2204=$override
20+
21+
# override multiple images at the same time
22+
act -W .github/workflow/release.yml \
23+
-P buildjet-8vcpu-ubuntu-2204=$override \
24+
-P buildjet-16vcpu-ubuntu-2204=$override
25+
```
26+
27+
Trigger with specific event payloads to test pushing to branches or tags:
28+
29+
```
30+
override=catthehacker/ubuntu:act-latest
31+
32+
# simulate push to main
33+
act -W .github/workflow/publish.yml \
34+
-P buildjet-8vcpu-ubuntu-2204=$override \
35+
-P buildjet-16vcpu-ubuntu-2204=$override \
36+
-e .github/events/push-tag-main.json
37+
38+
# simulate a `build-` prefixed tag
39+
act -W .github/workflow/publish.yml \
40+
-P buildjet-8vcpu-ubuntu-2204=$override \
41+
-P buildjet-16vcpu-ubuntu-2204=$override \
42+
-e .github/events/push-tag-buld.json
43+
```
44+
45+
By default, `act` will send a push event. To trigger a different event:
46+
47+
```
48+
# basic syntax
49+
act <EVENT> ...
50+
51+
# simulate a pull request
52+
act pull_request
53+
54+
# only trigger a specific workflow
55+
act pull_request -W .github/workflow/pr_checks.yml
56+
```
57+
58+
## Composite action tests
59+
60+
The composite (custom) action tests can be run by triggering the `test-actions` workflow:
61+
62+
```
63+
act -W .github/test/test-actions.yml
64+
```
65+
66+
## Helpful flags
67+
68+
- `--pull=false` - perform fully offline tests if all images are already present
69+
- `-j <job_name>` - run the specified job only
70+
- `-l push` - list all workflows with push triggers

.github/test/events/push-main.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"ref": "refs/heads/main"
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"ref": "refs/tags/build-buildtag"
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"ref": "refs/tags/v.docker.nonsemver"
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"ref": "refs/tags/v.docker.1.2.3"
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"ref": "refs/tags/infra-prod-anything"
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"ref": "refs/tags/infra-test-anything"
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"ref": "refs/tags/1.2.3"
3+
}

.github/test/events/push-tag.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"ref": "refs/tags/standard-tag"
3+
}

.github/test/test-actions.yml

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
name: Test Actions
2+
3+
on:
4+
workflow_dispatch:
5+
6+
jobs:
7+
get-image-tag-none:
8+
runs-on: ubuntu-latest
9+
continue-on-error: true
10+
steps:
11+
- name: Checkout code
12+
uses: actions/checkout@v4
13+
14+
- name: Log current ref
15+
run: |
16+
echo "ref: ${{ github.ref }}"
17+
echo "ref_type: ${{ github.ref_type }}"
18+
echo "ref_name: ${{ github.ref_name }}"
19+
20+
- name: Run without input tag
21+
id: get_tag
22+
# this step may fail depending on the current ref
23+
continue-on-error: true
24+
uses: ./.github/actions/get-image-tag
25+
26+
- name: Verify output
27+
run: |
28+
echo "${{ toJson(steps.get_tag) }}"
29+
30+
get-image-tag-null:
31+
runs-on: ubuntu-latest
32+
continue-on-error: true
33+
steps:
34+
- name: Checkout code
35+
uses: actions/checkout@v4
36+
37+
- name: Log current ref
38+
run: |
39+
echo "ref: ${{ github.ref }}"
40+
echo "ref_type: ${{ github.ref_type }}"
41+
echo "ref_name: ${{ github.ref_name }}"
42+
43+
- name: Run without input tag
44+
id: get_tag
45+
uses: ./.github/actions/get-image-tag
46+
# this step may fail depending on the current ref
47+
continue-on-error: true
48+
with:
49+
# this should behave exactly as when no tag is provided
50+
tag: null
51+
52+
- name: Verify output
53+
run: |
54+
echo "${{ toJson(steps.get_tag) }}"
55+
56+
get-image-tag-override:
57+
runs-on: ubuntu-latest
58+
continue-on-error: true
59+
steps:
60+
- name: Checkout code
61+
uses: actions/checkout@v4
62+
63+
- name: Run with tag override
64+
id: get_tag
65+
uses: ./.github/actions/get-image-tag
66+
with:
67+
tag: "abc-123"
68+
69+
- name: Verify output
70+
run: |
71+
echo "${{ toJson(steps.get_tag) }}"
72+
73+
get-image-tag-invalid-string:
74+
runs-on: ubuntu-latest
75+
continue-on-error: true
76+
steps:
77+
- name: Checkout code
78+
uses: actions/checkout@v4
79+
80+
- name: Run with invalid string
81+
id: get_tag
82+
uses: ./.github/actions/get-image-tag
83+
# this step is expected to fail
84+
continue-on-error: true
85+
with:
86+
# does not end with alphanumeric character
87+
tag: "abc-123-"
88+
89+
- name: Fail job if previous step did not fail
90+
if: steps.get_tag.outcome != 'failure'
91+
run: exit 1
92+
93+
- name: Verify output
94+
run: |
95+
echo "${{ toJson(steps.get_tag) }}"
96+
97+
get-image-tag-prerelease:
98+
runs-on: ubuntu-latest
99+
continue-on-error: true
100+
steps:
101+
- name: Checkout code
102+
uses: actions/checkout@v4
103+
104+
- name: Run with prerelease semver
105+
id: get_tag
106+
uses: ./.github/actions/get-image-tag
107+
with:
108+
tag: "v1.2.3-beta.4"
109+
110+
- name: Verify output
111+
run: |
112+
echo "${{ toJson(steps.get_tag) }}"
113+
114+
get-image-tag-semver:
115+
runs-on: ubuntu-latest
116+
continue-on-error: true
117+
steps:
118+
- name: Checkout code
119+
uses: actions/checkout@v4
120+
121+
- name: Run with basic semver
122+
id: get_tag
123+
uses: ./.github/actions/get-image-tag
124+
with:
125+
tag: "v1.2.3"
126+
127+
- name: Verify output
128+
run: |
129+
echo "${{ toJson(steps.get_tag) }}"
130+
131+
get-image-tag-invalid-semver:
132+
runs-on: ubuntu-latest
133+
continue-on-error: true
134+
steps:
135+
- name: Checkout code
136+
uses: actions/checkout@v4
137+
138+
- name: Run with invalid semver
139+
id: get_tag
140+
uses: ./.github/actions/get-image-tag
141+
# this step is expected to fail
142+
continue-on-error: true
143+
with:
144+
tag: "v1.2.3-"
145+
146+
- name: Fail job if previous step did not fail
147+
if: steps.get_tag.outcome != 'failure'
148+
run: exit 1
149+
150+
- name: Verify output
151+
run: |
152+
echo "${{ toJson(steps.get_tag) }}"

.github/workflows/docs.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: 📚 Docs Checks
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- "docs/**"
9+
pull_request:
10+
types: [opened, synchronize, reopened]
11+
paths:
12+
- "docs/**"
13+
14+
concurrency:
15+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
16+
cancel-in-progress: true
17+
18+
permissions:
19+
contents: read
20+
21+
jobs:
22+
check-broken-links:
23+
runs-on: ubuntu-latest
24+
defaults:
25+
run:
26+
working-directory: ./docs
27+
steps:
28+
- name: 📥 Checkout repository
29+
uses: actions/checkout@v4
30+
31+
- name: 📦 Cache npm
32+
uses: actions/cache@v4
33+
with:
34+
path: |
35+
~/.npm
36+
key: |
37+
${{ runner.os }}-mintlify
38+
restore-keys: |
39+
${{ runner.os }}-mintlify
40+
41+
- name: 🔗 Check for broken links
42+
run: npx mintlify@4.0.222 broken-links

0 commit comments

Comments
 (0)