5858 if : steps.list-changed.outputs.changed == 'true'
5959 run : ct lint --target-branch ${{ github.event.repository.default_branch }} --validate-maintainers=false --additional-commands "helm unittest {{ .Path }}"
6060
61- update-changelog :
61+ integration-test :
6262 runs-on : ubuntu-latest
6363 needs : [lint-test]
64- name : Automatically update CHANGELOG
65- permissions :
66- contents : write
6764 if : needs.lint-test.outputs.changed == 'true'
6865 steps :
6966 - name : Checkout pull request branch
@@ -73,74 +70,203 @@ jobs:
7370 repository : ${{github.event.pull_request.head.repo.full_name}}
7471 fetch-depth : 0
7572
73+ - name : Setup Helm
74+ uses : Azure/setup-helm@v4.3.1
75+
76+ - name : Setup kubectl
77+ uses : azure/setup-kubectl@v4
78+
79+ - name : Create kind cluster
80+ uses : helm/kind-action@v1.12.0
81+ with :
82+ cluster_name : helm-chart-test
83+ wait : 300s
84+
85+ - name : Installing plugin helm-unittest
86+ run : helm plugin install https://github.com/helm-unittest/helm-unittest
87+
88+ - name : Run integration tests
89+ env :
90+ CHANGED_CHARTS : ${{ needs.lint-test.outputs.changedCharts }}
91+ run : |
92+ # Make script executable
93+ chmod +x ./test-charts.sh
94+
95+ # Test each changed chart
96+ for chart_directory in ${CHANGED_CHARTS}; do
97+ CHART_NAME=${chart_directory#charts/}
98+ echo "Testing chart: $CHART_NAME"
99+
100+ # Run test script without cluster creation (kind-action already created it)
101+ # and without cleanup (let GitHub Actions handle it)
102+ ./test-charts.sh "$CHART_NAME" --no-cleanup
103+ done
104+
105+ update-changelog :
106+ runs-on : ubuntu-latest
107+ needs : [lint-test]
108+ name : Automatically update CHANGELOG
109+ permissions :
110+ contents : write
111+ pull-requests : write
112+ if : always() && needs.lint-test.outputs.changed == 'true'
113+ steps :
114+ - name : Checkout PR branch
115+ uses : actions/checkout@v5.0.0
116+ with :
117+ repository : ${{ github.event.pull_request.head.repo.full_name }}
118+ ref : ${{ github.event.pull_request.head.ref }}
119+ token : ${{ secrets.GITHUB_TOKEN }}
120+ fetch-depth : 0
121+
76122 - name : Configure Git
77123 run : |
78124 git config user.name 'github-actions[bot]'
79125 git config user.email 'github-actions[bot]@users.noreply.github.com'
80126
81- - name : Fetch tags
127+ - name : Add upstream remote and fetch tags
82128 run : |
83- git fetch --tags
129+ # Always fetch tags from the canonical upstream repository
130+ UPSTREAM_REPO="CloudPirates-io/helm-charts"
131+ echo "Fetching tags from upstream: ${UPSTREAM_REPO}"
132+ git remote add upstream https://github.com/${UPSTREAM_REPO}.git || true
133+ git fetch upstream --tags
134+
135+ # Also fetch tags from origin (the fork/current repo)
136+ git fetch origin --tags || true
84137
85- - name : Install conventional-changelog-cli
86- run : npm install -g conventional-changelog-cli
138+ # List all tags for debugging
139+ echo "Available tags:"
140+ git tag -l | head -20
87141
88- - name : Generate changelog
89- id : generate-changelog
142+ - name : Install yq
143+ run : |
144+ sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64
145+ sudo chmod +x /usr/local/bin/yq
146+
147+ - name : Generate changelog and commit
148+ id : check-changes
149+ shell : bash
90150 env :
91151 PULL_REQUEST_NUMBER : " ${{ github.event.pull_request.number }}"
92152 PULL_REQUEST_URL : " ${{ github.server_url }}/${{ github.repository }}/pull/${{ github.event.number }}"
93153 GITHUB_TOKEN : " ${{ github.token }}"
154+ GITHUB_REPOSITORY : " ${{ github.repository }}"
155+ GITHUB_REPOSITORY_URL : " ${{ github.server_url }}/${{ github.repository }}"
94156 CHANGED_CHARTS : ${{ needs.lint-test.outputs.changedCharts }}
95157 run : |
158+ set -e
96159 PR_TITLE="$(gh api "/repos/${GITHUB_REPOSITORY}/pulls/${PULL_REQUEST_NUMBER}" | jq -r '.title')"
160+
161+ # Extract chart names from changed chart directories
162+ CHART_NAMES=()
97163 for chart_directory in ${CHANGED_CHARTS}; do
98164 CHART_NAME=${chart_directory#charts/}
99- echo "Updating CHANGELOG for chart $CHART_NAME"
100-
101- # Extract version from Chart.yaml
102- CHART_VERSION=$(yq eval '.version' "${GITHUB_WORKSPACE}/charts/${CHART_NAME}/Chart.yaml")
103- CHANGELOG_FILE="${GITHUB_WORKSPACE}/charts/${CHART_NAME}/CHANGELOG.md"
104- CHANGELOG_TMP_FILE="${GITHUB_WORKSPACE}/charts/${CHART_NAME}/CHANGELOG.md.tmp"
105-
106- touch "$CHANGELOG_FILE"
107-
108- # Generate new CHANGELOG.md
109- npx conventional-changelog-cli -i "$CHANGELOG_FILE" -s -t "${CHART_NAME}-" -r 0 --commit-path "charts/${CHART_NAME}"
110-
111- # Remove unreleased section (includes all intermediate commits in the branch) and create future entry based on PR title
112- # The unreleased section looks like this "## (YYYY-MM-DD)" whereas a released section looks like this "## 0.0.1 (YYYY-MM-DD)"
113- # So we only need to find a released section to start printing in the awk script below
114- awk '/^##[^(]*[0-9]/ {flag=1} flag {print}' "$CHANGELOG_FILE" > "$CHANGELOG_TMP_FILE"
115-
116- # Remove chart name prefixes from commit messages
117- sed -i -E "s/\* \[${CHART_NAME}\] /\* /gi" "$CHANGELOG_TMP_FILE"
118- sed -i -E "s/\* \[$(echo ${CHART_NAME} | tr '[:lower:]' '[:upper:]')\] /\* /g" "$CHANGELOG_TMP_FILE"
119-
120- # Remove extra newlines so the changelog file passes the markdown linter
121- sed -i -E -e '/^$/d' "$CHANGELOG_TMP_FILE" && sed -i -E -e 's/(##.*)/\n\1\n/g' "$CHANGELOG_TMP_FILE"
122-
123- # Include h1 heading and add entry for the current version. There is no tag for the current version (this will be created once merged), so we need to manually add it.
124- # We know the final squashed commit title, which will be the PR title. We cannot add a link to the commit in the main branch because it has not been
125- # merged yet (this will be corrected once a new version regenerates the changelog). Instead, we add the PR url which contains the exact same information.
126- echo -e -n "# Changelog\n\n## $CHART_VERSION ($(date +'%Y-%m-%d'))\n\n* ${PR_TITLE} ([#${PULL_REQUEST_NUMBER}](${PULL_REQUEST_URL}))\n" > "$CHANGELOG_FILE"
127-
128- cat "$CHANGELOG_TMP_FILE" >> "$CHANGELOG_FILE"
129- rm "$CHANGELOG_TMP_FILE"
130-
131- # Commit all changes, if any
132- if git status -s | grep "charts/${CHART_NAME}/CHANGELOG.md"; then
133- git add "charts/${CHART_NAME}/CHANGELOG.md"
134- git commit -m "Update CHANGELOG.md" --signoff
135- fi
165+ CHART_NAMES+=("--chart" "$CHART_NAME")
136166 done
137167
138- - name : Push all changes
139- run : |
140- cd $GITHUB_WORKSPACE/charts
141- # Push all the new commits, if any
142- if [[ $(git cherry -v) ]]; then
143- git push
168+ # Run the changelog generation script
169+ ./generate-changelog.sh \
170+ "${CHART_NAMES[@]}" \
171+ --pr-title "${PR_TITLE}" \
172+ --pr-number "${PULL_REQUEST_NUMBER}" \
173+ --pr-url "${PULL_REQUEST_URL}"
174+
175+ # Check if there are changes
176+ if git status --porcelain | grep -q 'CHANGELOG.md'; then
177+ echo "has_changes=true" >> $GITHUB_OUTPUT
144178 else
145- echo "No changed CHANGELOGS, skip push"
179+ echo "No CHANGELOG changes"
180+ echo "has_changes=false" >> $GITHUB_OUTPUT
146181 fi
182+
183+ - name : Commit and push via GitHub API
184+ id : push-changes
185+ if : steps.check-changes.outputs.has_changes == 'true'
186+ uses : actions/github-script@v7
187+ with :
188+ github-token : ${{ secrets.GITHUB_TOKEN }}
189+ script : |
190+ const { execSync } = require('child_process');
191+ const fs = require('fs');
192+
193+ try {
194+ const headRef = '${{ github.event.pull_request.head.ref }}';
195+ const headRepo = '${{ github.event.pull_request.head.repo.full_name }}';
196+ const [owner, repo] = headRepo.split('/');
197+
198+ // Get current branch SHA
199+ const { data: refData } = await github.rest.git.getRef({
200+ owner,
201+ repo,
202+ ref: `heads/${headRef}`
203+ });
204+ const currentSha = refData.object.sha;
205+ console.log('Current branch SHA:', currentSha);
206+
207+ // Get the tree for current commit
208+ const { data: commitData } = await github.rest.git.getCommit({
209+ owner,
210+ repo,
211+ commit_sha: currentSha
212+ });
213+ const baseTreeSha = commitData.tree.sha;
214+
215+ // Get all changed CHANGELOG files
216+ const changedFiles = execSync('git status --porcelain').toString()
217+ .split('\n')
218+ .filter(line => line.includes('CHANGELOG.md'))
219+ .map(line => line.trim().split(/\s+/)[1])
220+ .filter(Boolean);
221+
222+ console.log('Changed files:', changedFiles);
223+
224+ // Create blobs for each changed file
225+ const blobs = await Promise.all(
226+ changedFiles.map(async (file) => {
227+ const content = fs.readFileSync(file, 'utf8');
228+ const { data: blob } = await github.rest.git.createBlob({
229+ owner,
230+ repo,
231+ content,
232+ encoding: 'utf-8'
233+ });
234+ return { path: file, sha: blob.sha, mode: '100644', type: 'blob' };
235+ })
236+ );
237+
238+ // Create new tree
239+ const { data: newTree } = await github.rest.git.createTree({
240+ owner,
241+ repo,
242+ base_tree: baseTreeSha,
243+ tree: blobs
244+ });
245+
246+ // Create commit (this will be automatically signed by GitHub)
247+ const { data: newCommit } = await github.rest.git.createCommit({
248+ owner,
249+ repo,
250+ message: 'chore: update CHANGELOG.md for changed charts\n\nSigned-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>',
251+ tree: newTree.sha,
252+ parents: [currentSha]
253+ });
254+
255+ console.log('Created commit:', newCommit.sha);
256+
257+ // Update reference
258+ await github.rest.git.updateRef({
259+ owner,
260+ repo,
261+ ref: `heads/${headRef}`,
262+ sha: newCommit.sha,
263+ force: false
264+ });
265+
266+ console.log('✅ Successfully committed and pushed changelog updates');
267+ core.notice('✅ Changelog updated and pushed successfully');
268+
269+ } catch (error) {
270+ console.error('Failed to commit via GitHub API:', error);
271+ core.setFailed(`Unable to push changelog updates: ${error.message}`);
272+ }
0 commit comments