Make action compatible with push events (#12)

This commit is contained in:
Bᴇʀɴᴅ Sᴄʜᴏʀɢᴇʀs 2022-07-30 14:33:55 +02:00
parent d2d078c510
commit f1fcfe77d5
No known key found for this signature in database
GPG key ID: BC5E2BD907F9A8EC
13 changed files with 179 additions and 75 deletions

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,5 @@
name: 'Changed charts' name: 'Collect charts'
description: 'Collects the changed Helm charts and returns the lint/test matrix' description: 'Collects Helm charts based on the inputs and returns the lint/test matrix'
inputs: inputs:
token: token:
description: > description: >
@ -17,8 +17,20 @@ inputs:
should be excluded from linting/testing. should be excluded from linting/testing.
required: true required: true
default: '.ci/repo-config.yaml' default: '.ci/repo-config.yaml'
getAllCharts:
description: >
Instead of finding the changed charts, return
all the charts
required: false
default: 'false'
overrideCharts:
description: >
A JSON encoded array of charts to return instead of finding
the changed charts
required: false
default: '[]'
outputs: outputs:
changedCharts: charts:
description: > description: >
An array of all the Helm charts that contain changes An array of all the Helm charts that contain changes
chartsToInstall: chartsToInstall:

View file

@ -49,20 +49,22 @@ function getErrorMessage(error) {
return error.message; return error.message;
return String(error); return String(error);
} }
function requestAddedModifiedFiles(base, head, githubToken) { function requestAddedModifiedFiles(baseCommit, headCommit, githubToken) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
let result = []; let result = [];
const octokit = github.getOctokit(githubToken); const octokit = github.getOctokit(githubToken);
core.info(`Base commit: ${baseCommit}`);
core.info(`Head commit: ${headCommit}`);
// Use GitHub's compare two commits API. // Use GitHub's compare two commits API.
const response = yield octokit.rest.repos.compareCommits({ const response = yield octokit.rest.repos.compareCommits({
base, base: baseCommit,
head, head: headCommit,
owner: github.context.repo.owner, owner: github.context.repo.owner,
repo: github.context.repo.repo, repo: github.context.repo.repo,
}); });
// Ensure that the request was successful. // Ensure that the request was successful.
if (response.status !== 200) { if (response.status !== 200) {
throw new Error(`The GitHub API for comparing the base and head commits for this PR event returned ${response.status}, expected 200.`); throw new Error(`The GitHub API returned ${response.status}, expected 200.`);
} }
// Ensure that the head commit is ahead of the base commit. // Ensure that the head commit is ahead of the base commit.
if (response.data.status !== "ahead") { if (response.data.status !== "ahead") {
@ -78,6 +80,30 @@ function requestAddedModifiedFiles(base, head, githubToken) {
return result; return result;
}); });
} }
function requestAllFiles(commit, githubToken) {
return __awaiter(this, void 0, void 0, function* () {
let result = [];
const octokit = github.getOctokit(githubToken);
core.info(`Commit SHA: ${commit}`);
const response = yield octokit.rest.git.getTree({
tree_sha: commit,
owner: github.context.repo.owner,
repo: github.context.repo.repo,
recursive: "true",
});
// Ensure that the request was successful.
if (response.status !== 200) {
throw new Error(`The GitHub API returned ${response.status}, expected 200.`);
}
const responseTreeItems = response.data.tree || [];
responseTreeItems.forEach((item) => {
if (item.type == "blob" && item.path) {
result.push(item.path);
}
});
return result;
});
}
function getRepoConfig(configPath) { function getRepoConfig(configPath) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
// Ensure that the repo config file exists. // Ensure that the repo config file exists.
@ -110,33 +136,56 @@ function run() {
var _a, _b, _c, _d; var _a, _b, _c, _d;
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
try { try {
if (github.context.eventName !== "pull_request") {
throw new Error("This action can only run on pull requests!");
}
const githubToken = core.getInput("token", { required: true }); const githubToken = core.getInput("token", { required: true });
const chartsFolder = core.getInput("chartsFolder", { required: true }); const chartsFolder = core.getInput("chartsFolder", { required: true });
const repoConfigFilePath = core.getInput("repoConfigFile", { const repoConfigFilePath = core.getInput("repoConfigFile", {
required: true, required: true,
}); });
let getAllCharts = core.getInput("getAllCharts", { required: false });
const overrideCharts = core.getInput("overrideCharts", { required: false });
const repoConfig = yield getRepoConfig(repoConfigFilePath); const repoConfig = yield getRepoConfig(repoConfigFilePath);
core.info(`Repo configuration: ${JSON.stringify(repoConfig, undefined, 2)}`); core.info(`Repo configuration: ${JSON.stringify(repoConfig, undefined, 2)}`);
// Define the base and head commits to be extracted from the payload. if (overrideCharts && overrideCharts != "[]") {
const baseCommit = (_b = (_a = github.context.payload.pull_request) === null || _a === void 0 ? void 0 : _a.base) === null || _b === void 0 ? void 0 : _b.sha; const responseCharts = YAML.parse(overrideCharts);
const headCommit = (_d = (_c = github.context.payload.pull_request) === null || _c === void 0 ? void 0 : _c.head) === null || _d === void 0 ? void 0 : _d.sha; core.info(`Charts: ${JSON.stringify(responseCharts, undefined, 2)}`);
// Ensure that the base and head properties are set on the payload. core.setOutput("charts", responseCharts);
if (!baseCommit || !headCommit) { return;
throw new Error(`The base and head commits are missing from the payload for this PR.`); }
const eventName = github.context.eventName;
let baseCommit;
let headCommit;
switch (eventName) {
case "pull_request":
baseCommit = (_b = (_a = github.context.payload.pull_request) === null || _a === void 0 ? void 0 : _a.base) === null || _b === void 0 ? void 0 : _b.sha;
headCommit = (_d = (_c = github.context.payload.pull_request) === null || _c === void 0 ? void 0 : _c.head) === null || _d === void 0 ? void 0 : _d.sha;
break;
case "push":
baseCommit = github.context.payload.before;
headCommit = github.context.payload.after;
break;
case "workflow_dispatch":
getAllCharts = "true";
baseCommit = "";
headCommit = github.context.sha;
break;
default:
throw new Error(`This action only supports pull requests, pushes and workflow_dispatch,` +
`${github.context.eventName} events are not supported.`);
}
let responseFiles;
if (getAllCharts === "true") {
responseFiles = yield requestAllFiles(headCommit, githubToken);
}
else {
responseFiles = yield requestAddedModifiedFiles(baseCommit, headCommit, githubToken);
} }
core.info(`Base commit: ${baseCommit}`);
core.info(`Head commit: ${headCommit}`);
const responseFiles = yield requestAddedModifiedFiles(baseCommit, headCommit, githubToken);
const changedCharts = filterChangedCharts(responseFiles, chartsFolder); const changedCharts = filterChangedCharts(responseFiles, chartsFolder);
const chartsToInstall = changedCharts.filter((x) => !repoConfig["excluded-charts-install"].includes(x)); const chartsToInstall = changedCharts.filter((x) => !repoConfig["excluded-charts-install"].includes(x));
const chartsToLint = changedCharts.filter((x) => !repoConfig["excluded-charts-lint"].includes(x)); const chartsToLint = changedCharts.filter((x) => !repoConfig["excluded-charts-lint"].includes(x));
core.info(`Changed charts: ${JSON.stringify(changedCharts, undefined, 2)}`); core.info(`Charts: ${JSON.stringify(changedCharts, undefined, 2)}`);
core.info(`Charts to lint: ${JSON.stringify(chartsToLint, undefined, 2)}`); core.info(`Charts to lint: ${JSON.stringify(chartsToLint, undefined, 2)}`);
core.info(`Charts to install: ${JSON.stringify(chartsToInstall, undefined, 2)}`); core.info(`Charts to install: ${JSON.stringify(chartsToInstall, undefined, 2)}`);
core.setOutput("changedCharts", changedCharts); core.setOutput("charts", changedCharts);
core.setOutput("chartsToInstall", chartsToInstall); core.setOutput("chartsToInstall", chartsToInstall);
core.setOutput("chartsToLint", chartsToLint); core.setOutput("chartsToLint", chartsToLint);
} }

File diff suppressed because one or more lines are too long

View file

@ -12,17 +12,20 @@ function getErrorMessage(error: unknown) {
} }
async function requestAddedModifiedFiles( async function requestAddedModifiedFiles(
base: string, baseCommit: string,
head: string, headCommit: string,
githubToken: string githubToken: string
) { ) {
let result: string[] = []; let result: string[] = [];
const octokit = github.getOctokit(githubToken); const octokit = github.getOctokit(githubToken);
core.info(`Base commit: ${baseCommit}`);
core.info(`Head commit: ${headCommit}`);
// Use GitHub's compare two commits API. // Use GitHub's compare two commits API.
const response = await octokit.rest.repos.compareCommits({ const response = await octokit.rest.repos.compareCommits({
base, base: baseCommit,
head, head: headCommit,
owner: github.context.repo.owner, owner: github.context.repo.owner,
repo: github.context.repo.repo, repo: github.context.repo.repo,
}); });
@ -30,7 +33,7 @@ async function requestAddedModifiedFiles(
// Ensure that the request was successful. // Ensure that the request was successful.
if (response.status !== 200) { if (response.status !== 200) {
throw new Error( throw new Error(
`The GitHub API for comparing the base and head commits for this PR event returned ${response.status}, expected 200.` `The GitHub API returned ${response.status}, expected 200.`
); );
} }
@ -51,6 +54,35 @@ async function requestAddedModifiedFiles(
return result; return result;
} }
async function requestAllFiles(commit: string, githubToken: string) {
let result: string[] = [];
const octokit = github.getOctokit(githubToken);
core.info(`Commit SHA: ${commit}`);
const response = await octokit.rest.git.getTree({
tree_sha: commit,
owner: github.context.repo.owner,
repo: github.context.repo.repo,
recursive: "true",
});
// Ensure that the request was successful.
if (response.status !== 200) {
throw new Error(
`The GitHub API returned ${response.status}, expected 200.`
);
}
const responseTreeItems = response.data.tree || [];
responseTreeItems.forEach((item) => {
if (item.type == "blob" && item.path) {
result.push(item.path);
}
});
return result;
}
async function getRepoConfig(configPath: string) { async function getRepoConfig(configPath: string) {
// Ensure that the repo config file exists. // Ensure that the repo config file exists.
if (!(await fs.pathExists(configPath))) { if (!(await fs.pathExists(configPath))) {
@ -88,40 +120,63 @@ function filterChangedCharts(files: string[], parentFolder: string) {
async function run() { async function run() {
try { try {
if (github.context.eventName !== "pull_request") {
throw new Error("This action can only run on pull requests!");
}
const githubToken = core.getInput("token", { required: true }); const githubToken = core.getInput("token", { required: true });
const chartsFolder = core.getInput("chartsFolder", { required: true }); const chartsFolder = core.getInput("chartsFolder", { required: true });
const repoConfigFilePath = core.getInput("repoConfigFile", { const repoConfigFilePath = core.getInput("repoConfigFile", {
required: true, required: true,
}); });
let getAllCharts = core.getInput("getAllCharts", { required: false });
const overrideCharts = core.getInput("overrideCharts", { required: false });
const repoConfig = await getRepoConfig(repoConfigFilePath); const repoConfig = await getRepoConfig(repoConfigFilePath);
core.info( core.info(
`Repo configuration: ${JSON.stringify(repoConfig, undefined, 2)}` `Repo configuration: ${JSON.stringify(repoConfig, undefined, 2)}`
); );
// Define the base and head commits to be extracted from the payload. if (overrideCharts && overrideCharts != "[]") {
const baseCommit = github.context.payload.pull_request?.base?.sha; const responseCharts = YAML.parse(overrideCharts);
const headCommit = github.context.payload.pull_request?.head?.sha; core.info(`Charts: ${JSON.stringify(responseCharts, undefined, 2)}`);
core.setOutput("charts", responseCharts);
return;
}
// Ensure that the base and head properties are set on the payload. const eventName = github.context.eventName;
if (!baseCommit || !headCommit) {
throw new Error( let baseCommit: string;
`The base and head commits are missing from the payload for this PR.` let headCommit: string;
switch (eventName) {
case "pull_request":
baseCommit = github.context.payload.pull_request?.base?.sha;
headCommit = github.context.payload.pull_request?.head?.sha;
break;
case "push":
baseCommit = github.context.payload.before;
headCommit = github.context.payload.after;
break;
case "workflow_dispatch":
getAllCharts = "true";
baseCommit = "";
headCommit = github.context.sha;
break;
default:
throw new Error(
`This action only supports pull requests, pushes and workflow_dispatch,` +
`${github.context.eventName} events are not supported.`
);
}
let responseFiles: string[];
if (getAllCharts === "true") {
responseFiles = await requestAllFiles(headCommit, githubToken);
} else {
responseFiles = await requestAddedModifiedFiles(
baseCommit,
headCommit,
githubToken
); );
} }
core.info(`Base commit: ${baseCommit}`);
core.info(`Head commit: ${headCommit}`);
const responseFiles = await requestAddedModifiedFiles(
baseCommit,
headCommit,
githubToken
);
const changedCharts = filterChangedCharts(responseFiles, chartsFolder); const changedCharts = filterChangedCharts(responseFiles, chartsFolder);
const chartsToInstall = changedCharts.filter( const chartsToInstall = changedCharts.filter(
(x) => !repoConfig["excluded-charts-install"].includes(x) (x) => !repoConfig["excluded-charts-install"].includes(x)
@ -130,13 +185,13 @@ async function run() {
(x) => !repoConfig["excluded-charts-lint"].includes(x) (x) => !repoConfig["excluded-charts-lint"].includes(x)
); );
core.info(`Changed charts: ${JSON.stringify(changedCharts, undefined, 2)}`); core.info(`Charts: ${JSON.stringify(changedCharts, undefined, 2)}`);
core.info(`Charts to lint: ${JSON.stringify(chartsToLint, undefined, 2)}`); core.info(`Charts to lint: ${JSON.stringify(chartsToLint, undefined, 2)}`);
core.info( core.info(
`Charts to install: ${JSON.stringify(chartsToInstall, undefined, 2)}` `Charts to install: ${JSON.stringify(chartsToInstall, undefined, 2)}`
); );
core.setOutput("changedCharts", changedCharts); core.setOutput("charts", changedCharts);
core.setOutput("chartsToInstall", chartsToInstall); core.setOutput("chartsToInstall", chartsToInstall);
core.setOutput("chartsToLint", chartsToLint); core.setOutput("chartsToLint", chartsToLint);
} catch (error) { } catch (error) {

View file

@ -6,9 +6,11 @@ on:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
chart: chart:
description: "Chart to release" description: >
default: "_all_" Chart to release. Comma-separated string.
required: true Defaults to releasing everything.
default: ""
required: false
push: push:
branches: branches:
- main - main
@ -37,28 +39,13 @@ jobs:
path: "src" path: "src"
fetch-depth: 0 fetch-depth: 0
- name: Collect changes - name: Collect charts to release
id: collect-changes uses: ./src/.github/actions/collect-charts
uses: ./src/.github/actions/collect-changes id: collect-charts
with: with:
token: ${{ steps.get-app-token.outputs.token }} token: ${{ steps.get-app-token.outputs.token }}
working-directory: src repoConfigFile: ./src/.ci/repo-config.yaml
overrideCharts: "[${{ inputs.chart }}]"
- name: Determine charts to release
id: charts-to-release
shell: bash
run: |
CHARTS=()
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
if [ "${{ github.event.inputs.chart }}" == "_all_" ]; then
CHARTS=($(find "src/charts" -type f -name 'Chart.yaml' | sed -r 's|/[^/]+$||' | sed 's|src/charts/||' | sort | uniq))
else
CHARTS=(${{ github.event.inputs.chart }})
fi
elif [ "${{ steps.collect-changes.outputs.chartChangesDetected }}" == "true" ]; then
CHARTS=(${{ steps.collect-changes.outputs.addedOrModifiedCharts }})
fi
printf "::set-output name=charts::%s\n" "${CHARTS[*]}"
- name: Checkout gh-pages branch - name: Checkout gh-pages branch
uses: actions/checkout@v3 uses: actions/checkout@v3
@ -80,9 +67,10 @@ jobs:
env: env:
SRC_DIR: "src/charts" SRC_DIR: "src/charts"
DEST_DIR: "dest" DEST_DIR: "dest"
CHARTS: "${{ steps.charts-to-release.outputs.charts }}"
run: | run: |
for CHART in $CHARTS ; do CHARTS=( $(yq --null-input e '${{ steps.collect-charts.outputs.charts }}[]' ) )
for CHART in "${CHARTS[@]}" ; do
mapfile -t CHART_PATH_PARTS < <(echo "$CHART" | tr '/' '\n') mapfile -t CHART_PATH_PARTS < <(echo "$CHART" | tr '/' '\n')
CHART_TYPE=${CHART_PATH_PARTS[0]} CHART_TYPE=${CHART_PATH_PARTS[0]}

View file

@ -54,7 +54,7 @@ jobs:
outputs: outputs:
addedOrModifiedFilesDetected: ${{ steps.changed-files.outputs.allAddedOrModified }} addedOrModifiedFilesDetected: ${{ steps.changed-files.outputs.allAddedOrModified }}
addedOrModifiedFiles: ${{ steps.changed-files.outputs.allAddedOrModified_files }} addedOrModifiedFiles: ${{ steps.changed-files.outputs.allAddedOrModified_files }}
addedOrModifiedCharts: ${{ steps.changed-charts.outputs.changedCharts }} addedOrModifiedCharts: ${{ steps.changed-charts.outputs.charts }}
chartsToLint: ${{ steps.changed-charts.outputs.chartsToLint }} chartsToLint: ${{ steps.changed-charts.outputs.chartsToLint }}
chartsToInstall: ${{ steps.changed-charts.outputs.chartsToInstall }} chartsToInstall: ${{ steps.changed-charts.outputs.chartsToInstall }}
steps: steps:
@ -73,5 +73,5 @@ jobs:
- added|modified: '**' - added|modified: '**'
- name: Collect changed charts - name: Collect changed charts
uses: ./.github/actions/collect-changed-charts uses: ./.github/actions/collect-charts
id: changed-charts id: changed-charts